From 0e9dfd62eed2c934940f4d5e5e7c7ee370b63b3b Mon Sep 17 00:00:00 2001 From: lazymio Date: Sat, 17 May 2025 20:45:08 +0800 Subject: [PATCH] Let`ForkserverExecutor` being `Send` (#3242) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implement `Send` for `Shm` it is safe because we take the ownership of the inner map pointer. Only potential violation is deref the underlying pointer but that’s already unsafe. Therefore, the properties of Send still hold within the safe world. * Bump 1.87 * use std::io::pipe so that they are `Send` * clippy * upgrade * Avoid phantomdata to make ForkserverExecutor !Send * Missing gates * Fix nostd * bump in Dockerfile * use dtolnay/rust-toolchain@stable instead * setup latest toolchain on non Linux * Fix typo --- .github/workflows/build_and_test.yml | 4 +- Dockerfile | 2 +- libafl/Cargo.toml | 2 +- libafl/src/executors/forkserver.rs | 2 +- libafl_bolts/Cargo.toml | 2 +- libafl_bolts/src/os/pipes.rs | 77 ++++++++++---------- libafl_bolts/src/shmem.rs | 10 +++ libafl_cc/Cargo.toml | 2 +- libafl_concolic/test/runtime_test/Cargo.toml | 2 +- libafl_derive/Cargo.toml | 2 +- libafl_libfuzzer/Cargo.toml | 2 +- libafl_qemu/librasan/Cargo.toml | 2 +- libafl_targets/Cargo.toml | 2 +- 13 files changed, 61 insertions(+), 50 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 128a28cc5c..74a090f084 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -42,6 +42,8 @@ jobs: - uses: actions/checkout@v4 - if: runner.os == 'Linux' uses: ./.github/workflows/ubuntu-prepare + - if: runner.os != 'Linux' + uses: dtolnay/rust-toolchain@stable - name: Install LLVM if: runner.os == 'MacOS' run: brew install llvm@${{env.MAIN_LLVM_VERSION}} @@ -227,8 +229,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable - uses: taiki-e/install-action@cargo-hack - - run: rustup upgrade # Note: We currently only specify minimum rust versions for the default workspace members - run: cargo hack check --rust-version -p libafl -p libafl_bolts -p libafl_derive -p libafl_cc -p libafl_targets diff --git a/Dockerfile b/Dockerfile index 01660f9272..51b46efbd5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1.2 -FROM rust:1.85.0 AS libafl +FROM rust:1.87.0 AS libafl LABEL "maintainer"="afl++ team " LABEL "about"="LibAFL Docker image" diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index b2c6d31709..b5cf030596 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -12,7 +12,7 @@ readme = "../../README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing", "testing", "security"] edition = "2024" -rust-version = "1.85" +rust-version = "1.87" categories = [ "development-tools::testing", "emulators", diff --git a/libafl/src/executors/forkserver.rs b/libafl/src/executors/forkserver.rs index 4302f8531b..0a82553223 100644 --- a/libafl/src/executors/forkserver.rs +++ b/libafl/src/executors/forkserver.rs @@ -671,7 +671,7 @@ pub struct ForkserverExecutor { forkserver: Forkserver, observers: OT, map: Option, - phantom: PhantomData<(I, S)>, + phantom: PhantomData (I, S)>, // For Send/Sync map_size: Option, min_input_size: usize, max_input_size: usize, diff --git a/libafl_bolts/Cargo.toml b/libafl_bolts/Cargo.toml index 2cb2c6d3f1..f09ae148b5 100644 --- a/libafl_bolts/Cargo.toml +++ b/libafl_bolts/Cargo.toml @@ -12,7 +12,7 @@ readme = "./README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing", "testing", "security"] edition = "2024" -rust-version = "1.85" +rust-version = "1.87" categories = [ "development-tools::testing", "emulators", diff --git a/libafl_bolts/src/os/pipes.rs b/libafl_bolts/src/os/pipes.rs index 1541623a3f..3d5d7c33b1 100644 --- a/libafl_bolts/src/os/pipes.rs +++ b/libafl_bolts/src/os/pipes.rs @@ -1,41 +1,55 @@ //! Unix `pipe` wrapper for `LibAFL` #[cfg(feature = "std")] -use alloc::rc::Rc; -#[cfg(feature = "std")] -use core::{borrow::Borrow, cell::RefCell}; -#[cfg(feature = "std")] use std::{ - io::{self, ErrorKind, Read, Write}, - os::{ - fd::{AsFd, AsRawFd, OwnedFd}, - unix::io::RawFd, - }, + io::{self, ErrorKind, PipeReader, PipeWriter, Read, Write}, + os::unix::io::RawFd, }; -#[cfg(feature = "std")] -use nix::unistd::{pipe, read, write}; - #[cfg(feature = "std")] use crate::Error; /// A unix pipe wrapper for `LibAFL` #[cfg(feature = "std")] -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Pipe { /// The read end of the pipe - read_end: Option>>, + read_end: Option, /// The write end of the pipe - write_end: Option>>, + write_end: Option, +} + +#[cfg(feature = "std")] +impl Clone for Pipe { + fn clone(&self) -> Self { + // try_clone only fails if we run out of fds (dup2) so this should be rather safe + let read_end = self + .read_end + .as_ref() + .map(PipeReader::try_clone) + .transpose() + .expect("fail to clone read_end"); + let write_end = self + .write_end + .as_ref() + .map(PipeWriter::try_clone) + .transpose() + .expect("fail to clone read_end"); + + Self { + read_end, + write_end, + } + } } #[cfg(feature = "std")] impl Pipe { /// Create a new `Unix` pipe pub fn new() -> Result { - let (read_end, write_end) = pipe()?; + let (read_end, write_end) = io::pipe()?; Ok(Self { - read_end: Some(Rc::new(RefCell::new(read_end))), - write_end: Some(Rc::new(RefCell::new(write_end))), + read_end: Some(read_end), + write_end: Some(write_end), }) } @@ -54,19 +68,13 @@ impl Pipe { /// The read end #[must_use] pub fn read_end(&self) -> Option { - self.read_end.as_ref().map(|fd| { - let borrowed: &RefCell = fd.borrow(); - borrowed.borrow().as_raw_fd() - }) + self.read_end.as_ref().map(std::os::fd::AsRawFd::as_raw_fd) } /// The write end #[must_use] pub fn write_end(&self) -> Option { - self.write_end.as_ref().map(|fd| { - let borrowed: &RefCell = fd.borrow(); - borrowed.borrow().as_raw_fd() - }) + self.write_end.as_ref().map(std::os::fd::AsRawFd::as_raw_fd) } } @@ -74,11 +82,8 @@ impl Pipe { impl Read for Pipe { /// Reads a few bytes fn read(&mut self, buf: &mut [u8]) -> Result { - match self.read_end() { - Some(read_end) => match read(read_end, buf) { - Ok(res) => Ok(res), - Err(e) => Err(io::Error::from_raw_os_error(e as i32)), - }, + match self.read_end.as_mut() { + Some(read_end) => read_end.read(buf), None => Err(io::Error::new( ErrorKind::BrokenPipe, "Read pipe end was already closed", @@ -91,14 +96,8 @@ impl Read for Pipe { impl Write for Pipe { /// Writes a few bytes fn write(&mut self, buf: &[u8]) -> Result { - match self.write_end.as_ref() { - Some(write_end) => { - let borrowed: &RefCell = write_end; - match write((*borrowed).borrow().as_fd(), buf) { - Ok(res) => Ok(res), - Err(e) => Err(io::Error::from_raw_os_error(e as i32)), - } - } + match self.write_end.as_mut() { + Some(write_end) => Ok(write_end.write(buf)?), None => Err(io::Error::new( ErrorKind::BrokenPipe, "Write pipe end was already closed", diff --git a/libafl_bolts/src/shmem.rs b/libafl_bolts/src/shmem.rs index c4e00bf8d8..4be592bfdd 100644 --- a/libafl_bolts/src/shmem.rs +++ b/libafl_bolts/src/shmem.rs @@ -715,6 +715,8 @@ pub mod unix_shmem { shm_fd: c_int, } + unsafe impl Send for MmapShMem {} + impl MmapShMem { /// Create a new [`MmapShMem`] /// @@ -1036,6 +1038,8 @@ pub mod unix_shmem { map_size: usize, } + unsafe impl Send for CommonUnixShMem {} + impl CommonUnixShMem { /// Create a new shared memory mapping, using shmget/shmat pub fn new(map_size: usize) -> Result { @@ -1189,6 +1193,8 @@ pub mod unix_shmem { map_size: usize, } + unsafe impl Send for AshmemShMem {} + #[allow(non_camel_case_types)] // expect somehow breaks here #[derive(Copy, Clone)] #[repr(C)] @@ -1409,6 +1415,8 @@ pub mod unix_shmem { map_size: usize, } + unsafe impl Send for MemfdShMem {} + impl MemfdShMem { /// Create a new shared memory mapping, using shmget/shmat pub fn new(map_size: usize) -> Result { @@ -1612,6 +1620,8 @@ pub mod win32_shmem { map_size: usize, } + unsafe impl Send for Win32ShMem {} + impl Debug for Win32ShMem { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("Win32ShMem") diff --git a/libafl_cc/Cargo.toml b/libafl_cc/Cargo.toml index a0ca8fcfbb..25323c7588 100644 --- a/libafl_cc/Cargo.toml +++ b/libafl_cc/Cargo.toml @@ -9,7 +9,7 @@ readme = "README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing", "testing", "compiler"] edition = "2024" -rust-version = "1.85" +rust-version = "1.87" categories = [ "development-tools::testing", "emulators", diff --git a/libafl_concolic/test/runtime_test/Cargo.toml b/libafl_concolic/test/runtime_test/Cargo.toml index bfddd19ace..b694482c83 100644 --- a/libafl_concolic/test/runtime_test/Cargo.toml +++ b/libafl_concolic/test/runtime_test/Cargo.toml @@ -2,7 +2,7 @@ name = "runtime_test" version.workspace = true edition = "2024" -rust-version = "1.85" +rust-version = "1.87" authors = ["Julius Hohnerlein "] description = "Runtime test of LibAFL fuzzing with symbolic execution" documentation = "https://docs.rs/libafl" diff --git a/libafl_derive/Cargo.toml b/libafl_derive/Cargo.toml index 4079aba2e4..46417c5a8a 100644 --- a/libafl_derive/Cargo.toml +++ b/libafl_derive/Cargo.toml @@ -9,7 +9,7 @@ readme = "../README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing", "testing"] edition = "2024" -rust-version = "1.85" +rust-version = "1.87" categories = [ "development-tools::testing", "emulators", diff --git a/libafl_libfuzzer/Cargo.toml b/libafl_libfuzzer/Cargo.toml index 1fc1b21818..f8462f74b0 100644 --- a/libafl_libfuzzer/Cargo.toml +++ b/libafl_libfuzzer/Cargo.toml @@ -7,7 +7,7 @@ readme = "../README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing", "testing", "security"] edition = "2024" -rust-version = "1.85" +rust-version = "1.87" categories = ["development-tools::testing"] include = [ diff --git a/libafl_qemu/librasan/Cargo.toml b/libafl_qemu/librasan/Cargo.toml index 1e251e1a27..763258c4c6 100644 --- a/libafl_qemu/librasan/Cargo.toml +++ b/libafl_qemu/librasan/Cargo.toml @@ -6,7 +6,7 @@ resolver = "2" version = "0.15.2" license = "MIT OR Apache-2.0" edition = "2024" -rust-version = "1.85" +rust-version = "1.87" [profile.dev] panic = "abort" diff --git a/libafl_targets/Cargo.toml b/libafl_targets/Cargo.toml index ed8426efb7..bbd2b9ccd6 100644 --- a/libafl_targets/Cargo.toml +++ b/libafl_targets/Cargo.toml @@ -9,7 +9,7 @@ readme = "../README.md" license = "MIT OR Apache-2.0" keywords = ["fuzzing", "testing"] edition = "2024" -rust-version = "1.85" +rust-version = "1.87" categories = [ "development-tools::testing", "emulators",