From 1679ef31ef15344eba218a5251fa1fb1438b4cb7 Mon Sep 17 00:00:00 2001 From: Fabricio Voznika Date: Fri, 21 Dec 2018 11:52:39 -0800 Subject: [PATCH] inotify notifies watchers when control events bit are set The code that matches the event being published with events watchers was wronly matching all watchers in case any of the control event bits were set. Issue #121 PiperOrigin-RevId: 226521230 Change-Id: Ie2c42bc4366faaf59fbf80a74e9297499bd93f9e --- pkg/sentry/fs/inotify_watch.go | 12 +++++++----- pkg/sentry/strace/linux64.go | 2 +- test/syscalls/linux/inotify.cc | 28 ++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/pkg/sentry/fs/inotify_watch.go b/pkg/sentry/fs/inotify_watch.go index b83544c9f..d33e7e498 100644 --- a/pkg/sentry/fs/inotify_watch.go +++ b/pkg/sentry/fs/inotify_watch.go @@ -76,15 +76,17 @@ func isRenameEvent(eventMask uint32) bool { // Notify queues a new event on this watch. func (w *Watch) Notify(name string, events uint32, cookie uint32) { - unmaskableBits := ^uint32(0) &^ linux.IN_ALL_EVENTS - effectiveMask := unmaskableBits | atomic.LoadUint32(&w.mask) - matchedEvents := effectiveMask & events - - if matchedEvents == 0 { + mask := atomic.LoadUint32(&w.mask) + if mask&events == 0 { // We weren't watching for this event. return } + // Event mask should include bits matched from the watch plus all control + // event bits. + unmaskableBits := ^uint32(0) &^ linux.IN_ALL_EVENTS + effectiveMask := unmaskableBits | mask + matchedEvents := effectiveMask & events w.owner.queueEvent(newEvent(w.wd, name, matchedEvents, cookie)) } diff --git a/pkg/sentry/strace/linux64.go b/pkg/sentry/strace/linux64.go index e8fb711a5..de2da9369 100644 --- a/pkg/sentry/strace/linux64.go +++ b/pkg/sentry/strace/linux64.go @@ -271,7 +271,7 @@ var linuxAMD64 = SyscallMap{ 251: makeSyscallInfo("ioprio_set", Hex, Hex, Hex), 252: makeSyscallInfo("ioprio_get", Hex, Hex), 253: makeSyscallInfo("inotify_init"), - 254: makeSyscallInfo("inotify_add_watch", Hex, Hex, Hex), + 254: makeSyscallInfo("inotify_add_watch", Hex, Path, Hex), 255: makeSyscallInfo("inotify_rm_watch", Hex, Hex), 256: makeSyscallInfo("migrate_pages", Hex, Hex, Hex, Hex), 257: makeSyscallInfo("openat", Hex, Path, OpenFlags, Mode), diff --git a/test/syscalls/linux/inotify.cc b/test/syscalls/linux/inotify.cc index 62fc55c72..0e361496c 100644 --- a/test/syscalls/linux/inotify.cc +++ b/test/syscalls/linux/inotify.cc @@ -1484,6 +1484,34 @@ TEST(Inotify, MaskAddMergesWithExistingEventMask) { ASSERT_THAT(events, Are({Event(IN_CLOSE_WRITE, wd)})); } +// Test that control events bits are not considered when checking event mask. +TEST(Inotify, ControlEvents) { + const TempPath dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir()); + const FileDescriptor fd = + ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK)); + + const int wd = ASSERT_NO_ERRNO_AND_VALUE( + InotifyAddWatch(fd.get(), dir.path(), IN_ACCESS)); + + // Check that events in the mask are dispatched and that control bits are + // part of the event mask. + std::vector files = + ASSERT_NO_ERRNO_AND_VALUE(ListDir(dir.path(), false)); + ASSERT_EQ(files.size(), 2); + + const std::vector events1 = + ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get())); + ASSERT_THAT(events1, Are({Event(IN_ACCESS | IN_ISDIR, wd)})); + + // Check that events not in the mask are discarded. + const FileDescriptor dir_fd = + ASSERT_NO_ERRNO_AND_VALUE(Open(dir.path(), O_RDONLY | O_DIRECTORY)); + + const std::vector events2 = + ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(fd.get())); + ASSERT_THAT(events2, Are({})); +} + } // namespace } // namespace testing } // namespace gvisor