diff --git a/runsc/boot/vfs.go b/runsc/boot/vfs.go index 48e195113..f933541d7 100644 --- a/runsc/boot/vfs.go +++ b/runsc/boot/vfs.go @@ -502,10 +502,32 @@ func (c *containerMounter) createMountNamespace(ctx context.Context, conf *confi fsName = overlay.Name } - mns, err := c.k.VFS().NewMountNamespace(ctx, creds, "", fsName, opts, c.k) + // The namespace root mount can't be changed, so let's mount a dummy + // read-only tmpfs here. It simplifies creation of containers without + // leaking the root file system. + mns, err := c.k.VFS().NewMountNamespace(ctx, creds, "rootfs", "tmpfs", + &vfs.MountOptions{ReadOnly: true}, c.k) if err != nil { return nil, fmt.Errorf("setting up mount namespace: %w", err) } + defer mns.DecRef(ctx) + + mnt, err := c.k.VFS().MountDisconnected(ctx, creds, "root", fsName, opts) + if err != nil { + return nil, fmt.Errorf("creating root file system: %w", err) + } + defer mnt.DecRef(ctx) + root := mns.Root(ctx) + defer root.DecRef(ctx) + target := &vfs.PathOperation{ + Root: root, + Start: root, + } + if err := c.k.VFS().ConnectMountAt(ctx, creds, mnt, target); err != nil { + return nil, fmt.Errorf("mounting root file system: %w", err) + } + + mns.IncRef() return mns, nil } diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD index 8049a214d..47c70db6c 100644 --- a/test/syscalls/linux/BUILD +++ b/test/syscalls/linux/BUILD @@ -491,6 +491,7 @@ cc_binary( "//test/util:logging", "//test/util:mount_util", "//test/util:multiprocess_util", + "//test/util:posix_error", "//test/util:temp_path", "//test/util:test_main", "//test/util:test_util", diff --git a/test/syscalls/linux/pivot_root.cc b/test/syscalls/linux/pivot_root.cc index fe5651910..d99c36089 100644 --- a/test/syscalls/linux/pivot_root.cc +++ b/test/syscalls/linux/pivot_root.cc @@ -38,6 +38,7 @@ #include "test/util/logging.h" #include "test/util/mount_util.h" #include "test/util/multiprocess_util.h" +#include "test/util/posix_error.h" #include "test/util/temp_path.h" #include "test/util/test_util.h" @@ -397,6 +398,18 @@ TEST(PivotRootTest, OnRootFS) { SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_CHROOT))); + std::vector mounts = + ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); + bool rootFSFound = false; + for (const auto& e : mounts) { + if (e.mount_point == "/" && e.id == e.parent_id) { + rootFSFound = true; + break; + } + } + + SKIP_IF(!rootFSFound); + auto new_root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); const std::string new_root_path = new_root.path(); EXPECT_THAT(mount("", new_root_path.c_str(), "tmpfs", 0, "mode=0700"),