Skip to content

Commit 591e2ed

Browse files
authored
Fix SignalFd::set_mask (#2141)
In 0.27.0 it inadvertently closed the file descriptor, leaving the SignalFd object accessing a stale file descriptor. Fixes #2116
1 parent 173bde1 commit 591e2ed

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ This project adheres to [Semantic Versioning](https://semver.org/).
1212
- Fixed the function signature of `recvmmsg`, potentially causing UB
1313
([#2119](https://github.com/nix-rust/nix/issues/2119))
1414

15+
- Fix `SignalFd::set_mask`. In 0.27.0 it would actually close the file
16+
descriptor.
17+
([#2141](https://github.com/nix-rust/nix/pull/2141))
18+
1519
### Changed
1620

1721
- The following APIs now take an implementation of `AsFd` rather than a

src/sys/signalfd.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ impl SignalFd {
101101
}
102102

103103
pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> {
104-
_signalfd(Some(self.0.as_fd()), mask, SfdFlags::empty()).map(drop)
104+
self.update(mask, SfdFlags::empty())
105105
}
106106

107107
pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
@@ -119,6 +119,17 @@ impl SignalFd {
119119
Err(error) => Err(error),
120120
}
121121
}
122+
123+
fn update(&self, mask: &SigSet, flags: SfdFlags) -> Result<()> {
124+
let raw_fd = self.0.as_raw_fd();
125+
unsafe {
126+
Errno::result(libc::signalfd(
127+
raw_fd,
128+
mask.as_ref(),
129+
flags.bits(),
130+
)).map(drop)
131+
}
132+
}
122133
}
123134

124135
impl AsFd for SignalFd {

test/sys/test_signalfd.rs

+29
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,32 @@ fn test_signalfd() {
2525
let signo = Signal::try_from(res.ssi_signo as i32).unwrap();
2626
assert_eq!(signo, signal::SIGUSR1);
2727
}
28+
29+
/// Update the signal mask of an already existing signalfd.
30+
#[test]
31+
fn test_signalfd_setmask() {
32+
use nix::sys::signal::{self, raise, SigSet, Signal};
33+
use nix::sys::signalfd::SignalFd;
34+
35+
// Grab the mutex for altering signals so we don't interfere with other tests.
36+
let _m = crate::SIGNAL_MTX.lock();
37+
38+
// Block the SIGUSR1 signal from automatic processing for this thread
39+
let mut mask = SigSet::empty();
40+
41+
let mut fd = SignalFd::new(&mask).unwrap();
42+
43+
mask.add(signal::SIGUSR1);
44+
mask.thread_block().unwrap();
45+
fd.set_mask(&mask).unwrap();
46+
47+
// Send a SIGUSR1 signal to the current process. Note that this uses `raise` instead of `kill`
48+
// because `kill` with `getpid` isn't correct during multi-threaded execution like during a
49+
// cargo test session. Instead use `raise` which does the correct thing by default.
50+
raise(signal::SIGUSR1).expect("Error: raise(SIGUSR1) failed");
51+
52+
// And now catch that same signal.
53+
let res = fd.read_signal().unwrap().unwrap();
54+
let signo = Signal::try_from(res.ssi_signo as i32).unwrap();
55+
assert_eq!(signo, signal::SIGUSR1);
56+
}

0 commit comments

Comments
 (0)