From 064ad7200c80a45a3a19e83a8becf73689af153a Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 8 Nov 2023 23:06:11 +0100 Subject: [PATCH] fuzzing function should also return stderr --- fuzz/fuzz_targets/fuzz_common.rs | 137 ++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 47 deletions(-) diff --git a/fuzz/fuzz_targets/fuzz_common.rs b/fuzz/fuzz_targets/fuzz_common.rs index e30e24ddd..9afc2cc83 100644 --- a/fuzz/fuzz_targets/fuzz_common.rs +++ b/fuzz/fuzz_targets/fuzz_common.rs @@ -3,10 +3,11 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use libc::{close, dup, dup2, pipe, STDOUT_FILENO}; +use libc::{close, dup, dup2, pipe, STDERR_FILENO, STDOUT_FILENO}; use std::ffi::OsString; use std::io; use std::io::Write; +use std::os::fd::RawFd; use std::process::Command; use std::sync::atomic::Ordering; use std::sync::{atomic::AtomicBool, Once}; @@ -33,57 +34,90 @@ pub fn is_gnu_cmd(cmd_path: &str) -> Result<(), std::io::Error> { } } -pub fn generate_and_run_uumain(args: &[OsString], uumain_function: F) -> (String, i32) +pub fn generate_and_run_uumain(args: &[OsString], uumain_function: F) -> (String, String, i32) where F: FnOnce(std::vec::IntoIter) -> i32, { let uumain_exit_status; - // Duplicate the stdout file descriptor + // Duplicate the stdout and stderr file descriptors let original_stdout_fd = unsafe { dup(STDOUT_FILENO) }; - if original_stdout_fd == -1 { - return ("Failed to duplicate STDOUT_FILENO".to_string(), -1); + let original_stderr_fd = unsafe { dup(STDERR_FILENO) }; + if original_stdout_fd == -1 || original_stderr_fd == -1 { + return ( + "Failed to duplicate STDOUT_FILENO or STDERR_FILENO".to_string(), + "".to_string(), + -1, + ); } println!("Running test {:?}", &args[0..]); - let mut pipe_fds = [-1; 2]; + let mut pipe_stdout_fds = [-1; 2]; + let mut pipe_stderr_fds = [-1; 2]; - if unsafe { pipe(pipe_fds.as_mut_ptr()) } == -1 { - return ("Failed to create a pipe".to_string(), -1); + // Create pipes for stdout and stderr + if unsafe { pipe(pipe_stdout_fds.as_mut_ptr()) } == -1 + || unsafe { pipe(pipe_stderr_fds.as_mut_ptr()) } == -1 + { + return ("Failed to create pipes".to_string(), "".to_string(), -1); } - // Redirect stdout to the pipe - unsafe { - if dup2(pipe_fds[1], STDOUT_FILENO) == -1 { - close(pipe_fds[0]); - close(pipe_fds[1]); - return ( - "Failed to redirect STDOUT_FILENO to the pipe".to_string(), - -1, - ); + // Redirect stdout and stderr to their respective pipes + if unsafe { dup2(pipe_stdout_fds[1], STDOUT_FILENO) } == -1 + || unsafe { dup2(pipe_stderr_fds[1], STDERR_FILENO) } == -1 + { + unsafe { + close(pipe_stdout_fds[0]); + close(pipe_stdout_fds[1]); + close(pipe_stderr_fds[0]); + close(pipe_stderr_fds[1]); } + return ( + "Failed to redirect STDOUT_FILENO or STDERR_FILENO".to_string(), + "".to_string(), + -1, + ); } uumain_exit_status = uumain_function(args.to_owned().into_iter()); io::stdout().flush().unwrap(); + io::stderr().flush().unwrap(); - // Restore the original stdout - unsafe { - if dup2(original_stdout_fd, STDOUT_FILENO) == -1 { - return ( - "Failed to restore the original STDOUT_FILENO".to_string(), - -1, - ); - } - close(original_stdout_fd); + // Restore the original stdout and stderr + if unsafe { dup2(original_stdout_fd, STDOUT_FILENO) } == -1 + || unsafe { dup2(original_stderr_fd, STDERR_FILENO) } == -1 + { + return ( + "Failed to restore the original STDOUT_FILENO or STDERR_FILENO".to_string(), + "".to_string(), + -1, + ); } - unsafe { close(pipe_fds[1]) }; + unsafe { + close(original_stdout_fd); + close(original_stderr_fd); + } + unsafe { close(pipe_stdout_fds[1]) }; + unsafe { close(pipe_stderr_fds[1]) }; + let captured_stdout = read_from_fd(pipe_stdout_fds[0]).trim().to_string(); + let captured_stderr = read_from_fd(pipe_stderr_fds[0]).to_string(); + let captured_stderr = captured_stderr + .splitn(2, ':') + .nth(1) + .unwrap_or("") + .trim() + .to_string(); + + (captured_stdout, captured_stderr, uumain_exit_status) +} + +fn read_from_fd(fd: RawFd) -> String { let mut captured_output = Vec::new(); let mut read_buffer = [0; 1024]; loop { let bytes_read = unsafe { libc::read( - pipe_fds[0], + fd, read_buffer.as_mut_ptr() as *mut libc::c_void, read_buffer.len(), ) @@ -93,29 +127,30 @@ where eprintln!("Failed to read from the pipe"); break; } - if bytes_read <= 0 { + if bytes_read == 0 { break; } captured_output.extend_from_slice(&read_buffer[..bytes_read as usize]); } - unsafe { libc::close(pipe_fds[0]) }; + unsafe { libc::close(fd) }; - let my_output = String::from_utf8_lossy(&captured_output) - .to_string() - .trim() - .to_owned(); - - (my_output, uumain_exit_status) + String::from_utf8_lossy(&captured_output).into_owned() } pub fn run_gnu_cmd( cmd_path: &str, args: &[OsString], check_gnu: bool, -) -> Result<(String, i32), io::Error> { +) -> Result<(String, String, i32), (String, String, i32)> { if check_gnu { - is_gnu_cmd(cmd_path)?; // Check if it's a GNU implementation + match is_gnu_cmd(cmd_path) { + Ok(_) => {} // if the check passes, do nothing + Err(e) => { + // Convert the io::Error into the function's error type + return Err((String::new(), e.to_string(), -1)); + } + } } let mut command = Command::new(cmd_path); @@ -123,17 +158,25 @@ pub fn run_gnu_cmd( command.arg(arg); } - let output = command.output()?; + let output = match command.output() { + Ok(output) => output, + Err(e) => return Err((String::new(), e.to_string(), -1)), + }; let exit_code = output.status.code().unwrap_or(-1); + + // Here we get stdout and stderr as Strings + let stdout = String::from_utf8_lossy(&output.stdout).to_string(); + let stderr = String::from_utf8_lossy(&output.stderr).to_string(); + let stderr = stderr + .splitn(2, ':') + .nth(1) + .unwrap_or("") + .trim() + .to_string(); + if output.status.success() || !check_gnu { - Ok(( - String::from_utf8_lossy(&output.stdout).to_string(), - exit_code, - )) + Ok((stdout, stderr, exit_code)) } else { - Err(io::Error::new( - io::ErrorKind::Other, - format!("GNU command execution failed with exit code {}", exit_code), - )) + Err((stdout, stderr, exit_code)) } }