From 40b54bfcd83968222794e2da4716830202ce08c5 Mon Sep 17 00:00:00 2001 From: tombl Date: Thu, 9 May 2024 01:19:26 +0800 Subject: [PATCH 1/4] fix: only close fanotify events with a valid fd --- src/sys/fanotify.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sys/fanotify.rs b/src/sys/fanotify.rs index 9ff306017d..eb695ddcff 100644 --- a/src/sys/fanotify.rs +++ b/src/sys/fanotify.rs @@ -236,6 +236,9 @@ impl FanotifyEvent { impl Drop for FanotifyEvent { fn drop(&mut self) { + if self.0.fd == libc::FAN_NOFD { + return; + } let e = close(self.0.fd); if !std::thread::panicking() && e == Err(Errno::EBADF) { panic!("Closing an invalid file descriptor!"); From c8fffe56e5f3be8dc30cefc9fca03b29616b1774 Mon Sep 17 00:00:00 2001 From: tombl Date: Sun, 12 May 2024 21:26:54 +0800 Subject: [PATCH 2/4] add changelog entry --- changelog/2399.fixed.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/2399.fixed.md diff --git a/changelog/2399.fixed.md b/changelog/2399.fixed.md new file mode 100644 index 0000000000..e6e0fe044a --- /dev/null +++ b/changelog/2399.fixed.md @@ -0,0 +1 @@ +No longer panics when the `fanotify` queue overflows. From c9c66e98dcac3ef99f8556884c8d101ec2e263fc Mon Sep 17 00:00:00 2001 From: tombl Date: Sun, 19 May 2024 16:39:14 +0800 Subject: [PATCH 3/4] add a test --- test/sys/test_fanotify.rs | 73 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/test/sys/test_fanotify.rs b/test/sys/test_fanotify.rs index 20226c272a..61737f9963 100644 --- a/test/sys/test_fanotify.rs +++ b/test/sys/test_fanotify.rs @@ -1,9 +1,10 @@ use crate::*; +use nix::errno::Errno; use nix::sys::fanotify::{ EventFFlags, Fanotify, FanotifyResponse, InitFlags, MarkFlags, MaskFlags, Response, }; -use std::fs::{read_link, File, OpenOptions}; +use std::fs::{read_link, read_to_string, File, OpenOptions}; use std::io::ErrorKind; use std::io::{Read, Write}; use std::os::fd::AsRawFd; @@ -16,6 +17,7 @@ pub fn test_fanotify() { test_fanotify_notifications(); test_fanotify_responses(); + test_fanotify_overflow(); } fn test_fanotify_notifications() { @@ -147,3 +149,72 @@ fn test_fanotify_responses() { file_thread.join().unwrap(); } + +fn test_fanotify_overflow() { + let max_events: usize = + read_to_string("/proc/sys/fs/fanotify/max_queued_events") + .unwrap() + .trim() + .parse() + .unwrap(); + + // make sure the kernel is configured with the default value, + // just so this test doesn't run forever + assert_eq!(max_events, 16384); + + let group = Fanotify::init( + InitFlags::FAN_CLASS_NOTIF + | InitFlags::FAN_REPORT_TID + | InitFlags::FAN_NONBLOCK, + EventFFlags::O_RDONLY, + ) + .unwrap(); + let tempdir = tempfile::tempdir().unwrap(); + let tempfile = tempdir.path().join("test"); + + OpenOptions::new() + .write(true) + .create_new(true) + .open(&tempfile) + .unwrap(); + + group + .mark( + MarkFlags::FAN_MARK_ADD, + MaskFlags::FAN_OPEN, + None, + Some(&tempfile), + ) + .unwrap(); + + // perform 10 more events to demonstrate some will be dropped + for _ in 0..(max_events + 10) { + let tempfile = tempfile.clone(); + thread::spawn(move || { + File::open(&tempfile).unwrap(); + }) + .join() + .unwrap(); + } + + // flush the queue until it's empty + let mut n = 0; + let mut last_event = None; + loop { + match group.read_events() { + Ok(events) => { + n += events.len(); + if let Some(event) = events.last() { + last_event = Some(event.mask()); + } + } + Err(e) if e == Errno::EWOULDBLOCK => break, + Err(e) => panic!("{e:?}"), + } + } + + // make sure we read all we expected. + // the +1 is for the overflow event. + assert_eq!(n, max_events + 1); + assert_eq!(last_event, Some(MaskFlags::FAN_Q_OVERFLOW)); +} From 7512b223ec91de8a8234f57a6c93c33cf8893e66 Mon Sep 17 00:00:00 2001 From: tombl Date: Sun, 19 May 2024 16:47:41 +0800 Subject: [PATCH 4/4] make the test pass clippy --- test/sys/test_fanotify.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/test/sys/test_fanotify.rs b/test/sys/test_fanotify.rs index 61737f9963..13ec945913 100644 --- a/test/sys/test_fanotify.rs +++ b/test/sys/test_fanotify.rs @@ -187,15 +187,14 @@ fn test_fanotify_overflow() { ) .unwrap(); - // perform 10 more events to demonstrate some will be dropped - for _ in 0..(max_events + 10) { - let tempfile = tempfile.clone(); - thread::spawn(move || { - File::open(&tempfile).unwrap(); - }) - .join() - .unwrap(); - } + thread::scope(|s| { + // perform 10 more events to demonstrate some will be dropped + for _ in 0..(max_events + 10) { + s.spawn(|| { + File::open(&tempfile).unwrap(); + }); + } + }); // flush the queue until it's empty let mut n = 0;