From dbc507dc5cfde2f69a94a58fcb2744ef0899ce7e Mon Sep 17 00:00:00 2001 From: Jamie Liu Date: Thu, 2 Apr 2020 16:57:08 -0700 Subject: Add equivalents to FMODE_PREAD/PWRITE to VFS2. This is mostly required for PipeTest_OffsetCalls. The options are DenyPRead/PWrite rather than AllowPRead/PWrite since, in Linux terms, fs/open.c:do_dentry_open sets FMODE_PREAD|FMODE_PWRITE unconditionally (although it allows filesystem implementations of open to unset these flags), so they're set for most FDs; it's usually FDs created outside of open(2) that don't get them, e.g.: - Syscall-created pipes (fs/pipe.c:create_pipe_files => fs/file_table.c:alloc_file_pseudo) - Epoll instances (fs/eventpoll.c:do_epoll_create => fs/anon_inodes.c:anon_inode_getfile => alloc_file_pseudo) - Sockets (net/socket.c:sock_alloc_file => alloc_file_pseudo) This CL adds the flags to epoll instances; a subsequent CL reworks the VFS2 implementation of pipe FDs to be filesystem-independent and adds the flags there, and sockets aren't implemented yet. Updates #1035 PiperOrigin-RevId: 304506434 --- pkg/sentry/vfs/epoll.go | 2 ++ pkg/sentry/vfs/file_description.go | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/pkg/sentry/vfs/epoll.go b/pkg/sentry/vfs/epoll.go index 3da45d744..8e0b40841 100644 --- a/pkg/sentry/vfs/epoll.go +++ b/pkg/sentry/vfs/epoll.go @@ -99,6 +99,8 @@ func (vfs *VirtualFilesystem) NewEpollInstanceFD() (*FileDescription, error) { interest: make(map[epollInterestKey]*epollInterest), } if err := ep.vfsfd.Init(ep, linux.O_RDWR, vd.Mount(), vd.Dentry(), &FileDescriptionOptions{ + DenyPRead: true, + DenyPWrite: true, UseDentryMetadata: true, }); err != nil { return nil, err diff --git a/pkg/sentry/vfs/file_description.go b/pkg/sentry/vfs/file_description.go index 8ee549dc2..5df4bbf45 100644 --- a/pkg/sentry/vfs/file_description.go +++ b/pkg/sentry/vfs/file_description.go @@ -84,6 +84,13 @@ type FileDescriptionOptions struct { // usually only the case if O_DIRECT would actually have an effect. AllowDirectIO bool + // If DenyPRead is true, calls to FileDescription.PRead() return ESPIPE. + DenyPRead bool + + // If DenyPWrite is true, calls to FileDescription.PWrite() return + // ESPIPE. + DenyPWrite bool + // If UseDentryMetadata is true, calls to FileDescription methods that // interact with file and filesystem metadata (Stat, SetStat, StatFS, // Listxattr, Getxattr, Setxattr, Removexattr) are implemented by calling @@ -306,6 +313,7 @@ type FileDescriptionImpl interface { // - If opts.Flags specifies unsupported options, PRead returns EOPNOTSUPP. // // Preconditions: The FileDescription was opened for reading. + // FileDescriptionOptions.DenyPRead == false. PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts ReadOptions) (int64, error) // Read is similar to PRead, but does not specify an offset. @@ -337,6 +345,7 @@ type FileDescriptionImpl interface { // EOPNOTSUPP. // // Preconditions: The FileDescription was opened for writing. + // FileDescriptionOptions.DenyPWrite == false. PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts WriteOptions) (int64, error) // Write is similar to PWrite, but does not specify an offset, which is @@ -515,6 +524,9 @@ func (fd *FileDescription) EventUnregister(e *waiter.Entry) { // offset, and returns the number of bytes read. PRead is permitted to return // partial reads with a nil error. func (fd *FileDescription) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts ReadOptions) (int64, error) { + if fd.opts.DenyPRead { + return 0, syserror.ESPIPE + } if !fd.readable { return 0, syserror.EBADF } @@ -533,6 +545,9 @@ func (fd *FileDescription) Read(ctx context.Context, dst usermem.IOSequence, opt // offset, and returns the number of bytes written. PWrite is permitted to // return partial writes with a nil error. func (fd *FileDescription) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts WriteOptions) (int64, error) { + if fd.opts.DenyPWrite { + return 0, syserror.ESPIPE + } if !fd.writable { return 0, syserror.EBADF } -- cgit v1.2.3