summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fsimpl/host
diff options
context:
space:
mode:
authorDean Deng <deandeng@google.com>2020-04-07 16:16:31 -0700
committergVisor bot <gvisor-bot@google.com>2020-04-07 16:17:40 -0700
commit693b6bdda9206a5910c552a3997b2df5480d6947 (patch)
treedc14bb5ecb3f1e7190fac8f7dbfd82aae1036826 /pkg/sentry/fsimpl/host
parentfc72eb3595a7c4e2fa83caa39a9bb4171875c208 (diff)
Correctly distinguish between seekable and non-seekable host fds.
Check whether an fd is seekable by calling the seek syscall and examining the return value, instead of checking the file type, which is inaccurate. PiperOrigin-RevId: 305361593
Diffstat (limited to 'pkg/sentry/fsimpl/host')
-rw-r--r--pkg/sentry/fsimpl/host/host.go42
1 files changed, 20 insertions, 22 deletions
diff --git a/pkg/sentry/fsimpl/host/host.go b/pkg/sentry/fsimpl/host/host.go
index 7d9dcd4c9..97fa7f7ab 100644
--- a/pkg/sentry/fsimpl/host/host.go
+++ b/pkg/sentry/fsimpl/host/host.go
@@ -74,31 +74,34 @@ func ImportFD(mnt *vfs.Mount, hostFD int, isTTY bool) (*vfs.FileDescription, err
}
// Retrieve metadata.
- var s syscall.Stat_t
- if err := syscall.Fstat(hostFD, &s); err != nil {
+ var s unix.Stat_t
+ if err := unix.Fstat(hostFD, &s); err != nil {
return nil, err
}
fileMode := linux.FileMode(s.Mode)
fileType := fileMode.FileType()
- // Pipes, character devices, and sockets.
- isStream := fileType == syscall.S_IFIFO || fileType == syscall.S_IFCHR || fileType == syscall.S_IFSOCK
+
+ // Determine if hostFD is seekable. If not, this syscall will return ESPIPE
+ // (see fs/read_write.c:llseek), e.g. for pipes, sockets, and some character
+ // devices.
+ _, err := unix.Seek(hostFD, 0, linux.SEEK_CUR)
+ seekable := err != syserror.ESPIPE
i := &inode{
hostFD: hostFD,
- isStream: isStream,
+ seekable: seekable,
isTTY: isTTY,
canMap: canMap(uint32(fileType)),
ino: fs.NextIno(),
mode: fileMode,
- // For simplicity, set offset to 0. Technically, we should
- // only set to 0 on files that are not seekable (sockets, pipes, etc.),
- // and use the offset from the host fd otherwise.
+ // For simplicity, set offset to 0. Technically, we should use the existing
+ // offset on the host if the file is seekable.
offset: 0,
}
- // These files can't be memory mapped, assert this.
- if i.isStream && i.canMap {
+ // Non-seekable files can't be memory mapped, assert this.
+ if !i.seekable && i.canMap {
panic("files that can return EWOULDBLOCK (sockets, pipes, etc.) cannot be memory mapped")
}
@@ -124,12 +127,12 @@ type inode struct {
// This field is initialized at creation time and is immutable.
hostFD int
- // isStream is true if the host fd points to a file representing a stream,
+ // seekable is false if the host fd points to a file representing a stream,
// e.g. a socket or a pipe. Such files are not seekable and can return
// EWOULDBLOCK for I/O operations.
//
// This field is initialized at creation time and is immutable.
- isStream bool
+ seekable bool
// isTTY is true if this file represents a TTY.
//
@@ -481,8 +484,7 @@ func (f *fileDescription) Release() {
// PRead implements FileDescriptionImpl.
func (f *fileDescription) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts vfs.ReadOptions) (int64, error) {
i := f.inode
- // TODO(b/34716638): Some char devices do support offsets, e.g. /dev/null.
- if i.isStream {
+ if !i.seekable {
return 0, syserror.ESPIPE
}
@@ -492,8 +494,7 @@ func (f *fileDescription) PRead(ctx context.Context, dst usermem.IOSequence, off
// Read implements FileDescriptionImpl.
func (f *fileDescription) Read(ctx context.Context, dst usermem.IOSequence, opts vfs.ReadOptions) (int64, error) {
i := f.inode
- // TODO(b/34716638): Some char devices do support offsets, e.g. /dev/null.
- if i.isStream {
+ if !i.seekable {
n, err := readFromHostFD(ctx, i.hostFD, dst, -1, opts.Flags)
if isBlockError(err) {
// If we got any data at all, return it as a "completed" partial read
@@ -538,8 +539,7 @@ func readFromHostFD(ctx context.Context, hostFD int, dst usermem.IOSequence, off
// PWrite implements FileDescriptionImpl.
func (f *fileDescription) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts vfs.WriteOptions) (int64, error) {
i := f.inode
- // TODO(b/34716638): Some char devices do support offsets, e.g. /dev/null.
- if i.isStream {
+ if !i.seekable {
return 0, syserror.ESPIPE
}
@@ -549,8 +549,7 @@ func (f *fileDescription) PWrite(ctx context.Context, src usermem.IOSequence, of
// Write implements FileDescriptionImpl.
func (f *fileDescription) Write(ctx context.Context, src usermem.IOSequence, opts vfs.WriteOptions) (int64, error) {
i := f.inode
- // TODO(b/34716638): Some char devices do support offsets, e.g. /dev/null.
- if i.isStream {
+ if !i.seekable {
n, err := writeToHostFD(ctx, i.hostFD, src, -1, opts.Flags)
if isBlockError(err) {
err = syserror.ErrWouldBlock
@@ -593,8 +592,7 @@ func writeToHostFD(ctx context.Context, hostFD int, src usermem.IOSequence, offs
// allow directory fds to be imported at all.
func (f *fileDescription) Seek(_ context.Context, offset int64, whence int32) (int64, error) {
i := f.inode
- // TODO(b/34716638): Some char devices do support seeking, e.g. /dev/null.
- if i.isStream {
+ if !i.seekable {
return 0, syserror.ESPIPE
}