From 52321c7e000382ce767ed920debb93f9aabf448b Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Tue, 5 Mar 2024 07:44:21 -0800 Subject: [PATCH] kernel/pipe: trigger EPOLLERR on a write end if all readers has been closed Fixes #10066 PiperOrigin-RevId: 612838688 --- pkg/sentry/kernel/pipe/vfs.go | 3 +++ test/syscalls/linux/epoll.cc | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/pkg/sentry/kernel/pipe/vfs.go b/pkg/sentry/kernel/pipe/vfs.go index b4efd6ee1..0ada567ea 100644 --- a/pkg/sentry/kernel/pipe/vfs.go +++ b/pkg/sentry/kernel/pipe/vfs.go @@ -178,6 +178,9 @@ func (fd *VFSPipeFD) Release(context.Context) { if fd.vfsfd.IsReadable() { fd.pipe.rClose() event |= waiter.WritableEvents + if !fd.pipe.HasReaders() { + event |= waiter.EventErr + } } if fd.vfsfd.IsWritable() { fd.pipe.wClose() diff --git a/test/syscalls/linux/epoll.cc b/test/syscalls/linux/epoll.cc index 3b2168dab..9a4c0ed29 100644 --- a/test/syscalls/linux/epoll.cc +++ b/test/syscalls/linux/epoll.cc @@ -594,6 +594,29 @@ TEST(EpollTest, PipeReaderHupAfterWriterClosed) { EXPECT_EQ(result[0].data.u64, kMagicConstant); } +TEST(EpollTest, PipeWriterErrAfterReaderClosed) { + auto epollfd = ASSERT_NO_ERRNO_AND_VALUE(NewEpollFD()); + int pipefds[2]; + ASSERT_THAT(pipe(pipefds), SyscallSucceeds()); + FileDescriptor rfd(pipefds[0]); + FileDescriptor wfd(pipefds[1]); + + ASSERT_NO_ERRNO( + RegisterEpollFD(epollfd.get(), wfd.get(), EPOLLERR, kMagicConstant)); + struct epoll_event result[kFDsPerEpoll]; + // Initially, wfd should not generate any events of interest. + ASSERT_THAT(epoll_wait(epollfd.get(), result, kFDsPerEpoll, 0), + SyscallSucceedsWithValue(0)); + // Close the read end of the pipe. + rfd.reset(); + // wfd should now generate EPOLLERR, which EPOLL_CTL_ADD unconditionally adds + // to the set of events of interest. + ASSERT_THAT(epoll_wait(epollfd.get(), result, kFDsPerEpoll, 0), + SyscallSucceedsWithValue(1)); + EXPECT_EQ(result[0].events, EPOLLERR); + EXPECT_EQ(result[0].data.u64, kMagicConstant); +} + TEST(EpollTest, DoubleLayerEpoll) { int pipefds[2]; ASSERT_THAT(pipe2(pipefds, O_NONBLOCK), SyscallSucceeds());