diff --git a/images/basic/integrationtest/host_fd.c b/images/basic/integrationtest/host_fd.c index 32990bb62..0066a1b6f 100644 --- a/images/basic/integrationtest/host_fd.c +++ b/images/basic/integrationtest/host_fd.c @@ -13,11 +13,13 @@ // limitations under the License. #include +#include +#include #include #include // Tests that FIONREAD is supported with host FD. -int main(int argc, char** argv) { +void testFionread() { int size = 0; if (ioctl(STDOUT_FILENO, FIONREAD, &size) < 0) { err(1, "ioctl(stdin, FIONREAD)"); @@ -25,5 +27,30 @@ int main(int argc, char** argv) { if (size != 0) { err(1, "FIONREAD wrong size, want: 0, got: %d", size); } +} + +// Docker maps stdin to /dev/null which doesn't support epoll. Check that error +// is correctly propagated. +void testEpoll() { + int fd = epoll_create(1); + if (fd < 0) { + err(1, "epoll_create"); + } + + struct epoll_event event; + event.events = EPOLLIN; + event.data.u64 = 123; + int res = epoll_ctl(fd, EPOLL_CTL_ADD, 0, &event); + if (res != -1) { + err(1, "epoll_ctl(EPOLL_CTL_ADD, stdin) should have failed"); + } + if (errno != EPERM) { + err(1, "epoll_ctl(EPOLL_CTL_ADD, stdin) should have returned EPERM"); + } +} + +int main(int argc, char** argv) { + testFionread(); + testEpoll(); return 0; } diff --git a/pkg/sentry/devices/tundev/tundev.go b/pkg/sentry/devices/tundev/tundev.go index d197c52d7..c98c8d3f8 100644 --- a/pkg/sentry/devices/tundev/tundev.go +++ b/pkg/sentry/devices/tundev/tundev.go @@ -152,8 +152,9 @@ func (fd *tunFD) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements watier.Waitable.EventRegister. -func (fd *tunFD) EventRegister(e *waiter.Entry) { +func (fd *tunFD) EventRegister(e *waiter.Entry) error { fd.device.EventRegister(e) + return nil } // EventUnregister implements watier.Waitable.EventUnregister. diff --git a/pkg/sentry/fs/dev/net_tun.go b/pkg/sentry/fs/dev/net_tun.go index 4b8a2d4f9..89aa2666d 100644 --- a/pkg/sentry/fs/dev/net_tun.go +++ b/pkg/sentry/fs/dev/net_tun.go @@ -158,8 +158,9 @@ func (n *netTunFileOperations) Readiness(mask waiter.EventMask) waiter.EventMask } // EventRegister implements watier.Waitable.EventRegister. -func (n *netTunFileOperations) EventRegister(e *waiter.Entry) { +func (n *netTunFileOperations) EventRegister(e *waiter.Entry) error { n.device.EventRegister(e) + return nil } // EventUnregister implements watier.Waitable.EventUnregister. diff --git a/pkg/sentry/fs/fdpipe/pipe.go b/pkg/sentry/fs/fdpipe/pipe.go index 2d79f89d7..97e40ce87 100644 --- a/pkg/sentry/fs/fdpipe/pipe.go +++ b/pkg/sentry/fs/fdpipe/pipe.go @@ -16,6 +16,7 @@ package fdpipe import ( + "fmt" "os" "golang.org/x/sys/unix" @@ -99,15 +100,21 @@ func (p *pipeOperations) init() error { } // EventRegister implements waiter.Waitable.EventRegister. -func (p *pipeOperations) EventRegister(e *waiter.Entry) { +func (p *pipeOperations) EventRegister(e *waiter.Entry) error { p.Queue.EventRegister(e) - fdnotifier.UpdateFD(int32(p.file.FD())) + if err := fdnotifier.UpdateFD(int32(p.file.FD())); err != nil { + p.Queue.EventUnregister(e) + return err + } + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. func (p *pipeOperations) EventUnregister(e *waiter.Entry) { p.Queue.EventUnregister(e) - fdnotifier.UpdateFD(int32(p.file.FD())) + if err := fdnotifier.UpdateFD(int32(p.file.FD())); err != nil { + panic(fmt.Sprint("UpdateFD:", err)) + } } // Readiness returns a mask of ready events for stream. diff --git a/pkg/sentry/fs/file.go b/pkg/sentry/fs/file.go index 55d7bf809..6f42b0443 100644 --- a/pkg/sentry/fs/file.go +++ b/pkg/sentry/fs/file.go @@ -159,7 +159,8 @@ func (f *File) SetFlags(newFlags SettableFileFlags) { f.flags.Append = newFlags.Append if f.async != nil { if newFlags.Async && !f.flags.Async { - f.async.Register(f) + // Ignore error given that VFS1 will not be here much longer. + _ = f.async.Register(f) } if !newFlags.Async && f.flags.Async { f.async.Unregister(f) @@ -180,8 +181,8 @@ func (f *File) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (f *File) EventRegister(e *waiter.Entry) { - f.FileOperations.EventRegister(e) +func (f *File) EventRegister(e *waiter.Entry) error { + return f.FileOperations.EventRegister(e) } // EventUnregister implements waiter.Waitable.EventUnregister. @@ -424,23 +425,25 @@ func (f *File) Msync(ctx context.Context, mr memmap.MappableRange) error { // A FileAsync sends signals to its owner when w is ready for IO. type FileAsync interface { - Register(w waiter.Waitable) + Register(w waiter.Waitable) error Unregister(w waiter.Waitable) } // Async gets the stored FileAsync or creates a new one with the supplied // function. If the supplied function is nil, no FileAsync is created and the // current value is returned. -func (f *File) Async(newAsync func() FileAsync) FileAsync { +func (f *File) Async(newAsync func() FileAsync) (FileAsync, error) { f.flagsMu.Lock() defer f.flagsMu.Unlock() if f.async == nil && newAsync != nil { f.async = newAsync() if f.flags.Async { - f.async.Register(f) + if err := f.async.Register(f); err != nil { + return nil, err + } } } - return f.async + return f.async, nil } // lockedReader implements io.Reader and io.ReaderAt. diff --git a/pkg/sentry/fs/file_overlay.go b/pkg/sentry/fs/file_overlay.go index ae2f959b2..52e1be1f2 100644 --- a/pkg/sentry/fs/file_overlay.go +++ b/pkg/sentry/fs/file_overlay.go @@ -100,14 +100,13 @@ func (f *overlayFileOperations) Release(ctx context.Context) { } // EventRegister implements FileOperations.EventRegister. -func (f *overlayFileOperations) EventRegister(we *waiter.Entry) { +func (f *overlayFileOperations) EventRegister(we *waiter.Entry) error { f.upperMu.Lock() defer f.upperMu.Unlock() if f.upper != nil { - f.upper.EventRegister(we) - return + return f.upper.EventRegister(we) } - f.lower.EventRegister(we) + return f.lower.EventRegister(we) } // EventUnregister implements FileOperations.Unregister. diff --git a/pkg/sentry/fs/file_state.go b/pkg/sentry/fs/file_state.go index a8d14357a..032e94629 100644 --- a/pkg/sentry/fs/file_state.go +++ b/pkg/sentry/fs/file_state.go @@ -14,6 +14,8 @@ package fs +import "fmt" + // beforeSave is invoked by stateify. func (f *File) beforeSave() { f.saving = true @@ -25,6 +27,8 @@ func (f *File) beforeSave() { // afterLoad is invoked by stateify. func (f *File) afterLoad() { if f.flags.Async && f.async != nil { - f.async.Register(f) + if err := f.async.Register(f); err != nil { + panic(fmt.Sprint("async.Register:", err)) + } } } diff --git a/pkg/sentry/fs/host/file.go b/pkg/sentry/fs/host/file.go index 1d405c782..83779ec38 100644 --- a/pkg/sentry/fs/host/file.go +++ b/pkg/sentry/fs/host/file.go @@ -149,15 +149,21 @@ func newFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags, iops *i } // EventRegister implements waiter.Waitable.EventRegister. -func (f *fileOperations) EventRegister(e *waiter.Entry) { +func (f *fileOperations) EventRegister(e *waiter.Entry) error { f.iops.fileState.queue.EventRegister(e) - fdnotifier.UpdateFD(int32(f.iops.fileState.FD())) + if err := fdnotifier.UpdateFD(int32(f.iops.fileState.FD())); err != nil { + f.iops.fileState.queue.EventUnregister(e) + return err + } + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. func (f *fileOperations) EventUnregister(e *waiter.Entry) { f.iops.fileState.queue.EventUnregister(e) - fdnotifier.UpdateFD(int32(f.iops.fileState.FD())) + if err := fdnotifier.UpdateFD(int32(f.iops.fileState.FD())); err != nil { + panic(fmt.Sprint("UpdateFD:", err)) + } } // Readiness uses the poll() syscall to check the status of the underlying FD. diff --git a/pkg/sentry/fs/host/socket.go b/pkg/sentry/fs/host/socket.go index 458e565db..37c876505 100644 --- a/pkg/sentry/fs/host/socket.go +++ b/pkg/sentry/fs/host/socket.go @@ -259,12 +259,15 @@ func (c *ConnectedEndpoint) GetLocalAddress() (tcpip.FullAddress, tcpip.Error) { } // EventUpdate implements transport.ConnectedEndpoint.EventUpdate. -func (c *ConnectedEndpoint) EventUpdate() { +func (c *ConnectedEndpoint) EventUpdate() error { c.mu.RLock() defer c.mu.RUnlock() if c.file.FD() != -1 { - fdnotifier.UpdateFD(int32(c.file.FD())) + if err := fdnotifier.UpdateFD(int32(c.file.FD())); err != nil { + return err + } } + return nil } // Recv implements transport.Receiver.Recv. diff --git a/pkg/sentry/fs/inotify.go b/pkg/sentry/fs/inotify.go index 941f37116..a164afe2a 100644 --- a/pkg/sentry/fs/inotify.go +++ b/pkg/sentry/fs/inotify.go @@ -351,3 +351,9 @@ func (i *Inotify) RmWatch(ctx context.Context, wd int32) error { return nil } + +// EventRegister implements waiter.Waitable. +func (i *Inotify) EventRegister(e *waiter.Entry) error { + i.Queue.EventRegister(e) + return nil +} diff --git a/pkg/sentry/fs/timerfd/timerfd.go b/pkg/sentry/fs/timerfd/timerfd.go index 66ae9debb..4c0744d8c 100644 --- a/pkg/sentry/fs/timerfd/timerfd.go +++ b/pkg/sentry/fs/timerfd/timerfd.go @@ -108,8 +108,9 @@ func (t *TimerOperations) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (t *TimerOperations) EventRegister(e *waiter.Entry) { +func (t *TimerOperations) EventRegister(e *waiter.Entry) error { t.events.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/fs/tty/master.go b/pkg/sentry/fs/tty/master.go index 2003e658a..7702f6c98 100644 --- a/pkg/sentry/fs/tty/master.go +++ b/pkg/sentry/fs/tty/master.go @@ -128,8 +128,9 @@ func (mf *masterFileOperations) Release(ctx context.Context) { } // EventRegister implements waiter.Waitable.EventRegister. -func (mf *masterFileOperations) EventRegister(e *waiter.Entry) { +func (mf *masterFileOperations) EventRegister(e *waiter.Entry) error { mf.t.ld.masterWaiter.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/fs/tty/replica.go b/pkg/sentry/fs/tty/replica.go index 272ce3ae9..e58e610a1 100644 --- a/pkg/sentry/fs/tty/replica.go +++ b/pkg/sentry/fs/tty/replica.go @@ -113,8 +113,9 @@ func (sf *replicaFileOperations) Release(context.Context) { } // EventRegister implements waiter.Waitable.EventRegister. -func (sf *replicaFileOperations) EventRegister(e *waiter.Entry) { +func (sf *replicaFileOperations) EventRegister(e *waiter.Entry) error { sf.si.t.ld.replicaWaiter.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/fsimpl/devpts/master.go b/pkg/sentry/fsimpl/devpts/master.go index 0ce84302f..35a682b40 100644 --- a/pkg/sentry/fsimpl/devpts/master.go +++ b/pkg/sentry/fsimpl/devpts/master.go @@ -103,8 +103,9 @@ func (mfd *masterFileDescription) Release(ctx context.Context) { } // EventRegister implements waiter.Waitable.EventRegister. -func (mfd *masterFileDescription) EventRegister(e *waiter.Entry) { +func (mfd *masterFileDescription) EventRegister(e *waiter.Entry) error { mfd.t.ld.masterWaiter.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/fsimpl/devpts/replica.go b/pkg/sentry/fsimpl/devpts/replica.go index 5b6311d3c..eced9e618 100644 --- a/pkg/sentry/fsimpl/devpts/replica.go +++ b/pkg/sentry/fsimpl/devpts/replica.go @@ -112,8 +112,9 @@ var _ vfs.FileDescriptionImpl = (*replicaFileDescription)(nil) func (rfd *replicaFileDescription) Release(ctx context.Context) {} // EventRegister implements waiter.Waitable.EventRegister. -func (rfd *replicaFileDescription) EventRegister(e *waiter.Entry) { +func (rfd *replicaFileDescription) EventRegister(e *waiter.Entry) error { rfd.inode.t.ld.replicaWaiter.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/fsimpl/eventfd/eventfd.go b/pkg/sentry/fsimpl/eventfd/eventfd.go index 8ba81a74e..f79d2b252 100644 --- a/pkg/sentry/fsimpl/eventfd/eventfd.go +++ b/pkg/sentry/fsimpl/eventfd/eventfd.go @@ -16,6 +16,7 @@ package eventfd import ( + "fmt" "math" "sync" @@ -266,14 +267,18 @@ func (efd *EventFileDescription) Readiness(mask waiter.EventMask) waiter.EventMa } // EventRegister implements waiter.Waitable.EventRegister. -func (efd *EventFileDescription) EventRegister(entry *waiter.Entry) { +func (efd *EventFileDescription) EventRegister(entry *waiter.Entry) error { efd.queue.EventRegister(entry) efd.mu.Lock() defer efd.mu.Unlock() if efd.hostfd >= 0 { - fdnotifier.UpdateFD(int32(efd.hostfd)) + if err := fdnotifier.UpdateFD(int32(efd.hostfd)); err != nil { + efd.queue.EventUnregister(entry) + return err + } } + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. @@ -283,6 +288,8 @@ func (efd *EventFileDescription) EventUnregister(entry *waiter.Entry) { efd.mu.Lock() defer efd.mu.Unlock() if efd.hostfd >= 0 { - fdnotifier.UpdateFD(int32(efd.hostfd)) + if err := fdnotifier.UpdateFD(int32(efd.hostfd)); err != nil { + panic(fmt.Sprint("UpdateFD:", err)) + } } } diff --git a/pkg/sentry/fsimpl/eventfd/eventfd_test.go b/pkg/sentry/fsimpl/eventfd/eventfd_test.go index fcf759b87..41b4cd7f6 100644 --- a/pkg/sentry/fsimpl/eventfd/eventfd_test.go +++ b/pkg/sentry/fsimpl/eventfd/eventfd_test.go @@ -49,7 +49,9 @@ func TestEventFD(t *testing.T) { // Register a callback for a write event. w, ch := waiter.NewChannelEntry(waiter.ReadableEvents) - eventfd.EventRegister(&w) + if err := eventfd.EventRegister(&w); err != nil { + t.Fatalf("EventRegister(): %v", err) + } defer eventfd.EventUnregister(&w) data := []byte("00000124") diff --git a/pkg/sentry/fsimpl/fuse/dev.go b/pkg/sentry/fsimpl/fuse/dev.go index f2c688219..55d86b933 100644 --- a/pkg/sentry/fsimpl/fuse/dev.go +++ b/pkg/sentry/fsimpl/fuse/dev.go @@ -378,8 +378,9 @@ func (fd *DeviceFD) readinessLocked(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (fd *DeviceFD) EventRegister(e *waiter.Entry) { +func (fd *DeviceFD) EventRegister(e *waiter.Entry) error { fd.waitQueue.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/fsimpl/gofer/special_file.go b/pkg/sentry/fsimpl/gofer/special_file.go index 1536601b9..65af8856e 100644 --- a/pkg/sentry/fsimpl/gofer/special_file.go +++ b/pkg/sentry/fsimpl/gofer/special_file.go @@ -15,6 +15,7 @@ package gofer import ( + "fmt" "sync/atomic" "golang.org/x/sys/unix" @@ -165,20 +166,25 @@ func (fd *specialFileFD) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (fd *specialFileFD) EventRegister(e *waiter.Entry) { +func (fd *specialFileFD) EventRegister(e *waiter.Entry) error { if fd.haveQueue { fd.queue.EventRegister(e) - fdnotifier.UpdateFD(fd.handle.fd) - return + if err := fdnotifier.UpdateFD(fd.handle.fd); err != nil { + fd.queue.EventUnregister(e) + return err + } + return nil } - fd.fileDescription.EventRegister(e) + return fd.fileDescription.EventRegister(e) } // EventUnregister implements waiter.Waitable.EventUnregister. func (fd *specialFileFD) EventUnregister(e *waiter.Entry) { if fd.haveQueue { fd.queue.EventUnregister(e) - fdnotifier.UpdateFD(fd.handle.fd) + if err := fdnotifier.UpdateFD(fd.handle.fd); err != nil { + panic(fmt.Sprint("UpdateFD:", err)) + } return } fd.fileDescription.EventUnregister(e) diff --git a/pkg/sentry/fsimpl/host/host.go b/pkg/sentry/fsimpl/host/host.go index f1939776e..c4e58f82c 100644 --- a/pkg/sentry/fsimpl/host/host.go +++ b/pkg/sentry/fsimpl/host/host.go @@ -907,18 +907,24 @@ func (f *fileDescription) ConfigureMMap(_ context.Context, opts *memmap.MMapOpts } // EventRegister implements waiter.Waitable.EventRegister. -func (f *fileDescription) EventRegister(e *waiter.Entry) { +func (f *fileDescription) EventRegister(e *waiter.Entry) error { f.inode.queue.EventRegister(e) if f.inode.mayBlock { - fdnotifier.UpdateFD(int32(f.inode.hostFD)) + if err := fdnotifier.UpdateFD(int32(f.inode.hostFD)); err != nil { + f.inode.queue.EventUnregister(e) + return err + } } + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. func (f *fileDescription) EventUnregister(e *waiter.Entry) { f.inode.queue.EventUnregister(e) if f.inode.mayBlock { - fdnotifier.UpdateFD(int32(f.inode.hostFD)) + if err := fdnotifier.UpdateFD(int32(f.inode.hostFD)); err != nil { + panic(fmt.Sprint("UpdateFD:", err)) + } } } diff --git a/pkg/sentry/fsimpl/mqfs/queue.go b/pkg/sentry/fsimpl/mqfs/queue.go index dae7208a9..eee2bd8f6 100644 --- a/pkg/sentry/fsimpl/mqfs/queue.go +++ b/pkg/sentry/fsimpl/mqfs/queue.go @@ -135,8 +135,8 @@ func (fd *queueFD) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements Waitable.EventRegister. -func (fd *queueFD) EventRegister(e *waiter.Entry) { - fd.queue.EventRegister(e) +func (fd *queueFD) EventRegister(e *waiter.Entry) error { + return fd.queue.EventRegister(e) } // EventUnregister implements Waitable.EventUnregister. diff --git a/pkg/sentry/fsimpl/overlay/regular_file.go b/pkg/sentry/fsimpl/overlay/regular_file.go index 719990346..65d270c69 100644 --- a/pkg/sentry/fsimpl/overlay/regular_file.go +++ b/pkg/sentry/fsimpl/overlay/regular_file.go @@ -103,7 +103,9 @@ func (fd *regularFileFD) currentFDLocked(ctx context.Context) (*vfs.FileDescript ready := upperFD.Readiness(^waiter.EventMask(0)) for e := range fd.lowerWaiters { fd.cachedFD.EventUnregister(e) - upperFD.EventRegister(e) + if err := upperFD.EventRegister(e); err != nil { + return nil, err + } e.NotifyEvent(ready) } } @@ -254,7 +256,7 @@ func (fd *regularFileFD) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (fd *regularFileFD) EventRegister(e *waiter.Entry) { +func (fd *regularFileFD) EventRegister(e *waiter.Entry) error { fd.mu.Lock() defer fd.mu.Unlock() wrappedFD, err := fd.currentFDLocked(context.Background()) @@ -265,13 +267,16 @@ func (fd *regularFileFD) EventRegister(e *waiter.Entry) { log.Warningf("overlay.regularFileFD.EventRegister: currentFDLocked failed: %v", err) wrappedFD = fd.cachedFD } - wrappedFD.EventRegister(e) + if err := wrappedFD.EventRegister(e); err != nil { + return err + } if !fd.copiedUp { if fd.lowerWaiters == nil { fd.lowerWaiters = make(map[*waiter.Entry]struct{}) } fd.lowerWaiters[e] = struct{}{} } + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/fsimpl/signalfd/signalfd.go b/pkg/sentry/fsimpl/signalfd/signalfd.go index 746d205c9..a1f8aed14 100644 --- a/pkg/sentry/fsimpl/signalfd/signalfd.go +++ b/pkg/sentry/fsimpl/signalfd/signalfd.go @@ -131,8 +131,9 @@ func (sfd *SignalFileDescription) Readiness(mask waiter.EventMask) waiter.EventM } // EventRegister implements waiter.Waitable.EventRegister. -func (sfd *SignalFileDescription) EventRegister(e *waiter.Entry) { +func (sfd *SignalFileDescription) EventRegister(e *waiter.Entry) error { sfd.queue.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/fsimpl/timerfd/timerfd.go b/pkg/sentry/fsimpl/timerfd/timerfd.go index 1f07419bf..467c76596 100644 --- a/pkg/sentry/fsimpl/timerfd/timerfd.go +++ b/pkg/sentry/fsimpl/timerfd/timerfd.go @@ -112,8 +112,9 @@ func (tfd *TimerFileDescription) Readiness(mask waiter.EventMask) waiter.EventMa } // EventRegister implements waiter.Waitable.EventRegister. -func (tfd *TimerFileDescription) EventRegister(e *waiter.Entry) { +func (tfd *TimerFileDescription) EventRegister(e *waiter.Entry) error { tfd.events.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/kernel/epoll/epoll.go b/pkg/sentry/kernel/epoll/epoll.go index 93accd7c9..f46acafc7 100644 --- a/pkg/sentry/kernel/epoll/epoll.go +++ b/pkg/sentry/kernel/epoll/epoll.go @@ -456,3 +456,9 @@ func (e *EventPoll) RemoveEntry(ctx context.Context, id FileIdentifier) error { return nil } + +// EventRegister implements waiter.Waitable. +func (e *EventPoll) EventRegister(entry *waiter.Entry) error { + e.Queue.EventRegister(entry) + return nil +} diff --git a/pkg/sentry/kernel/eventfd/eventfd.go b/pkg/sentry/kernel/eventfd/eventfd.go index 7bef7d41a..20e654c00 100644 --- a/pkg/sentry/kernel/eventfd/eventfd.go +++ b/pkg/sentry/kernel/eventfd/eventfd.go @@ -17,6 +17,7 @@ package eventfd import ( + "fmt" "math" "golang.org/x/sys/unix" @@ -264,14 +265,17 @@ func (e *EventOperations) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (e *EventOperations) EventRegister(entry *waiter.Entry) { +func (e *EventOperations) EventRegister(entry *waiter.Entry) error { e.wq.EventRegister(entry) e.mu.Lock() defer e.mu.Unlock() if e.hostfd >= 0 { - fdnotifier.UpdateFD(int32(e.hostfd)) + if err := fdnotifier.UpdateFD(int32(e.hostfd)); err != nil { + return err + } } + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. @@ -281,6 +285,8 @@ func (e *EventOperations) EventUnregister(entry *waiter.Entry) { e.mu.Lock() defer e.mu.Unlock() if e.hostfd >= 0 { - fdnotifier.UpdateFD(int32(e.hostfd)) + if err := fdnotifier.UpdateFD(int32(e.hostfd)); err != nil { + panic(fmt.Sprint("UpdateFD:", err)) + } } } diff --git a/pkg/sentry/kernel/fasync/fasync.go b/pkg/sentry/kernel/fasync/fasync.go index b4036cea7..d595ce077 100644 --- a/pkg/sentry/kernel/fasync/fasync.go +++ b/pkg/sentry/kernel/fasync/fasync.go @@ -145,7 +145,7 @@ func (a *FileAsync) NotifyEvent(mask waiter.EventMask) { // Register sets the file which will be monitored for IO events. // // The file must not be currently registered. -func (a *FileAsync) Register(w waiter.Waitable) { +func (a *FileAsync) Register(w waiter.Waitable) error { a.regMu.Lock() defer a.regMu.Unlock() a.mu.Lock() @@ -156,7 +156,7 @@ func (a *FileAsync) Register(w waiter.Waitable) { a.e.Init(a, waiter.ReadableEvents|waiter.WritableEvents|waiter.EventErr|waiter.EventHUp) a.registered = true a.mu.Unlock() - w.EventRegister(&a.e) + return w.EventRegister(&a.e) } // Unregister stops monitoring a file. diff --git a/pkg/sentry/kernel/mq/mq.go b/pkg/sentry/kernel/mq/mq.go index e38a7fae1..586700127 100644 --- a/pkg/sentry/kernel/mq/mq.go +++ b/pkg/sentry/kernel/mq/mq.go @@ -418,10 +418,11 @@ func (q *Queue) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements Waitable.EventRegister. -func (q *Queue) EventRegister(e *waiter.Entry) { +func (q *Queue) EventRegister(e *waiter.Entry) error { q.mu.Lock() defer q.mu.Unlock() q.queue.EventRegister(e) + return nil } // EventUnregister implements Waitable.EventUnregister. diff --git a/pkg/sentry/kernel/pipe/pipe.go b/pkg/sentry/kernel/pipe/pipe.go index 8345473f3..36712c2f9 100644 --- a/pkg/sentry/kernel/pipe/pipe.go +++ b/pkg/sentry/kernel/pipe/pipe.go @@ -444,3 +444,9 @@ func (p *Pipe) SetFifoSize(size int64) (int64, error) { p.max = size return size, nil } + +// EventRegister implements waiter.Waitable. +func (p *Pipe) EventRegister(e *waiter.Entry) error { + p.Queue.EventRegister(e) + return nil +} diff --git a/pkg/sentry/kernel/pipe/vfs.go b/pkg/sentry/kernel/pipe/vfs.go index 06325d99f..a3011bacf 100644 --- a/pkg/sentry/kernel/pipe/vfs.go +++ b/pkg/sentry/kernel/pipe/vfs.go @@ -228,8 +228,9 @@ func (fd *VFSPipeFD) Allocate(ctx context.Context, mode, offset, length uint64) } // EventRegister implements waiter.Waitable.EventRegister. -func (fd *VFSPipeFD) EventRegister(e *waiter.Entry) { +func (fd *VFSPipeFD) EventRegister(e *waiter.Entry) error { fd.pipe.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/kernel/signalfd/signalfd.go b/pkg/sentry/kernel/signalfd/signalfd.go index 0dca88579..8ff74b12d 100644 --- a/pkg/sentry/kernel/signalfd/signalfd.go +++ b/pkg/sentry/kernel/signalfd/signalfd.go @@ -134,8 +134,9 @@ func (s *SignalOperations) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (s *SignalOperations) EventRegister(e *waiter.Entry) { +func (s *SignalOperations) EventRegister(e *waiter.Entry) error { s.queue.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/kernel/time/time.go b/pkg/sentry/kernel/time/time.go index a92b4e23c..a4a0c4767 100644 --- a/pkg/sentry/kernel/time/time.go +++ b/pkg/sentry/kernel/time/time.go @@ -265,7 +265,8 @@ func (*NoClockEvents) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (*NoClockEvents) EventRegister(e *waiter.Entry) { +func (*NoClockEvents) EventRegister(e *waiter.Entry) error { + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. @@ -278,6 +279,12 @@ type ClockEventsQueue struct { waiter.Queue } +// EventRegister implements waiter.Waitable. +func (c *ClockEventsQueue) EventRegister(e *waiter.Entry) error { + c.Queue.EventRegister(e) + return nil +} + // Readiness implements waiter.Waitable.Readiness. func (*ClockEventsQueue) Readiness(mask waiter.EventMask) waiter.EventMask { return 0 @@ -474,7 +481,9 @@ func (t *Timer) init() { // race with it. t.kicker = time.NewTimer(0) t.entry, t.events = waiter.NewChannelEntry(timerTickEvents) - t.clock.EventRegister(&t.entry) + if err := t.clock.EventRegister(&t.entry); err != nil { + panic(err) + } go t.runGoroutine() // S/R-SAFE: synchronized by t.mu } diff --git a/pkg/sentry/socket/hostinet/socket.go b/pkg/sentry/socket/hostinet/socket.go index c7f9ceafe..3ac02e2c2 100644 --- a/pkg/sentry/socket/hostinet/socket.go +++ b/pkg/sentry/socket/hostinet/socket.go @@ -216,15 +216,21 @@ func (s *socketOpsCommon) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (s *socketOpsCommon) EventRegister(e *waiter.Entry) { +func (s *socketOpsCommon) EventRegister(e *waiter.Entry) error { s.queue.EventRegister(e) - _ = fdnotifier.UpdateFD(int32(s.fd)) + if err := fdnotifier.UpdateFD(int32(s.fd)); err != nil { + s.queue.EventUnregister(e) + return err + } + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. func (s *socketOpsCommon) EventUnregister(e *waiter.Entry) { s.queue.EventUnregister(e) - _ = fdnotifier.UpdateFD(int32(s.fd)) + if err := fdnotifier.UpdateFD(int32(s.fd)); err != nil { + panic(err) + } } // Connect implements socket.Socket.Connect. diff --git a/pkg/sentry/socket/hostinet/socket_vfs2.go b/pkg/sentry/socket/hostinet/socket_vfs2.go index 7eeb17f71..5bea70106 100644 --- a/pkg/sentry/socket/hostinet/socket_vfs2.go +++ b/pkg/sentry/socket/hostinet/socket_vfs2.go @@ -89,8 +89,8 @@ func (s *socketVFS2) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (s *socketVFS2) EventRegister(e *waiter.Entry) { - s.socketOpsCommon.EventRegister(e) +func (s *socketVFS2) EventRegister(e *waiter.Entry) error { + return s.socketOpsCommon.EventRegister(e) } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/socket/netlink/socket.go b/pkg/sentry/socket/netlink/socket.go index a2c1f7284..955881cf4 100644 --- a/pkg/sentry/socket/netlink/socket.go +++ b/pkg/sentry/socket/netlink/socket.go @@ -187,8 +187,8 @@ func (s *socketOpsCommon) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (s *socketOpsCommon) EventRegister(e *waiter.Entry) { - s.ep.EventRegister(e) +func (s *socketOpsCommon) EventRegister(e *waiter.Entry) error { + return s.ep.EventRegister(e) // Writable readiness never changes, so no registration is needed. } @@ -543,7 +543,9 @@ func (s *socketOpsCommon) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags // We'll have to block. Register for notification and keep trying to // receive all the data. e, ch := waiter.NewChannelEntry(waiter.ReadableEvents) - s.EventRegister(&e) + if err := s.EventRegister(&e); err != nil { + return 0, 0, from, fromLen, socket.ControlMessages{}, syserr.FromError(err) + } defer s.EventUnregister(&e) for { diff --git a/pkg/sentry/socket/netlink/socket_vfs2.go b/pkg/sentry/socket/netlink/socket_vfs2.go index 216b51550..0de568e5a 100644 --- a/pkg/sentry/socket/netlink/socket_vfs2.go +++ b/pkg/sentry/socket/netlink/socket_vfs2.go @@ -96,8 +96,8 @@ func (s *SocketVFS2) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (s *SocketVFS2) EventRegister(e *waiter.Entry) { - s.socketOpsCommon.EventRegister(e) +func (s *SocketVFS2) EventRegister(e *waiter.Entry) error { + return s.socketOpsCommon.EventRegister(e) } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go index 30c81c27a..1dc1f5d08 100644 --- a/pkg/sentry/socket/netstack/netstack.go +++ b/pkg/sentry/socket/netstack/netstack.go @@ -3393,4 +3393,10 @@ func (s *socketOpsCommon) Type() (family int, skType linux.SockType, protocol in return s.family, s.skType, s.protocol } +// EventRegister implements waiter.Waitable. +func (s *socketOpsCommon) EventRegister(e *waiter.Entry) error { + s.Queue.EventRegister(e) + return nil +} + // LINT.ThenChange(./netstack_vfs2.go) diff --git a/pkg/sentry/socket/netstack/netstack_vfs2.go b/pkg/sentry/socket/netstack/netstack_vfs2.go index f35f52d9c..145951145 100644 --- a/pkg/sentry/socket/netstack/netstack_vfs2.go +++ b/pkg/sentry/socket/netstack/netstack_vfs2.go @@ -90,8 +90,9 @@ func (s *SocketVFS2) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (s *SocketVFS2) EventRegister(e *waiter.Entry) { +func (s *SocketVFS2) EventRegister(e *waiter.Entry) error { s.socketOpsCommon.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/socket/unix/transport/host.go b/pkg/sentry/socket/unix/transport/host.go index df078da46..4bd2c5671 100644 --- a/pkg/sentry/socket/unix/transport/host.go +++ b/pkg/sentry/socket/unix/transport/host.go @@ -217,12 +217,15 @@ func (c *HostConnectedEndpoint) GetLocalAddress() (tcpip.FullAddress, tcpip.Erro } // EventUpdate implements ConnectedEndpoint.EventUpdate. -func (c *HostConnectedEndpoint) EventUpdate() { +func (c *HostConnectedEndpoint) EventUpdate() error { c.mu.RLock() defer c.mu.RUnlock() if c.fd != -1 { - fdnotifier.UpdateFD(int32(c.fd)) + if err := fdnotifier.UpdateFD(int32(c.fd)); err != nil { + return err + } } + return nil } // Recv implements Receiver.Recv. diff --git a/pkg/sentry/socket/unix/transport/unix.go b/pkg/sentry/socket/unix/transport/unix.go index ae30d02d5..7eae48628 100644 --- a/pkg/sentry/socket/unix/transport/unix.go +++ b/pkg/sentry/socket/unix/transport/unix.go @@ -617,7 +617,7 @@ type ConnectedEndpoint interface { // EventUpdate lets the ConnectedEndpoint know that event registrations // have changed. - EventUpdate() + EventUpdate() error // SendQueuedSize returns the total amount of data currently queued for // sending. SendQueuedSize should return -1 if the operation isn't @@ -712,7 +712,9 @@ func (e *connectedEndpoint) Writable() bool { } // EventUpdate implements ConnectedEndpoint.EventUpdate. -func (*connectedEndpoint) EventUpdate() {} +func (*connectedEndpoint) EventUpdate() error { + return nil +} // SendQueuedSize implements ConnectedEndpoint.SendQueuedSize. func (e *connectedEndpoint) SendQueuedSize() int64 { @@ -774,14 +776,17 @@ type baseEndpoint struct { } // EventRegister implements waiter.Waitable.EventRegister. -func (e *baseEndpoint) EventRegister(we *waiter.Entry) { +func (e *baseEndpoint) EventRegister(we *waiter.Entry) error { e.Queue.EventRegister(we) e.Lock() c := e.connected e.Unlock() if c != nil { - c.EventUpdate() + if err := c.EventUpdate(); err != nil { + return err + } } + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/socket/unix/unix.go b/pkg/sentry/socket/unix/unix.go index 9db9976c4..ba6038373 100644 --- a/pkg/sentry/socket/unix/unix.go +++ b/pkg/sentry/socket/unix/unix.go @@ -544,8 +544,8 @@ func (s *socketOpsCommon) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (s *socketOpsCommon) EventRegister(e *waiter.Entry) { - s.ep.EventRegister(e) +func (s *socketOpsCommon) EventRegister(e *waiter.Entry) error { + return s.ep.EventRegister(e) } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/socket/unix/unix_vfs2.go b/pkg/sentry/socket/unix/unix_vfs2.go index e48776f59..fd1194bc1 100644 --- a/pkg/sentry/socket/unix/unix_vfs2.go +++ b/pkg/sentry/socket/unix/unix_vfs2.go @@ -315,8 +315,8 @@ func (s *SocketVFS2) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (s *SocketVFS2) EventRegister(e *waiter.Entry) { - s.socketOpsCommon.EventRegister(e) +func (s *SocketVFS2) EventRegister(e *waiter.Entry) error { + return s.socketOpsCommon.EventRegister(e) } // EventUnregister implements waiter.Waitable.EventUnregister. diff --git a/pkg/sentry/syscalls/linux/sys_file.go b/pkg/sentry/syscalls/linux/sys_file.go index 6b283dbaf..7e6aab3e8 100644 --- a/pkg/sentry/syscalls/linux/sys_file.go +++ b/pkg/sentry/syscalls/linux/sys_file.go @@ -649,7 +649,11 @@ func Ioctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall return 0, nil, nil case linux.FIOGETOWN, linux.SIOCGPGRP: - _, err := primitive.CopyInt32Out(t, args[2].Pointer(), fGetOwn(t, file)) + owner, err := fGetOwn(t, file) + if err != nil { + return 0, nil, err + } + _, err = primitive.CopyInt32Out(t, args[2].Pointer(), owner) return 0, nil, err default: @@ -860,10 +864,13 @@ func Dup3(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallC return uintptr(newfd), nil, nil } -func fGetOwnEx(t *kernel.Task, file *fs.File) linux.FOwnerEx { - ma := file.Async(nil) +func fGetOwnEx(t *kernel.Task, file *fs.File) (linux.FOwnerEx, error) { + ma, err := file.Async(nil) + if err != nil { + return linux.FOwnerEx{}, err + } if ma == nil { - return linux.FOwnerEx{} + return linux.FOwnerEx{}, nil } a := ma.(*fasync.FileAsync) ot, otg, opg := a.Owner() @@ -872,28 +879,31 @@ func fGetOwnEx(t *kernel.Task, file *fs.File) linux.FOwnerEx { return linux.FOwnerEx{ Type: linux.F_OWNER_TID, PID: int32(t.PIDNamespace().IDOfTask(ot)), - } + }, nil case otg != nil: return linux.FOwnerEx{ Type: linux.F_OWNER_PID, PID: int32(t.PIDNamespace().IDOfThreadGroup(otg)), - } + }, nil case opg != nil: return linux.FOwnerEx{ Type: linux.F_OWNER_PGRP, PID: int32(t.PIDNamespace().IDOfProcessGroup(opg)), - } + }, nil default: - return linux.FOwnerEx{} + return linux.FOwnerEx{}, nil } } -func fGetOwn(t *kernel.Task, file *fs.File) int32 { - owner := fGetOwnEx(t, file) - if owner.Type == linux.F_OWNER_PGRP { - return -owner.PID +func fGetOwn(t *kernel.Task, file *fs.File) (int32, error) { + owner, err := fGetOwnEx(t, file) + if err != nil { + return 0, err } - return owner.PID + if owner.Type == linux.F_OWNER_PGRP { + return -owner.PID, nil + } + return owner.PID, nil } // fSetOwn sets the file's owner with the semantics of F_SETOWN in Linux. @@ -901,17 +911,21 @@ func fGetOwn(t *kernel.Task, file *fs.File) int32 { // If who is positive, it represents a PID. If negative, it represents a PGID. // If the PID or PGID is invalid, the owner is silently unset. func fSetOwn(t *kernel.Task, fd int, file *fs.File, who int32) error { - a := file.Async(fasync.New(fd)).(*fasync.FileAsync) + a, err := file.Async(fasync.New(fd)) + if err != nil { + return err + } + async := a.(*fasync.FileAsync) if who < 0 { // Check for overflow before flipping the sign. if who-1 > who { return linuxerr.EINVAL } pg := t.PIDNamespace().ProcessGroupWithID(kernel.ProcessGroupID(-who)) - a.SetOwnerProcessGroup(t, pg) + async.SetOwnerProcessGroup(t, pg) } else { tg := t.PIDNamespace().ThreadGroupWithID(kernel.ThreadID(who)) - a.SetOwnerThreadGroup(t, tg) + async.SetOwnerThreadGroup(t, tg) } return nil } @@ -1046,13 +1060,20 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall return 0, nil, linuxerr.EINVAL } case linux.F_GETOWN: - return uintptr(fGetOwn(t, file)), nil, nil + owner, err := fGetOwn(t, file) + if err != nil { + return 0, nil, err + } + return uintptr(owner), nil, nil case linux.F_SETOWN: return 0, nil, fSetOwn(t, int(fd), file, args[2].Int()) case linux.F_GETOWN_EX: addr := args[2].Pointer() - owner := fGetOwnEx(t, file) - _, err := owner.CopyOut(t, addr) + owner, err := fGetOwnEx(t, file) + if err != nil { + return 0, nil, err + } + _, err = owner.CopyOut(t, addr) return 0, nil, err case linux.F_SETOWN_EX: addr := args[2].Pointer() @@ -1061,28 +1082,32 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall if err != nil { return 0, nil, err } - a := file.Async(fasync.New(int(fd))).(*fasync.FileAsync) + a, err := file.Async(fasync.New(int(fd))) + if err != nil { + return 0, nil, err + } + async := a.(*fasync.FileAsync) switch owner.Type { case linux.F_OWNER_TID: task := t.PIDNamespace().TaskWithID(kernel.ThreadID(owner.PID)) if task == nil { return 0, nil, linuxerr.ESRCH } - a.SetOwnerTask(t, task) + async.SetOwnerTask(t, task) return 0, nil, nil case linux.F_OWNER_PID: tg := t.PIDNamespace().ThreadGroupWithID(kernel.ThreadID(owner.PID)) if tg == nil { return 0, nil, linuxerr.ESRCH } - a.SetOwnerThreadGroup(t, tg) + async.SetOwnerThreadGroup(t, tg) return 0, nil, nil case linux.F_OWNER_PGRP: pg := t.PIDNamespace().ProcessGroupWithID(kernel.ProcessGroupID(owner.PID)) if pg == nil { return 0, nil, linuxerr.ESRCH } - a.SetOwnerProcessGroup(t, pg) + async.SetOwnerProcessGroup(t, pg) return 0, nil, nil default: return 0, nil, linuxerr.EINVAL @@ -1111,11 +1136,19 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall n, err := sz.SetFifoSize(int64(args[2].Int())) return uintptr(n), nil, err case linux.F_GETSIG: - a := file.Async(fasync.New(int(fd))).(*fasync.FileAsync) - return uintptr(a.Signal()), nil, nil + a, err := file.Async(fasync.New(int(fd))) + if err != nil { + return 0, nil, err + } + async := a.(*fasync.FileAsync) + return uintptr(async.Signal()), nil, nil case linux.F_SETSIG: - a := file.Async(fasync.New(int(fd))).(*fasync.FileAsync) - return 0, nil, a.SetSignal(linux.Signal(args[2].Int())) + a, err := file.Async(fasync.New(int(fd))) + if err != nil { + return 0, nil, err + } + async := a.(*fasync.FileAsync) + return 0, nil, async.SetSignal(linux.Signal(args[2].Int())) default: // Everything else is not yet supported. return 0, nil, linuxerr.EINVAL diff --git a/pkg/sentry/syscalls/linux/vfs2/epoll.go b/pkg/sentry/syscalls/linux/vfs2/epoll.go index 9a78a543b..938af4603 100644 --- a/pkg/sentry/syscalls/linux/vfs2/epoll.go +++ b/pkg/sentry/syscalls/linux/vfs2/epoll.go @@ -164,7 +164,9 @@ func waitEpoll(t *kernel.Task, epfd int32, eventsAddr hostarch.Addr, maxEvents i if ch == nil { var w waiter.Entry w, ch = waiter.NewChannelEntry(waiter.ReadableEvents) - epfile.EventRegister(&w) + if err := epfile.EventRegister(&w); err != nil { + return 0, nil, err + } defer epfile.EventUnregister(&w) } else { // Set up the timer if a timeout was specified. diff --git a/pkg/sentry/syscalls/linux/vfs2/fd.go b/pkg/sentry/syscalls/linux/vfs2/fd.go index 2198aa065..7ef93253e 100644 --- a/pkg/sentry/syscalls/linux/vfs2/fd.go +++ b/pkg/sentry/syscalls/linux/vfs2/fd.go @@ -228,8 +228,12 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall } return uintptr(a.(*fasync.FileAsync).Signal()), nil, nil case linux.F_SETSIG: - a := file.SetAsyncHandler(fasync.NewVFS2(int(fd))).(*fasync.FileAsync) - return 0, nil, a.SetSignal(linux.Signal(args[2].Int())) + a, err := file.SetAsyncHandler(fasync.NewVFS2(int(fd))) + if err != nil { + return 0, nil, err + } + async := a.(*fasync.FileAsync) + return 0, nil, async.SetSignal(linux.Signal(args[2].Int())) default: // Everything else is not yet supported. return 0, nil, linuxerr.EINVAL @@ -272,9 +276,13 @@ func setAsyncOwner(t *kernel.Task, fd int, file *vfs.FileDescription, ownerType, return linuxerr.EINVAL } - a := file.SetAsyncHandler(fasync.NewVFS2(fd)).(*fasync.FileAsync) + a, err := file.SetAsyncHandler(fasync.NewVFS2(fd)) + if err != nil { + return err + } + async := a.(*fasync.FileAsync) if pid == 0 { - a.ClearOwner() + async.ClearOwner() return nil } @@ -284,21 +292,21 @@ func setAsyncOwner(t *kernel.Task, fd int, file *vfs.FileDescription, ownerType, if task == nil { return linuxerr.ESRCH } - a.SetOwnerTask(t, task) + async.SetOwnerTask(t, task) return nil case linux.F_OWNER_PID: tg := t.PIDNamespace().ThreadGroupWithID(kernel.ThreadID(pid)) if tg == nil { return linuxerr.ESRCH } - a.SetOwnerThreadGroup(t, tg) + async.SetOwnerThreadGroup(t, tg) return nil case linux.F_OWNER_PGRP: pg := t.PIDNamespace().ProcessGroupWithID(kernel.ProcessGroupID(pid)) if pg == nil { return linuxerr.ESRCH } - a.SetOwnerProcessGroup(t, pg) + async.SetOwnerProcessGroup(t, pg) return nil default: return linuxerr.EINVAL diff --git a/pkg/sentry/syscalls/linux/vfs2/poll.go b/pkg/sentry/syscalls/linux/vfs2/poll.go index 30559c23c..32726952c 100644 --- a/pkg/sentry/syscalls/linux/vfs2/poll.go +++ b/pkg/sentry/syscalls/linux/vfs2/poll.go @@ -60,16 +60,16 @@ type pollState struct { // stored in pfd.FD. If a channel is passed in, the waiter entry in "state" is // used to register with the file for event notifications, and a reference to // the file is stored in "state". -func initReadiness(t *kernel.Task, pfd *linux.PollFD, state *pollState, ch chan struct{}) { +func initReadiness(t *kernel.Task, pfd *linux.PollFD, state *pollState, ch chan struct{}) error { if pfd.FD < 0 { pfd.REvents = 0 - return + return nil } file := t.GetFileVFS2(pfd.FD) if file == nil { pfd.REvents = linux.POLLNVAL - return + return nil } if ch == nil { @@ -77,11 +77,14 @@ func initReadiness(t *kernel.Task, pfd *linux.PollFD, state *pollState, ch chan } else { state.file = file state.waiter.Init(waiter.ChannelNotifier(ch), waiter.EventMaskFromLinux(uint32(pfd.Events))) - file.EventRegister(&state.waiter) + if err := file.EventRegister(&state.waiter); err != nil { + return err + } } r := file.Readiness(waiter.EventMaskFromLinux(uint32(pfd.Events))) pfd.REvents = int16(r.ToLinux()) & pfd.Events + return nil } // releaseState releases all the pollState in "state". @@ -113,7 +116,9 @@ func pollBlock(t *kernel.Task, pfd []linux.PollFD, timeout time.Duration) (time. defer releaseState(t, state) n := uintptr(0) for i := range pfd { - initReadiness(t, &pfd[i], &state[i], ch) + if err := initReadiness(t, &pfd[i], &state[i], ch); err != nil { + return timeout, 0, err + } if pfd[i].REvents != 0 { n++ ch = nil diff --git a/pkg/sentry/syscalls/linux/vfs2/read_write.go b/pkg/sentry/syscalls/linux/vfs2/read_write.go index 06442b93d..5ade14a89 100644 --- a/pkg/sentry/syscalls/linux/vfs2/read_write.go +++ b/pkg/sentry/syscalls/linux/vfs2/read_write.go @@ -103,7 +103,9 @@ func read(t *kernel.Task, file *vfs.FileDescription, dst usermem.IOSequence, opt // Register for notifications. w, ch := waiter.NewChannelEntry(eventMaskRead) - file.EventRegister(&w) + if err := file.EventRegister(&w); err != nil { + return n, err + } total := n for { @@ -258,8 +260,9 @@ func pread(t *kernel.Task, file *vfs.FileDescription, dst usermem.IOSequence, of // Register for notifications. w, ch := waiter.NewChannelEntry(eventMaskRead) - file.EventRegister(&w) - + if err := file.EventRegister(&w); err != nil { + return n, err + } total := n for { // Shorten dst to reflect bytes previously read. @@ -354,7 +357,9 @@ func write(t *kernel.Task, file *vfs.FileDescription, src usermem.IOSequence, op // Register for notifications. w, ch := waiter.NewChannelEntry(eventMaskWrite) - file.EventRegister(&w) + if err := file.EventRegister(&w); err != nil { + return n, err + } total := n for { @@ -508,7 +513,9 @@ func pwrite(t *kernel.Task, file *vfs.FileDescription, src usermem.IOSequence, o // Register for notifications. w, ch := waiter.NewChannelEntry(eventMaskWrite) - file.EventRegister(&w) + if err := file.EventRegister(&w); err != nil { + return n, err + } total := n for { diff --git a/pkg/sentry/syscalls/linux/vfs2/splice.go b/pkg/sentry/syscalls/linux/vfs2/splice.go index 5ba1207be..d8580b44a 100644 --- a/pkg/sentry/syscalls/linux/vfs2/splice.go +++ b/pkg/sentry/syscalls/linux/vfs2/splice.go @@ -471,7 +471,9 @@ func (dw *dualWaiter) waitForBoth(t *kernel.Task) error { if dw.inFile.Readiness(eventMaskRead)&eventMaskRead == 0 { if dw.inCh == nil { dw.inW, dw.inCh = waiter.NewChannelEntry(eventMaskRead) - dw.inFile.EventRegister(&dw.inW) + if err := dw.inFile.EventRegister(&dw.inW); err != nil { + return err + } // We might be ready now. Try again before blocking. return nil } @@ -490,7 +492,9 @@ func (dw *dualWaiter) waitForOut(t *kernel.Task) error { // EWOULDBLOCK. See b/172075629, b/170743336. if dw.outCh == nil { dw.outW, dw.outCh = waiter.NewChannelEntry(eventMaskWrite) - dw.outFile.EventRegister(&dw.outW) + if err := dw.outFile.EventRegister(&dw.outW); err != nil { + return err + } // We might be ready to write now. Try again before blocking. return nil } diff --git a/pkg/sentry/vfs/epoll.go b/pkg/sentry/vfs/epoll.go index 95132e1f8..128e743f3 100644 --- a/pkg/sentry/vfs/epoll.go +++ b/pkg/sentry/vfs/epoll.go @@ -151,8 +151,9 @@ func (ep *EpollInstance) Readiness(mask waiter.EventMask) waiter.EventMask { } // EventRegister implements waiter.Waitable.EventRegister. -func (ep *EpollInstance) EventRegister(e *waiter.Entry) { +func (ep *EpollInstance) EventRegister(e *waiter.Entry) error { ep.q.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable.EventUnregister. @@ -205,7 +206,9 @@ func (ep *EpollInstance) AddInterest(file *FileDescription, num int32, event lin ep.interest[key] = epi wmask := waiter.EventMaskFromLinux(mask) epi.waiter.Init(epi, wmask) - file.EventRegister(&epi.waiter) + if err := file.EventRegister(&epi.waiter); err != nil { + return err + } // Check if the file is already ready. if m := file.Readiness(wmask) & wmask; m != 0 { @@ -276,7 +279,9 @@ func (ep *EpollInstance) ModifyInterest(file *FileDescription, num int32, event file.EventUnregister(&epi.waiter) wmask := waiter.EventMaskFromLinux(mask) epi.waiter.Init(epi, wmask) - file.EventRegister(&epi.waiter) + if err := file.EventRegister(&epi.waiter); err != nil { + return err + } // Check if the file is already ready with the new mask. if m := file.Readiness(wmask) & wmask; m != 0 { diff --git a/pkg/sentry/vfs/file_description.go b/pkg/sentry/vfs/file_description.go index 2a608feb8..76188b68b 100644 --- a/pkg/sentry/vfs/file_description.go +++ b/pkg/sentry/vfs/file_description.go @@ -282,7 +282,9 @@ func (fd *FileDescription) SetStatusFlags(ctx context.Context, creds *auth.Crede // Use fd.statusFlags instead of oldFlags, which may have become outdated, // to avoid double registering/unregistering. if fd.statusFlags&linux.O_ASYNC == 0 && flags&linux.O_ASYNC != 0 { - fd.asyncHandler.Register(fd) + if err := fd.asyncHandler.Register(fd); err != nil { + return err + } } else if fd.statusFlags&linux.O_ASYNC != 0 && flags&linux.O_ASYNC == 0 { fd.asyncHandler.Unregister(fd) } @@ -586,8 +588,8 @@ func (fd *FileDescription) Readiness(mask waiter.EventMask) waiter.EventMask { // EventRegister implements waiter.Waitable.EventRegister. // // It registers e for I/O readiness events in mask. -func (fd *FileDescription) EventRegister(e *waiter.Entry) { - fd.impl.EventRegister(e) +func (fd *FileDescription) EventRegister(e *waiter.Entry) error { + return fd.impl.EventRegister(e) } // EventUnregister implements waiter.Waitable.EventUnregister. @@ -883,7 +885,7 @@ func (fd *FileDescription) ComputeLockRange(ctx context.Context, start uint64, l // implemented by pkg/sentry/fasync:FileAsync, but we unfortunately need this // interface to avoid circular dependencies. type FileAsync interface { - Register(w waiter.Waitable) + Register(w waiter.Waitable) error Unregister(w waiter.Waitable) } @@ -896,16 +898,18 @@ func (fd *FileDescription) AsyncHandler() FileAsync { // SetAsyncHandler sets fd.asyncHandler if it has not been set before and // returns it. -func (fd *FileDescription) SetAsyncHandler(newHandler func() FileAsync) FileAsync { +func (fd *FileDescription) SetAsyncHandler(newHandler func() FileAsync) (FileAsync, error) { fd.flagsMu.Lock() defer fd.flagsMu.Unlock() if fd.asyncHandler == nil { fd.asyncHandler = newHandler() if fd.statusFlags&linux.O_ASYNC != 0 { - fd.asyncHandler.Register(fd) + if err := fd.asyncHandler.Register(fd); err != nil { + return nil, err + } } } - return fd.asyncHandler + return fd.asyncHandler, nil } // CopyRegularFileData copies data from srcFD to dstFD until reading from srcFD diff --git a/pkg/sentry/vfs/file_description_impl_util.go b/pkg/sentry/vfs/file_description_impl_util.go index ddb2b1658..f8b35f248 100644 --- a/pkg/sentry/vfs/file_description_impl_util.go +++ b/pkg/sentry/vfs/file_description_impl_util.go @@ -78,7 +78,8 @@ func (FileDescriptionDefaultImpl) Readiness(mask waiter.EventMask) waiter.EventM // EventRegister implements waiter.Waitable.EventRegister analogously to // file_operations::poll == NULL in Linux. -func (FileDescriptionDefaultImpl) EventRegister(e *waiter.Entry) { +func (FileDescriptionDefaultImpl) EventRegister(e *waiter.Entry) error { + return nil } // EventUnregister implements waiter.Waitable.EventUnregister analogously to diff --git a/pkg/sentry/vfs/inotify.go b/pkg/sentry/vfs/inotify.go index 42d9f819e..9b5e63317 100644 --- a/pkg/sentry/vfs/inotify.go +++ b/pkg/sentry/vfs/inotify.go @@ -157,8 +157,9 @@ func (i *Inotify) Allocate(ctx context.Context, mode, offset, length uint64) err } // EventRegister implements waiter.Waitable. -func (i *Inotify) EventRegister(e *waiter.Entry) { +func (i *Inotify) EventRegister(e *waiter.Entry) error { i.queue.EventRegister(e) + return nil } // EventUnregister implements waiter.Waitable. diff --git a/pkg/sentry/vfs/save_restore.go b/pkg/sentry/vfs/save_restore.go index d0dcad760..4720987bc 100644 --- a/pkg/sentry/vfs/save_restore.go +++ b/pkg/sentry/vfs/save_restore.go @@ -15,6 +15,7 @@ package vfs import ( + "fmt" "sync/atomic" "gvisor.dev/gvisor/pkg/abi/linux" @@ -145,6 +146,8 @@ func (fd *FileDescription) beforeSave() { // afterLoad is called by stateify. func (fd *FileDescription) afterLoad() { if fd.statusFlags&linux.O_ASYNC != 0 && fd.asyncHandler != nil { - fd.asyncHandler.Register(fd) + if err := fd.asyncHandler.Register(fd); err != nil { + panic(fmt.Sprint("asyncHandler.Register:", err)) + } } } diff --git a/pkg/waiter/waiter.go b/pkg/waiter/waiter.go index 4d6dd4ce3..df4ecd1ff 100644 --- a/pkg/waiter/waiter.go +++ b/pkg/waiter/waiter.go @@ -107,7 +107,7 @@ type Waitable interface { // EventRegister registers the given waiter entry to receive // notifications when an event occurs that makes the object ready for // at least one of the events in mask. - EventRegister(e *Entry) + EventRegister(e *Entry) error // EventUnregister unregisters a waiter entry previously registered with // EventRegister(). @@ -273,7 +273,8 @@ func (*AlwaysReady) Readiness(mask EventMask) EventMask { // EventRegister doesn't do anything because this object doesn't need to issue // notifications because its readiness never changes. -func (*AlwaysReady) EventRegister(e *Entry) { +func (*AlwaysReady) EventRegister(*Entry) error { + return nil } // EventUnregister doesn't do anything because this object doesn't need to issue