summaryrefslogtreecommitdiffhomepage
path: root/pkg
diff options
context:
space:
mode:
authorAndrei Vagin <avagin@google.com>2020-01-28 13:36:16 -0800
committergVisor bot <gvisor-bot@google.com>2020-01-28 13:37:19 -0800
commitf263801a74d4ccac042b068d0928c8738e40af5b (patch)
tree3e4fa2cf7a20ed4a38efb9b582262bfc8dfa12ab /pkg
parent34fbd8446c386fb0136dad31ab6b173f17049a58 (diff)
fs/splice: don't report partial errors for special files
Special files can have additional requirements for granularity. For example, read from eventfd returns EINVAL if a size is less 8 bytes. Reported-by: syzbot+3905f5493bec08eb7b02@syzkaller.appspotmail.com PiperOrigin-RevId: 292002926
Diffstat (limited to 'pkg')
-rw-r--r--pkg/sentry/fs/attr.go5
-rw-r--r--pkg/sentry/fs/file.go7
-rw-r--r--pkg/sentry/fs/splice.go5
-rw-r--r--pkg/sentry/syscalls/linux/sys_splice.go19
4 files changed, 20 insertions, 16 deletions
diff --git a/pkg/sentry/fs/attr.go b/pkg/sentry/fs/attr.go
index fa9e7d517..f60bd423d 100644
--- a/pkg/sentry/fs/attr.go
+++ b/pkg/sentry/fs/attr.go
@@ -206,6 +206,11 @@ func IsPipe(s StableAttr) bool {
return s.Type == Pipe
}
+// IsAnonymous returns true if StableAttr.Type matches any type of anonymous.
+func IsAnonymous(s StableAttr) bool {
+ return s.Type == Anonymous
+}
+
// IsSocket returns true if StableAttr.Type matches any type of socket.
func IsSocket(s StableAttr) bool {
return s.Type == Socket
diff --git a/pkg/sentry/fs/file.go b/pkg/sentry/fs/file.go
index ca3466f4f..78100e448 100644
--- a/pkg/sentry/fs/file.go
+++ b/pkg/sentry/fs/file.go
@@ -555,10 +555,6 @@ type lockedWriter struct {
//
// This applies only to Write, not WriteAt.
Offset int64
-
- // Err contains the first error encountered while copying. This is
- // useful to determine whether Writer or Reader failed during io.Copy.
- Err error
}
// Write implements io.Writer.Write.
@@ -594,8 +590,5 @@ func (w *lockedWriter) WriteAt(buf []byte, offset int64) (int, error) {
break
}
}
- if w.Err == nil {
- w.Err = err
- }
return written, err
}
diff --git a/pkg/sentry/fs/splice.go b/pkg/sentry/fs/splice.go
index 791d1526c..33da82868 100644
--- a/pkg/sentry/fs/splice.go
+++ b/pkg/sentry/fs/splice.go
@@ -167,11 +167,6 @@ func Splice(ctx context.Context, dst *File, src *File, opts SpliceOpts) (int64,
if !srcPipe && !opts.SrcOffset {
atomic.StoreInt64(&src.offset, src.offset+n)
}
-
- // Don't report any errors if we have some progress without data loss.
- if w.Err == nil {
- err = nil
- }
}
// Drop locks.
diff --git a/pkg/sentry/syscalls/linux/sys_splice.go b/pkg/sentry/syscalls/linux/sys_splice.go
index dd3a5807f..f43d6c155 100644
--- a/pkg/sentry/syscalls/linux/sys_splice.go
+++ b/pkg/sentry/syscalls/linux/sys_splice.go
@@ -211,8 +211,10 @@ func Splice(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
opts := fs.SpliceOpts{
Length: count,
}
+ inFileAttr := inFile.Dirent.Inode.StableAttr
+ outFileAttr := outFile.Dirent.Inode.StableAttr
switch {
- case fs.IsPipe(inFile.Dirent.Inode.StableAttr) && !fs.IsPipe(outFile.Dirent.Inode.StableAttr):
+ case fs.IsPipe(inFileAttr) && !fs.IsPipe(outFileAttr):
if inOffset != 0 {
return 0, nil, syserror.ESPIPE
}
@@ -229,7 +231,7 @@ func Splice(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
opts.DstOffset = true
opts.DstStart = offset
}
- case !fs.IsPipe(inFile.Dirent.Inode.StableAttr) && fs.IsPipe(outFile.Dirent.Inode.StableAttr):
+ case !fs.IsPipe(inFileAttr) && fs.IsPipe(outFileAttr):
if outOffset != 0 {
return 0, nil, syserror.ESPIPE
}
@@ -246,13 +248,13 @@ func Splice(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
opts.SrcOffset = true
opts.SrcStart = offset
}
- case fs.IsPipe(inFile.Dirent.Inode.StableAttr) && fs.IsPipe(outFile.Dirent.Inode.StableAttr):
+ case fs.IsPipe(inFileAttr) && fs.IsPipe(outFileAttr):
if inOffset != 0 || outOffset != 0 {
return 0, nil, syserror.ESPIPE
}
// We may not refer to the same pipe; otherwise it's a continuous loop.
- if inFile.Dirent.Inode.StableAttr.InodeID == outFile.Dirent.Inode.StableAttr.InodeID {
+ if inFileAttr.InodeID == outFileAttr.InodeID {
return 0, nil, syserror.EINVAL
}
default:
@@ -262,6 +264,15 @@ func Splice(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
// Splice data.
n, err := doSplice(t, outFile, inFile, opts, nonBlock)
+ // Special files can have additional requirements for granularity. For
+ // example, read from eventfd returns EINVAL if a size is less 8 bytes.
+ // Inotify is another example. read will return EINVAL is a buffer is
+ // too small to return the next event, but a size of an event isn't
+ // fixed, it is sizeof(struct inotify_event) + {NAME_LEN} + 1.
+ if n != 0 && err != nil && (fs.IsAnonymous(inFileAttr) || fs.IsAnonymous(outFileAttr)) {
+ err = nil
+ }
+
// See above; inFile is chosen arbitrarily here.
return uintptr(n), nil, handleIOError(t, n != 0, err, kernel.ERESTARTSYS, "splice", inFile)
}