Skip to content

Commit 3429165

Browse files
Merge #1575
1575: Fix unsoundness in FdSet methods r=asomers a=taylordotfish Ensure file descriptors are nonnegative and less than `FD_SETSIZE`. (Fixes #1572.) Co-authored-by: taylor.fish <[email protected]>
2 parents 103b29f + dc80b4c commit 3429165

File tree

3 files changed

+52
-0
lines changed

3 files changed

+52
-0
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@
33
All notable changes to this project will be documented in this file.
44
This project adheres to [Semantic Versioning](https://semver.org/).
55

6+
## [Unreleased] - ReleaseDate
7+
8+
### Added
9+
### Changed
10+
### Fixed
11+
12+
- Fixed soundness issues in `FdSet::insert`, `FdSet::remove`, and
13+
`FdSet::contains` involving file descriptors outside of the range
14+
`0..FD_SETSIZE`.
15+
(#[1575](https://github.com/nix-rust/nix/pull/1575))
16+
17+
### Removed
18+
619
## [0.23.0] - 2021-09-28
720
### Added
821

src/sys/select.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Portably monitor a group of file descriptors for readiness.
2+
use std::convert::TryFrom;
23
use std::iter::FusedIterator;
34
use std::mem;
45
use std::ops::Range;
@@ -17,6 +18,13 @@ pub use libc::FD_SETSIZE;
1718
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1819
pub struct FdSet(libc::fd_set);
1920

21+
fn assert_fd_valid(fd: RawFd) {
22+
assert!(
23+
usize::try_from(fd).map_or(false, |fd| fd < FD_SETSIZE),
24+
"fd must be in the range 0..FD_SETSIZE",
25+
);
26+
}
27+
2028
impl FdSet {
2129
/// Create an empty `FdSet`
2230
pub fn new() -> FdSet {
@@ -29,16 +37,19 @@ impl FdSet {
2937

3038
/// Add a file descriptor to an `FdSet`
3139
pub fn insert(&mut self, fd: RawFd) {
40+
assert_fd_valid(fd);
3241
unsafe { libc::FD_SET(fd, &mut self.0) };
3342
}
3443

3544
/// Remove a file descriptor from an `FdSet`
3645
pub fn remove(&mut self, fd: RawFd) {
46+
assert_fd_valid(fd);
3747
unsafe { libc::FD_CLR(fd, &mut self.0) };
3848
}
3949

4050
/// Test an `FdSet` for the presence of a certain file descriptor.
4151
pub fn contains(&self, fd: RawFd) -> bool {
52+
assert_fd_valid(fd);
4253
unsafe { libc::FD_ISSET(fd, &self.0) }
4354
}
4455

test/sys/test_select.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,31 @@ pub fn test_pselect_nfds2() {
5252
assert!(fd_set.contains(r1));
5353
assert!(!fd_set.contains(r2));
5454
}
55+
56+
macro_rules! generate_fdset_bad_fd_tests {
57+
($fd:expr, $($method:ident),* $(,)?) => {
58+
$(
59+
#[test]
60+
#[should_panic]
61+
fn $method() {
62+
FdSet::new().$method($fd);
63+
}
64+
)*
65+
}
66+
}
67+
68+
mod test_fdset_negative_fd {
69+
use super::*;
70+
generate_fdset_bad_fd_tests!(-1, insert, remove, contains);
71+
}
72+
73+
mod test_fdset_too_large_fd {
74+
use super::*;
75+
use std::convert::TryInto;
76+
generate_fdset_bad_fd_tests!(
77+
FD_SETSIZE.try_into().unwrap(),
78+
insert,
79+
remove,
80+
contains,
81+
);
82+
}

0 commit comments

Comments
 (0)