MCPcopy
hub / github.com/opencontainers/runc / msMoveRoot

Function msMoveRoot

libcontainer/rootfs_linux.go:1189–1250  ·  view source on GitHub ↗
(rootfs string)

Source from the content-addressed store, hash-verified

1187}
1188
1189func msMoveRoot(rootfs string) error {
1190 // Before we move the root and chroot we have to mask all "full" sysfs and
1191 // procfs mounts which exist on the host. This is because while the kernel
1192 // has protections against mounting procfs if it has masks, when using
1193 // chroot(2) the *host* procfs mount is still reachable in the mount
1194 // namespace and the kernel permits procfs mounts inside --no-pivot
1195 // containers.
1196 //
1197 // Users shouldn't be using --no-pivot except in exceptional circumstances,
1198 // but to avoid such a trivial security flaw we apply a best-effort
1199 // protection here. The kernel only allows a mount of a pseudo-filesystem
1200 // like procfs or sysfs if there is a *full* mount (the root of the
1201 // filesystem is mounted) without any other locked mount points covering a
1202 // subtree of the mount.
1203 //
1204 // So we try to unmount (or mount tmpfs on top of) any mountpoint which is
1205 // a full mount of either sysfs or procfs (since those are the most
1206 // concerning filesystems to us).
1207 mountinfos, err := mountinfo.GetMounts(func(info *mountinfo.Info) (skip, stop bool) {
1208 // Collect every sysfs and procfs filesystem, except for those which
1209 // are non-full mounts or are inside the rootfs of the container.
1210 if info.Root != "/" ||
1211 (info.FSType != "proc" && info.FSType != "sysfs") ||
1212 strings.HasPrefix(info.Mountpoint, rootfs) {
1213 skip = true
1214 }
1215 return skip, stop
1216 })
1217 if err != nil {
1218 return err
1219 }
1220 for _, info := range mountinfos {
1221 p := info.Mountpoint
1222 // Be sure umount events are not propagated to the host.
1223 if err := mount("", p, "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil {
1224 if errors.Is(err, unix.ENOENT) {
1225 // If the mountpoint doesn't exist that means that we've
1226 // already blasted away some parent directory of the mountpoint
1227 // and so we don't care about this error.
1228 continue
1229 }
1230 return err
1231 }
1232 if err := unmount(p, unix.MNT_DETACH); err != nil {
1233 if !errors.Is(err, unix.EINVAL) && !errors.Is(err, unix.EPERM) {
1234 return err
1235 } else {
1236 // If we have not privileges for umounting (e.g. rootless), then
1237 // cover the path.
1238 if err := mount("tmpfs", p, "tmpfs", 0, ""); err != nil {
1239 return err
1240 }
1241 }
1242 }
1243 }
1244
1245 // Move the rootfs on top of "/" in our mount namespace.
1246 if err := mount(rootfs, "/", "", unix.MS_MOVE, ""); err != nil {

Callers 1

prepareRootfsFunction · 0.85

Calls 3

mountFunction · 0.85
unmountFunction · 0.85
chrootFunction · 0.85

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…