From 417096f781c4fe74ff8a6db5c0fa0d46ba08e81d Mon Sep 17 00:00:00 2001 From: Ayush Ranjan Date: Wed, 24 Jul 2019 17:58:28 -0700 Subject: ext: Add tests for root directory inode. PiperOrigin-RevId: 259856442 --- pkg/sentry/fs/ext/BUILD | 1 + pkg/sentry/fs/ext/dentry.go | 9 ++++ pkg/sentry/fs/ext/disklayout/inode.go | 6 +++ pkg/sentry/fs/ext/ext.go | 7 ++- pkg/sentry/fs/ext/ext_test.go | 85 +++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) (limited to 'pkg/sentry') diff --git a/pkg/sentry/fs/ext/BUILD b/pkg/sentry/fs/ext/BUILD index 7028b3f78..e660e545d 100644 --- a/pkg/sentry/fs/ext/BUILD +++ b/pkg/sentry/fs/ext/BUILD @@ -44,6 +44,7 @@ go_test( "//pkg/sentry/context", "//pkg/sentry/context/contexttest", "//pkg/sentry/fs/ext/disklayout", + "//pkg/sentry/kernel/auth", "//pkg/sentry/vfs", "//runsc/test/testutil", "@com_github_google_go-cmp//cmp:go_default_library", diff --git a/pkg/sentry/fs/ext/dentry.go b/pkg/sentry/fs/ext/dentry.go index 07be99a84..054fb42b6 100644 --- a/pkg/sentry/fs/ext/dentry.go +++ b/pkg/sentry/fs/ext/dentry.go @@ -31,6 +31,15 @@ type dentry struct { // Compiles only if dentry implements vfs.DentryImpl. var _ vfs.DentryImpl = (*dentry)(nil) +// newDentry is the dentry constructor. +func newDentry(in *inode) *dentry { + d := &dentry{ + inode: in, + } + d.vfsd.Init(d) + return d +} + // IncRef implements vfs.DentryImpl.IncRef. func (d *dentry) IncRef(vfsfs *vfs.Filesystem) { d.inode.incRef() diff --git a/pkg/sentry/fs/ext/disklayout/inode.go b/pkg/sentry/fs/ext/disklayout/inode.go index 9ab9a4988..88ae913f5 100644 --- a/pkg/sentry/fs/ext/disklayout/inode.go +++ b/pkg/sentry/fs/ext/disklayout/inode.go @@ -20,6 +20,12 @@ import ( "gvisor.dev/gvisor/pkg/sentry/kernel/time" ) +// Special inodes. See https://www.kernel.org/doc/html/latest/filesystems/ext4/overview.html#special-inodes. +const ( + // RootDirInode is the inode number of the root directory inode. + RootDirInode = 2 +) + // The Inode interface must be implemented by structs representing ext inodes. // The inode stores all the metadata pertaining to the file (except for the // file name which is held by the directory entry). It does NOT expose all diff --git a/pkg/sentry/fs/ext/ext.go b/pkg/sentry/fs/ext/ext.go index c8b554f4d..2604169de 100644 --- a/pkg/sentry/fs/ext/ext.go +++ b/pkg/sentry/fs/ext/ext.go @@ -131,7 +131,12 @@ func (fstype filesystemType) NewFilesystem(ctx context.Context, creds *auth.Cred return nil, nil, err } - return &fs.vfsfs, nil, nil + rootInode, err := fs.getOrCreateInode(disklayout.RootDirInode) + if err != nil { + return nil, nil, err + } + + return &fs.vfsfs, &newDentry(rootInode).vfsd, nil } // getOrCreateInode gets the inode corresponding to the inode number passed in. diff --git a/pkg/sentry/fs/ext/ext_test.go b/pkg/sentry/fs/ext/ext_test.go index f92e77450..ee7f7907c 100644 --- a/pkg/sentry/fs/ext/ext_test.go +++ b/pkg/sentry/fs/ext/ext_test.go @@ -25,6 +25,7 @@ import ( "gvisor.dev/gvisor/pkg/sentry/context" "gvisor.dev/gvisor/pkg/sentry/context/contexttest" "gvisor.dev/gvisor/pkg/sentry/fs/ext/disklayout" + "gvisor.dev/gvisor/pkg/sentry/kernel/auth" "gvisor.dev/gvisor/pkg/sentry/vfs" "gvisor.dev/gvisor/runsc/test/testutil" @@ -82,6 +83,90 @@ func setUp(t *testing.T, imagePath string) (context.Context, *vfs.Filesystem, *v return mockCtx, fs, d, tearDown, nil } +// TestRootDir tests that the root directory inode is correctly initialized and +// returned from setUp. +func TestRootDir(t *testing.T) { + type inodeProps struct { + Mode linux.FileMode + UID auth.KUID + GID auth.KGID + Size uint64 + InodeSize uint16 + Links uint16 + Flags disklayout.InodeFlags + } + + type rootDirTest struct { + name string + image string + wantInode inodeProps + } + + tests := []rootDirTest{ + { + name: "ext4 root dir", + image: ext4ImagePath, + wantInode: inodeProps{ + Mode: linux.ModeDirectory | 0755, + Size: 0x400, + InodeSize: 0x80, + Links: 3, + Flags: disklayout.InodeFlags{Extents: true}, + }, + }, + { + name: "ext3 root dir", + image: ext3ImagePath, + wantInode: inodeProps{ + Mode: linux.ModeDirectory | 0755, + Size: 0x400, + InodeSize: 0x80, + Links: 3, + }, + }, + { + name: "ext2 root dir", + image: ext2ImagePath, + wantInode: inodeProps{ + Mode: linux.ModeDirectory | 0755, + Size: 0x400, + InodeSize: 0x80, + Links: 3, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + _, _, vfsd, tearDown, err := setUp(t, test.image) + if err != nil { + t.Fatalf("setUp failed: %v", err) + } + defer tearDown() + + d, ok := vfsd.Impl().(*dentry) + if !ok { + t.Fatalf("ext dentry of incorrect type: %T", vfsd.Impl()) + } + + // Offload inode contents into local structs for comparison. + gotInode := inodeProps{ + Mode: d.inode.diskInode.Mode(), + UID: d.inode.diskInode.UID(), + GID: d.inode.diskInode.GID(), + Size: d.inode.diskInode.Size(), + InodeSize: d.inode.diskInode.InodeSize(), + Links: d.inode.diskInode.LinksCount(), + Flags: d.inode.diskInode.Flags(), + } + + if diff := cmp.Diff(gotInode, test.wantInode); diff != "" { + t.Errorf("inode mismatch (-want +got):\n%s", diff) + } + }) + } +} + // TestFilesystemInit tests that the filesystem superblock and block group // descriptors are correctly read in and initialized. func TestFilesystemInit(t *testing.T) { -- cgit v1.2.3