From 99cc6c2dea59ca51f7672359ed4321041fae02a4 Mon Sep 17 00:00:00 2001 From: Lucas Manning Date: Thu, 1 Dec 2022 16:03:04 -0800 Subject: [PATCH] Display the proper root path in mountinfo. PiperOrigin-RevId: 492323370 --- pkg/sentry/fsimpl/tmpfs/filesystem.go | 2 +- pkg/sentry/vfs/mount.go | 30 +++++++++++++++++---------- pkg/sentry/vfs/pathname.go | 23 ++++++++++++++++++++ test/syscalls/linux/mount.cc | 20 ++++++++++++++++++ 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/pkg/sentry/fsimpl/tmpfs/filesystem.go b/pkg/sentry/fsimpl/tmpfs/filesystem.go index fb398f499..59b2efe4e 100644 --- a/pkg/sentry/fsimpl/tmpfs/filesystem.go +++ b/pkg/sentry/fsimpl/tmpfs/filesystem.go @@ -920,7 +920,7 @@ func (fs *filesystem) PrependPath(ctx context.Context, vfsroot, vd vfs.VirtualDe if mnt == vfsroot.Mount() && &d.vfsd == vfsroot.Dentry() { return vfs.PrependPathAtVFSRootError{} } - if &d.vfsd == mnt.Root() { + if mnt != nil && &d.vfsd == mnt.Root() { return nil } if d.parent == nil { diff --git a/pkg/sentry/vfs/mount.go b/pkg/sentry/vfs/mount.go index 5904adb9e..3383fa8cc 100644 --- a/pkg/sentry/vfs/mount.go +++ b/pkg/sentry/vfs/mount.go @@ -1161,16 +1161,27 @@ func (vfs *VirtualFilesystem) GenerateProcMountInfo(ctx context.Context, taskRoo mount: mnt, dentry: mnt.root, } - path, err := vfs.PathnameReachable(ctx, taskRootDir, mntRootVD) + pathFromRoot, err := vfs.PathnameReachable(ctx, taskRootDir, mntRootVD) if err != nil { // For some reason we didn't get a path. Log a warning // and run with empty path. ctx.Warningf("VFS.GenerateProcMountInfo: error getting pathname for mount root %+v: %v", mnt.root, err) - path = "" + continue } - if path == "" { - // Either an error occurred, or path is not reachable - // from root. + if pathFromRoot == "" { + // The path is not reachable from root. + continue + } + var pathFromFS string + pathFromFS, err = vfs.PathnameInFilesystem(ctx, mntRootVD) + if err != nil { + // For some reason we didn't get a path. Log a warning + // and run with empty path. + ctx.Warningf("VFS.GenerateProcMountInfo: error getting pathname for mount root %+v: %v", mnt.root, err) + continue + } + if pathFromFS == "" { + // The path is not reachable from root. continue } // Stat the mount root to get the major/minor device numbers. @@ -1208,13 +1219,10 @@ func (vfs *VirtualFilesystem) GenerateProcMountInfo(ctx context.Context, taskRoo // (4) Root: the pathname of the directory in the filesystem // which forms the root of this mount. - // - // NOTE(b/78135857): This will always be "/" until we implement - // bind mounts. - fmt.Fprintf(buf, "/ ") + fmt.Fprintf(buf, "%s ", manglePath(pathFromFS)) // (5) Mount point (relative to process root). - fmt.Fprintf(buf, "%s ", manglePath(path)) + fmt.Fprintf(buf, "%s ", manglePath(pathFromRoot)) // (6) Mount options. opts := "rw" @@ -1241,7 +1249,7 @@ func (vfs *VirtualFilesystem) GenerateProcMountInfo(ctx context.Context, taskRoo fmt.Fprintf(buf, "none ") // (11) Superblock options, and final newline. - fmt.Fprintf(buf, "%s\n", superBlockOpts(path, mnt)) + fmt.Fprintf(buf, "%s\n", superBlockOpts(pathFromRoot, mnt)) } } diff --git a/pkg/sentry/vfs/pathname.go b/pkg/sentry/vfs/pathname.go index 7efe72021..a06a69c59 100644 --- a/pkg/sentry/vfs/pathname.go +++ b/pkg/sentry/vfs/pathname.go @@ -133,6 +133,29 @@ loop: return b.String(), nil } +// PathnameInFilesystem returns an absolute path to vd relative to vd's +// Filesystem root. It also appends //deleted to for disowned entries. It is +// equivalent to Linux's dentry_path(). +func (vfs *VirtualFilesystem) PathnameInFilesystem(ctx context.Context, vd VirtualDentry) (string, error) { + b := getFSPathBuilder() + defer putFSPathBuilder(b) + if vd.dentry.IsDead() { + b.PrependString("//deleted") + } + if err := vd.mount.fs.impl.PrependPath(ctx, VirtualDentry{}, VirtualDentry{dentry: vd.dentry}, b); err != nil { + // PrependPath returns an error if it encounters a filesystem root before + // the provided vfsroot. We don't provide a vfsroot, so encountering this + // error is expected and can be ignored. + switch err.(type) { + case PrependPathAtNonMountRootError: + default: + return "", err + } + } + b.PrependByte('/') + return b.String(), nil +} + // PathnameForGetcwd returns an absolute pathname to vd, consistent with // Linux's sys_getcwd(). func (vfs *VirtualFilesystem) PathnameForGetcwd(ctx context.Context, vfsroot, vd VirtualDentry) (string, error) { diff --git a/test/syscalls/linux/mount.cc b/test/syscalls/linux/mount.cc index 096e31a30..ea34c3477 100644 --- a/test/syscalls/linux/mount.cc +++ b/test/syscalls/linux/mount.cc @@ -1397,6 +1397,26 @@ TEST(MountTest, BindParentToChild) { ASSERT_EQ(opt2, opt3); } +TEST(MountTest, MountInfoHasRoot) { + SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); + auto const parent = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + auto const mount = ASSERT_NO_ERRNO_AND_VALUE( + Mount("", parent.path(), "tmpfs", 0, "mode=0123", 0)); + auto const child = + ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent.path())); + auto const bind_mount = Mount(child.path(), child.path(), "", MS_BIND, "", 0); + std::vector mounts = + ASSERT_NO_ERRNO_AND_VALUE(ProcSelfMountInfoEntries()); + for (const auto& e : mounts) { + if (e.mount_point == child.path()) { + ASSERT_EQ(e.root, JoinPath("/", Basename(child.path()))); + } + if (e.mount_point == parent.path()) { + ASSERT_EQ(e.root, "/"); + } + } +} + } // namespace } // namespace testing