diff --git a/pkg/sentry/vfs/opath.go b/pkg/sentry/vfs/opath.go index da0b33b79..df51bb227 100644 --- a/pkg/sentry/vfs/opath.go +++ b/pkg/sentry/vfs/opath.go @@ -137,3 +137,32 @@ func (fd *opathFD) StatFS(ctx context.Context) (linux.Statfs, error) { rp.Release(ctx) return statfs, err } + +func (vfs *VirtualFilesystem) openOPathFD(ctx context.Context, creds *auth.Credentials, pop *PathOperation, flags uint32) (*FileDescription, error) { + vd, err := vfs.GetDentryAt(ctx, creds, pop, &GetDentryOptions{}) + if err != nil { + return nil, err + } + defer vd.DecRef(ctx) + + if flags&linux.O_DIRECTORY != 0 { + stat, err := vfs.StatAt(ctx, creds, &PathOperation{ + Root: vd, + Start: vd, + }, &StatOptions{ + Mask: linux.STATX_MODE, + }) + if err != nil { + return nil, err + } + if stat.Mode&linux.S_IFDIR == 0 { + return nil, linuxerr.ENOTDIR + } + } + + fd := &opathFD{} + if err := fd.vfsfd.Init(fd, flags, vd.Mount(), vd.Dentry(), &FileDescriptionOptions{}); err != nil { + return nil, err + } + return &fd.vfsfd, err +} diff --git a/pkg/sentry/vfs/vfs.go b/pkg/sentry/vfs/vfs.go index 3921d4acf..0ce44038b 100644 --- a/pkg/sentry/vfs/vfs.go +++ b/pkg/sentry/vfs/vfs.go @@ -417,22 +417,13 @@ func (vfs *VirtualFilesystem) OpenAt(ctx context.Context, creds *auth.Credential if opts.Flags&linux.O_NOFOLLOW != 0 { pop.FollowFinalSymlink = false } + if opts.Flags&linux.O_PATH != 0 { + return vfs.openOPathFD(ctx, creds, pop, opts.Flags) + } rp := vfs.getResolvingPath(creds, pop) if opts.Flags&linux.O_DIRECTORY != 0 { rp.mustBeDir = true } - if opts.Flags&linux.O_PATH != 0 { - vd, err := vfs.GetDentryAt(ctx, creds, pop, &GetDentryOptions{}) - if err != nil { - return nil, err - } - fd := &opathFD{} - if err := fd.vfsfd.Init(fd, opts.Flags, vd.Mount(), vd.Dentry(), &FileDescriptionOptions{}); err != nil { - return nil, err - } - vd.DecRef(ctx) - return &fd.vfsfd, err - } for { fd, err := rp.mount.fs.impl.OpenAt(ctx, rp, *opts) if err == nil { diff --git a/test/syscalls/linux/open.cc b/test/syscalls/linux/open.cc index c1d0ecce3..6fd37f3a2 100644 --- a/test/syscalls/linux/open.cc +++ b/test/syscalls/linux/open.cc @@ -523,6 +523,14 @@ TEST_F(OpenTest, OpenWithOpath) { ASSERT_NO_ERRNO(Open(path, O_PATH)); } +// NOTE(b/236445327): Regression test. Opening a non-directory with O_PATH and +// O_DIRECTORY should fail with ENOTDIR. +TEST_F(OpenTest, OPathWithODirectory) { + auto newFile = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile()); + EXPECT_THAT(open(newFile.path().c_str(), O_RDONLY | O_DIRECTORY | O_PATH), + SyscallFailsWithErrno(ENOTDIR)); +} + } // namespace } // namespace testing