Skip to content

Commit

Permalink
Merge #1575
Browse files Browse the repository at this point in the history
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 <contact@taylor.fish>
  • Loading branch information
bors[bot] and taylordotfish committed Oct 22, 2021
2 parents 103b29f + dc80b4c commit 3429165
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 0 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased] - ReleaseDate

### Added
### Changed
### Fixed

- Fixed soundness issues in `FdSet::insert`, `FdSet::remove`, and
`FdSet::contains` involving file descriptors outside of the range
`0..FD_SETSIZE`.
(#[1575](https://github.com/nix-rust/nix/pull/1575))

### Removed

## [0.23.0] - 2021-09-28
### Added

Expand Down
11 changes: 11 additions & 0 deletions src/sys/select.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Portably monitor a group of file descriptors for readiness.
use std::convert::TryFrom;
use std::iter::FusedIterator;
use std::mem;
use std::ops::Range;
Expand All @@ -17,6 +18,13 @@ pub use libc::FD_SETSIZE;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct FdSet(libc::fd_set);

fn assert_fd_valid(fd: RawFd) {
assert!(
usize::try_from(fd).map_or(false, |fd| fd < FD_SETSIZE),
"fd must be in the range 0..FD_SETSIZE",
);
}

impl FdSet {
/// Create an empty `FdSet`
pub fn new() -> FdSet {
Expand All @@ -29,16 +37,19 @@ impl FdSet {

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

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

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

Expand Down
28 changes: 28 additions & 0 deletions test/sys/test_select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,31 @@ pub fn test_pselect_nfds2() {
assert!(fd_set.contains(r1));
assert!(!fd_set.contains(r2));
}

macro_rules! generate_fdset_bad_fd_tests {
($fd:expr, $($method:ident),* $(,)?) => {
$(
#[test]
#[should_panic]
fn $method() {
FdSet::new().$method($fd);
}
)*
}
}

mod test_fdset_negative_fd {
use super::*;
generate_fdset_bad_fd_tests!(-1, insert, remove, contains);
}

mod test_fdset_too_large_fd {
use super::*;
use std::convert::TryInto;
generate_fdset_bad_fd_tests!(
FD_SETSIZE.try_into().unwrap(),
insert,
remove,
contains,
);
}

0 comments on commit 3429165

Please sign in to comment.