pivotRoot will call pivot_root such that rootfs becomes the new root filesystem, and everything else is cleaned up.
(root *os.File)
| 1136 | // pivotRoot will call pivot_root such that rootfs becomes the new root |
| 1137 | // filesystem, and everything else is cleaned up. |
| 1138 | func pivotRoot(root *os.File) error { |
| 1139 | // While the documentation may claim otherwise, pivot_root(".", ".") is |
| 1140 | // actually valid. What this results in is / being the new root but |
| 1141 | // /proc/self/cwd being the old root. Since we can play around with the cwd |
| 1142 | // with pivot_root this allows us to pivot without creating directories in |
| 1143 | // the rootfs. Shout-outs to the LXC developers for giving us this idea. |
| 1144 | |
| 1145 | oldroot, err := linux.Open("/", unix.O_DIRECTORY|unix.O_RDONLY|unix.O_PATH, 0) |
| 1146 | if err != nil { |
| 1147 | return err |
| 1148 | } |
| 1149 | defer unix.Close(oldroot) |
| 1150 | |
| 1151 | // Change to the new root so that the pivot_root actually acts on it. |
| 1152 | if err := unix.Fchdir(int(root.Fd())); err != nil { |
| 1153 | return &os.PathError{Op: "chdir", Path: root.Name(), Err: err} |
| 1154 | } |
| 1155 | |
| 1156 | if err := unix.PivotRoot(".", "."); err != nil { |
| 1157 | return &os.PathError{Op: "pivot_root", Path: ".", Err: err} |
| 1158 | } |
| 1159 | |
| 1160 | // Currently our "." is oldroot (according to the current kernel code). |
| 1161 | // However, purely for safety, we will fchdir(oldroot) since there isn't |
| 1162 | // really any guarantee from the kernel what /proc/self/cwd will be after a |
| 1163 | // pivot_root(2). |
| 1164 | |
| 1165 | if err := unix.Fchdir(oldroot); err != nil { |
| 1166 | return &os.PathError{Op: "fchdir", Path: "fd " + strconv.Itoa(oldroot), Err: err} |
| 1167 | } |
| 1168 | |
| 1169 | // Make oldroot rslave to make sure our unmounts don't propagate to the |
| 1170 | // host (and thus bork the machine). We don't use rprivate because this is |
| 1171 | // known to cause issues due to races where we still have a reference to a |
| 1172 | // mount while a process in the host namespace are trying to operate on |
| 1173 | // something they think has no mounts (devicemapper in particular). |
| 1174 | if err := mount("", ".", "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil { |
| 1175 | return err |
| 1176 | } |
| 1177 | // Perform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd. |
| 1178 | if err := unmount(".", unix.MNT_DETACH); err != nil { |
| 1179 | return err |
| 1180 | } |
| 1181 | |
| 1182 | // Switch back to our shiny new root. |
| 1183 | if err := unix.Chdir("/"); err != nil { |
| 1184 | return &os.PathError{Op: "chdir", Path: "/", Err: err} |
| 1185 | } |
| 1186 | return nil |
| 1187 | } |
| 1188 | |
| 1189 | func msMoveRoot(rootfs string) error { |
| 1190 | // Before we move the root and chroot we have to mask all "full" sysfs and |
no test coverage detected
searching dependent graphs…