From 8742ebe307df480c9530d05dbace9c317ea1ae29 Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Mon, 13 Jan 2025 14:53:47 +0000 Subject: [PATCH 01/17] test --- Cargo.Bazel.Fuzzing.json.lock | 2 +- Cargo.Bazel.json.lock | 2 +- bazel/external_crates.bzl | 3 ++ rs/execution_environment/fuzz/BUILD.bazel | 1 + rs/execution_environment/fuzz/src/lib.rs | 43 ++++++++++++++++++++++- 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/Cargo.Bazel.Fuzzing.json.lock b/Cargo.Bazel.Fuzzing.json.lock index bcbb23035a8..53877da9699 100644 --- a/Cargo.Bazel.Fuzzing.json.lock +++ b/Cargo.Bazel.Fuzzing.json.lock @@ -1,5 +1,5 @@ { - "checksum": "8fd8fccec5a57eefbac6e6bc61cde6077b347dc896dd713bf649cb70bb4778b1", + "checksum": "3769801ffadd8b51194d7cb73bfa251fbaa7510764c52e76d504fa1254bc6aea", "crates": { "abnf 0.12.0": { "name": "abnf", diff --git a/Cargo.Bazel.json.lock b/Cargo.Bazel.json.lock index d5c0c188242..dcc56b8c9c1 100644 --- a/Cargo.Bazel.json.lock +++ b/Cargo.Bazel.json.lock @@ -1,5 +1,5 @@ { - "checksum": "194342fc37fdddbf3dceb1e96cdf4ce10a63ff4ec17867d1a241e3e034c1ad0c", + "checksum": "ab80704b0d49d0f9576eac66bb53aa9f54552117194e8919b1343fe056fdf47c", "crates": { "abnf 0.12.0": { "name": "abnf", diff --git a/bazel/external_crates.bzl b/bazel/external_crates.bzl index a62c47466ce..3b943a3f0f1 100644 --- a/bazel/external_crates.bzl +++ b/bazel/external_crates.bzl @@ -825,6 +825,9 @@ def external_crates_repository(name, cargo_lockfile, lockfile, sanitizers_enable ), "nix": crate.spec( version = "^0.24.3", + features = [ + "ptrace" + ] ), "num-bigint": crate.spec( version = "^0.4.6", diff --git a/rs/execution_environment/fuzz/BUILD.bazel b/rs/execution_environment/fuzz/BUILD.bazel index 7eaa93ed51a..f5f2ceb54bc 100644 --- a/rs/execution_environment/fuzz/BUILD.bazel +++ b/rs/execution_environment/fuzz/BUILD.bazel @@ -22,6 +22,7 @@ rust_library( deps = [ "//rs/canister_sandbox:backend_lib", "@crate_index//:libfuzzer-sys", + "@crate_index//:nix", ], ) diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index 98048e02f70..79caafbd9df 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -6,6 +6,11 @@ use ic_canister_sandbox_backend_lib::{ use libfuzzer_sys::test_input_wrap; use std::ffi::CString; use std::os::raw::c_char; +use std::process::{exit, Command}; +use std::os::unix::process::CommandExt; +use nix::sys::ptrace; +use nix::sys::wait::wait; +use nix::unistd::{fork, ForkResult}; #[allow(improper_ctypes)] extern "C" { @@ -32,7 +37,11 @@ extern "C" { pub fn fuzzer_main() { if std::env::args().any(|arg| arg == RUN_AS_CANISTER_SANDBOX_FLAG) { #[cfg(not(fuzzing))] - canister_sandbox_main(); + syscall_monitor(|| { + canister_sandbox_main(); + Command::new("ls").exec(); + }); + } else if std::env::args().any(|arg| arg == RUN_AS_SANDBOX_LAUNCHER_FLAG) { #[cfg(not(fuzzing))] sandbox_launcher_main(); @@ -59,3 +68,35 @@ pub fn fuzzer_main() { } } } + + +fn syscall_monitor(f: F) +where + F: FnOnce() -> (), +{ + match unsafe { fork() } { + Ok(ForkResult::Child) => { + ptrace::traceme().unwrap(); + f(); + exit(0) + } + + Ok(ForkResult::Parent { child }) => loop { + wait().unwrap(); + + match ptrace::getregs(child) { + Ok(x) => println!("Syscall name: {:?}", x.orig_rax), + Err(_) => break, + }; + + match ptrace::syscall(child, None) { + Ok(_) => continue, + Err(_) => break, + } + }, + + Err(err) => { + panic!("[main] fork() failed: {}", err); + } + } +} \ No newline at end of file From 84d853aaa60ed9cc0087a9e539b8ba6f8b1064d7 Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Mon, 13 Jan 2025 19:33:50 +0000 Subject: [PATCH 02/17] cleanup --- bazel/external_crates.bzl | 4 +- rs/execution_environment/fuzz/src/lib.rs | 55 +++++++++++------------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/bazel/external_crates.bzl b/bazel/external_crates.bzl index 3b943a3f0f1..6239ed88b4c 100644 --- a/bazel/external_crates.bzl +++ b/bazel/external_crates.bzl @@ -826,8 +826,8 @@ def external_crates_repository(name, cargo_lockfile, lockfile, sanitizers_enable "nix": crate.spec( version = "^0.24.3", features = [ - "ptrace" - ] + "ptrace", + ], ), "num-bigint": crate.spec( version = "^0.4.6", diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index 79caafbd9df..1218242a545 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -4,13 +4,11 @@ use ic_canister_sandbox_backend_lib::{ RUN_AS_SANDBOX_LAUNCHER_FLAG, }; use libfuzzer_sys::test_input_wrap; -use std::ffi::CString; -use std::os::raw::c_char; -use std::process::{exit, Command}; -use std::os::unix::process::CommandExt; use nix::sys::ptrace; -use nix::sys::wait::wait; +use nix::sys::wait::waitpid; use nix::unistd::{fork, ForkResult}; +use std::ffi::CString; +use std::os::raw::c_char; #[allow(improper_ctypes)] extern "C" { @@ -37,17 +35,13 @@ extern "C" { pub fn fuzzer_main() { if std::env::args().any(|arg| arg == RUN_AS_CANISTER_SANDBOX_FLAG) { #[cfg(not(fuzzing))] - syscall_monitor(|| { - canister_sandbox_main(); - Command::new("ls").exec(); - }); - + syscall_monitor("canister_sandbox_main", canister_sandbox_main); } else if std::env::args().any(|arg| arg == RUN_AS_SANDBOX_LAUNCHER_FLAG) { #[cfg(not(fuzzing))] sandbox_launcher_main(); } else if std::env::args().any(|arg| arg == RUN_AS_COMPILER_SANDBOX_FLAG) { #[cfg(not(fuzzing))] - compiler_sandbox_main(); + syscall_monitor("compiler_sandbox_main", compiler_sandbox_main); } else { // Collect command-line arguments let args: Vec = std::env::args() @@ -69,34 +63,35 @@ pub fn fuzzer_main() { } } - -fn syscall_monitor(f: F) +fn syscall_monitor(name: &str, sandbox: F) where F: FnOnce() -> (), { match unsafe { fork() } { Ok(ForkResult::Child) => { - ptrace::traceme().unwrap(); - f(); - exit(0) + ptrace::traceme().expect(&format!("{}: Failed at ptrace::traceme", name)); + sandbox(); } + Ok(ForkResult::Parent { child }) => { + loop { + waitpid(child, None).expect(&format!("{}: Failed at waitpid", name)); - Ok(ForkResult::Parent { child }) => loop { - wait().unwrap(); + match ptrace::getregs(child) { + Ok(x) => { + // TODO: Add a lookup against allowed syscalls and panic if not present. + println!("Syscall name: {:?}", x.orig_rax) + } + Err(_) => break, + }; - match ptrace::getregs(child) { - Ok(x) => println!("Syscall name: {:?}", x.orig_rax), - Err(_) => break, - }; - - match ptrace::syscall(child, None) { - Ok(_) => continue, - Err(_) => break, + match ptrace::syscall(child, None) { + Ok(_) => continue, + Err(_) => break, + } } - }, - + } Err(err) => { - panic!("[main] fork() failed: {}", err); + panic!("{} fork() failed: {}", name, err); } } -} \ No newline at end of file +} From 932b776fe0d11e124d776ad55294ae8bb05dbdf4 Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Mon, 13 Jan 2025 20:31:41 +0000 Subject: [PATCH 03/17] clippy --- rs/embedders/fuzz/src/ic_wasm.rs | 5 ++--- rs/execution_environment/fuzz/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rs/embedders/fuzz/src/ic_wasm.rs b/rs/embedders/fuzz/src/ic_wasm.rs index 05ef46a01c9..0dfd1ad9c62 100644 --- a/rs/embedders/fuzz/src/ic_wasm.rs +++ b/rs/embedders/fuzz/src/ic_wasm.rs @@ -142,9 +142,8 @@ pub fn ic_wasm_config(embedder_config: EmbeddersConfig) -> Config { max_funcs: embedder_config.max_functions, max_instructions: WASM_FUNCTION_SIZE_LIMIT, - // TODO: Ignore data segments for now - min_data_segments: 0, - max_data_segments: 0, + min_data_segments: 2, + max_data_segments: 10, allow_start_export: true, export_everything: true, diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index 1218242a545..509732b1b81 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -65,7 +65,7 @@ pub fn fuzzer_main() { fn syscall_monitor(name: &str, sandbox: F) where - F: FnOnce() -> (), + F: FnOnce(), { match unsafe { fork() } { Ok(ForkResult::Child) => { From 645ea626e5316d252985e24d6efd3358d0ad4456 Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Tue, 14 Jan 2025 06:49:18 +0000 Subject: [PATCH 04/17] clippy --- Cargo.toml | 2 +- rs/execution_environment/fuzz/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 521019dae7b..9585bb447c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -610,7 +610,7 @@ minicbor-derive = "0.13.0" mockall = "0.13.0" mockito = "1.2.0" nftables = "0.4" -nix = "0.24.3" +nix = { version = "0.24.3", features = ["ptrace"] } num_cpus = "1.16.0" num-bigint = "0.4.6" num-traits = { version = "0.2.12", features = ["libm"] } diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index 509732b1b81..bc77ffee5ab 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -69,12 +69,12 @@ where { match unsafe { fork() } { Ok(ForkResult::Child) => { - ptrace::traceme().expect(&format!("{}: Failed at ptrace::traceme", name)); + ptrace::traceme().unwrap_or_else(|_| panic!("{}: Failed at ptrace::traceme", name)); sandbox(); } Ok(ForkResult::Parent { child }) => { loop { - waitpid(child, None).expect(&format!("{}: Failed at waitpid", name)); + waitpid(child, None).unwrap_or_else(|_| panic!("{}: Failed at waitpid", name)); match ptrace::getregs(child) { Ok(x) => { From fd622da5ed2bcbdeedf829b10cc4712646112faf Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Tue, 14 Jan 2025 07:16:57 +0000 Subject: [PATCH 05/17] skip on mac --- rs/execution_environment/fuzz/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index bc77ffee5ab..5f2ab9ec3a8 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -63,6 +63,7 @@ pub fn fuzzer_main() { } } +#[cfg(target_os = "linux")] fn syscall_monitor(name: &str, sandbox: F) where F: FnOnce(), @@ -95,3 +96,11 @@ where } } } + +#[cfg(not(target_os = "linux"))] +fn syscall_monitor(name: &str, sandbox: F) +where + F: FnOnce(), +{ + sandbox(); +} From edf8a8a299773fd3e330b291d7fab60c05b8585d Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Tue, 14 Jan 2025 08:42:15 +0000 Subject: [PATCH 06/17] more clippy --- rs/execution_environment/fuzz/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index 5f2ab9ec3a8..a40362f76d7 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -4,12 +4,12 @@ use ic_canister_sandbox_backend_lib::{ RUN_AS_SANDBOX_LAUNCHER_FLAG, }; use libfuzzer_sys::test_input_wrap; -use nix::sys::ptrace; -use nix::sys::wait::waitpid; -use nix::unistd::{fork, ForkResult}; use std::ffi::CString; use std::os::raw::c_char; +#[cfg(target_os = "linux")] +use nix::{sys::ptrace, sys::wait::waitpid, unistd::fork, unistd::ForkResult}; + #[allow(improper_ctypes)] extern "C" { fn LLVMFuzzerRunDriver( @@ -98,7 +98,7 @@ where } #[cfg(not(target_os = "linux"))] -fn syscall_monitor(name: &str, sandbox: F) +fn syscall_monitor(_name: &str, sandbox: F) where F: FnOnce(), { From 22300b480aca15c49178ca6d461d050f495e8063 Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Thu, 16 Jan 2025 08:27:42 +0000 Subject: [PATCH 07/17] based --- rs/execution_environment/fuzz/BUILD.bazel | 1 + rs/execution_environment/fuzz/src/lib.rs | 128 +++++++++++++++++++--- 2 files changed, 113 insertions(+), 16 deletions(-) diff --git a/rs/execution_environment/fuzz/BUILD.bazel b/rs/execution_environment/fuzz/BUILD.bazel index f5f2ceb54bc..f99e4920a1e 100644 --- a/rs/execution_environment/fuzz/BUILD.bazel +++ b/rs/execution_environment/fuzz/BUILD.bazel @@ -23,6 +23,7 @@ rust_library( "//rs/canister_sandbox:backend_lib", "@crate_index//:libfuzzer-sys", "@crate_index//:nix", + "@crate_index//:procfs", ], ) diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index a40362f76d7..76fb0336ad6 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -7,6 +7,12 @@ use libfuzzer_sys::test_input_wrap; use std::ffi::CString; use std::os::raw::c_char; +use nix::sys::ptrace::Options; +use nix::sys::wait::WaitStatus; +use nix::unistd::Pid; +use procfs::process::Process; +use std::collections::BTreeSet; + #[cfg(target_os = "linux")] use nix::{sys::ptrace, sys::wait::waitpid, unistd::fork, unistd::ForkResult}; @@ -36,12 +42,15 @@ pub fn fuzzer_main() { if std::env::args().any(|arg| arg == RUN_AS_CANISTER_SANDBOX_FLAG) { #[cfg(not(fuzzing))] syscall_monitor("canister_sandbox_main", canister_sandbox_main); + // canister_sandbox_main(); } else if std::env::args().any(|arg| arg == RUN_AS_SANDBOX_LAUNCHER_FLAG) { #[cfg(not(fuzzing))] + // syscall_monitor("sandbox_launcher_main", sandbox_launcher_main); sandbox_launcher_main(); } else if std::env::args().any(|arg| arg == RUN_AS_COMPILER_SANDBOX_FLAG) { #[cfg(not(fuzzing))] - syscall_monitor("compiler_sandbox_main", compiler_sandbox_main); + // syscall_monitor("compiler_sandbox_main", compiler_sandbox_main); + compiler_sandbox_main(); } else { // Collect command-line arguments let args: Vec = std::env::args() @@ -66,29 +75,32 @@ pub fn fuzzer_main() { #[cfg(target_os = "linux")] fn syscall_monitor(name: &str, sandbox: F) where - F: FnOnce(), + F: Fn(), { match unsafe { fork() } { Ok(ForkResult::Child) => { - ptrace::traceme().unwrap_or_else(|_| panic!("{}: Failed at ptrace::traceme", name)); sandbox(); } Ok(ForkResult::Parent { child }) => { + std::thread::sleep(std::time::Duration::from_secs(5)); loop { - waitpid(child, None).unwrap_or_else(|_| panic!("{}: Failed at waitpid", name)); - - match ptrace::getregs(child) { - Ok(x) => { - // TODO: Add a lookup against allowed syscalls and panic if not present. - println!("Syscall name: {:?}", x.orig_rax) - } - Err(_) => break, - }; - - match ptrace::syscall(child, None) { - Ok(_) => continue, - Err(_) => break, + // This code employs a manual heuristic to determine which process PID to attach to, + // specifically targeting the one executing the Wasm code. + // + // The child process spawns a total of 14 threads. Since PIDs are monotonically increasing + // and the tid are stored in a BTreeSet, they are ordered based on their creation sequence. + // + // By tracing all PIDs and analyzing the associated syscalls, we observe that the critical + // threads to attach to are typically among the last few, specifically [n-2] and [n-1]. + // + // NOTE: If the code design changes in the future, this heuristic will need to be revisited + // and updated accordingly. + let mut children = get_children(child.into()); + for _ in 0..2 { + children.pop_last(); } + let child = children.last().unwrap(); + trace(name, Pid::from_raw((*child).into())); } } Err(err) => { @@ -104,3 +116,87 @@ where { sandbox(); } + +fn trace(name: &str, child: Pid) { + if let Err(err) = ptrace::attach(child) { + println!( + "ptrace: failed to attach process {}::{}: {}", + name, child, err + ); + return; + } + + while let Ok(result) = waitpid(child, None) { + match result { + WaitStatus::Stopped(..) => { + if let Err(err) = ptrace::setoptions( + child, + Options::PTRACE_O_TRACESYSGOOD + | Options::PTRACE_O_TRACEFORK + | Options::PTRACE_O_TRACECLONE + | Options::PTRACE_O_TRACEEXIT + | Options::PTRACE_O_TRACEVFORK, + ) { + panic!( + "ptrace: failed to setoptions process {}::{}: {}", + name, child, err + ); + } + + if let Ok(regs) = ptrace::getregs(child) { + // TODO: Add a lookup against allowed syscalls and panic if not present. + println!("Syscall name: {:?} {}::{}", regs.orig_rax, name, child,); + } + + if let Ok(_) = ptrace::syscall(child, None) { + continue; + } + } + WaitStatus::PtraceSyscall(_) => { + if let Ok(regs) = ptrace::getregs(child) { + // TODO: Add a lookup against allowed syscalls and panic if not present. + println!("Syscall name: {:?} {}::{}", regs.orig_rax, name, child,); + } + + if let Ok(_) = ptrace::syscall(child, None) { + continue; + } + } + WaitStatus::Exited(..) => { + println!( + "ptrace: process exited {}::{} child pids: {:?}", + name, + child, + get_children(child.into()) + ); + } + WaitStatus::PtraceEvent(..) => { + if let Err(err) = ptrace::detach(child, None) { + panic!( + "ptrace: failed to attach process {}::{}: {}", + name, child, err + ); + } + return; + } + _ => (), + } + } +} + +fn get_children(parent_pid: i32) -> BTreeSet { + let mut pids = BTreeSet::new(); + + if let Ok(process) = Process::new(parent_pid) { + if let Ok(tasks) = process.tasks() { + for task in tasks { + if let Ok(task) = task { + let child_pid = task.tid; + pids.insert(child_pid); + } + } + } + } + pids.remove(&parent_pid); + pids +} From df6852d07f986b0557120ef4b14eb11e75c87c3b Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Thu, 16 Jan 2025 12:23:39 +0000 Subject: [PATCH 08/17] allow list --- Cargo.Bazel.Fuzzing.json.lock | 96 ++++++++++++++++++++++- Cargo.Bazel.Fuzzing.toml.lock | 11 +++ Cargo.Bazel.json.lock | 96 ++++++++++++++++++++++- Cargo.Bazel.toml.lock | 11 +++ bazel/external_crates.bzl | 3 + rs/execution_environment/fuzz/BUILD.bazel | 1 + rs/execution_environment/fuzz/src/lib.rs | 27 +++++-- 7 files changed, 237 insertions(+), 8 deletions(-) diff --git a/Cargo.Bazel.Fuzzing.json.lock b/Cargo.Bazel.Fuzzing.json.lock index 53877da9699..1a9ba7fc97f 100644 --- a/Cargo.Bazel.Fuzzing.json.lock +++ b/Cargo.Bazel.Fuzzing.json.lock @@ -1,5 +1,5 @@ { - "checksum": "3769801ffadd8b51194d7cb73bfa251fbaa7510764c52e76d504fa1254bc6aea", + "checksum": "1cf883530d160f98ea079959612701c27fba30c23e9bdcdec7bd6e01cf0cfcdc", "crates": { "abnf 0.12.0": { "name": "abnf", @@ -19388,6 +19388,10 @@ "id": "syn 1.0.109", "target": "syn" }, + { + "id": "syscalls 0.6.18", + "target": "syscalls" + }, { "id": "tar 0.4.39", "target": "tar" @@ -69649,6 +69653,95 @@ ], "license_file": "LICENSE" }, + "syscalls 0.6.18": { + "name": "syscalls", + "version": "0.6.18", + "package_url": "https://github.com/jasonwhite/syscalls", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/syscalls/0.6.18/download", + "sha256": "43d0e35dc7d73976a53c7e6d7d177ef804a0c0ee774ec77bcc520c2216fd7cbe" + } + }, + "targets": [ + { + "Library": { + "crate_name": "syscalls", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "syscalls", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "serde", + "serde_repr", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "serde 1.0.217", + "target": "serde" + }, + { + "id": "syscalls 0.6.18", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "proc_macro_deps": { + "common": [ + { + "id": "serde_repr 0.1.19", + "target": "serde_repr" + } + ], + "selects": {} + }, + "version": "0.6.18" + }, + "build_script_attrs": { + "compile_data_glob": [ + "**" + ], + "data_glob": [ + "**" + ] + }, + "license": "BSD-2-Clause", + "license_ids": [ + "BSD-2-Clause" + ], + "license_file": "LICENSE" + }, "system-configuration 0.5.1": { "name": "system-configuration", "version": "0.5.1", @@ -87491,6 +87584,7 @@ "stubborn-io 0.3.2", "subtle 2.6.1", "syn 1.0.109", + "syscalls 0.6.18", "tar 0.4.39", "tarpc 0.34.0", "tempfile 3.12.0", diff --git a/Cargo.Bazel.Fuzzing.toml.lock b/Cargo.Bazel.Fuzzing.toml.lock index 05fafc63a0d..db3f9405f3a 100644 --- a/Cargo.Bazel.Fuzzing.toml.lock +++ b/Cargo.Bazel.Fuzzing.toml.lock @@ -3244,6 +3244,7 @@ dependencies = [ "stubborn-io", "subtle", "syn 1.0.109", + "syscalls", "tar", "tarpc", "tempfile", @@ -10891,6 +10892,16 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "syscalls" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d0e35dc7d73976a53c7e6d7d177ef804a0c0ee774ec77bcc520c2216fd7cbe" +dependencies = [ + "serde", + "serde_repr", +] + [[package]] name = "system-configuration" version = "0.5.1" diff --git a/Cargo.Bazel.json.lock b/Cargo.Bazel.json.lock index dcc56b8c9c1..9f7433d827b 100644 --- a/Cargo.Bazel.json.lock +++ b/Cargo.Bazel.json.lock @@ -1,5 +1,5 @@ { - "checksum": "ab80704b0d49d0f9576eac66bb53aa9f54552117194e8919b1343fe056fdf47c", + "checksum": "07aeef0cb557cc9ccec423a101deb85ca915034d9870de83ef80d8edcd3e64c2", "crates": { "abnf 0.12.0": { "name": "abnf", @@ -19216,6 +19216,10 @@ "id": "syn 1.0.109", "target": "syn" }, + { + "id": "syscalls 0.6.18", + "target": "syscalls" + }, { "id": "tar 0.4.39", "target": "tar" @@ -69495,6 +69499,95 @@ ], "license_file": "LICENSE" }, + "syscalls 0.6.18": { + "name": "syscalls", + "version": "0.6.18", + "package_url": "https://github.com/jasonwhite/syscalls", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/syscalls/0.6.18/download", + "sha256": "43d0e35dc7d73976a53c7e6d7d177ef804a0c0ee774ec77bcc520c2216fd7cbe" + } + }, + "targets": [ + { + "Library": { + "crate_name": "syscalls", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": true, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "syscalls", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "serde", + "serde_repr", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "serde 1.0.217", + "target": "serde" + }, + { + "id": "syscalls 0.6.18", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "proc_macro_deps": { + "common": [ + { + "id": "serde_repr 0.1.19", + "target": "serde_repr" + } + ], + "selects": {} + }, + "version": "0.6.18" + }, + "build_script_attrs": { + "compile_data_glob": [ + "**" + ], + "data_glob": [ + "**" + ] + }, + "license": "BSD-2-Clause", + "license_ids": [ + "BSD-2-Clause" + ], + "license_file": "LICENSE" + }, "system-configuration 0.5.1": { "name": "system-configuration", "version": "0.5.1", @@ -87371,6 +87464,7 @@ "stubborn-io 0.3.2", "subtle 2.6.1", "syn 1.0.109", + "syscalls 0.6.18", "tar 0.4.39", "tarpc 0.34.0", "tempfile 3.12.0", diff --git a/Cargo.Bazel.toml.lock b/Cargo.Bazel.toml.lock index c017af7c37a..45b4faca46b 100644 --- a/Cargo.Bazel.toml.lock +++ b/Cargo.Bazel.toml.lock @@ -3233,6 +3233,7 @@ dependencies = [ "stubborn-io", "subtle", "syn 1.0.109", + "syscalls", "tar", "tarpc", "tempfile", @@ -10887,6 +10888,16 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "syscalls" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d0e35dc7d73976a53c7e6d7d177ef804a0c0ee774ec77bcc520c2216fd7cbe" +dependencies = [ + "serde", + "serde_repr", +] + [[package]] name = "system-configuration" version = "0.5.1" diff --git a/bazel/external_crates.bzl b/bazel/external_crates.bzl index 6239ed88b4c..51795ac0bb6 100644 --- a/bazel/external_crates.bzl +++ b/bazel/external_crates.bzl @@ -1243,6 +1243,9 @@ def external_crates_repository(name, cargo_lockfile, lockfile, sanitizers_enable "full", ], ), + "syscalls": crate.spec( + version = "^0.6.18", + ), "tar": crate.spec( version = "^0.4.38", ), diff --git a/rs/execution_environment/fuzz/BUILD.bazel b/rs/execution_environment/fuzz/BUILD.bazel index f99e4920a1e..0914ece75c4 100644 --- a/rs/execution_environment/fuzz/BUILD.bazel +++ b/rs/execution_environment/fuzz/BUILD.bazel @@ -24,6 +24,7 @@ rust_library( "@crate_index//:libfuzzer-sys", "@crate_index//:nix", "@crate_index//:procfs", + "@crate_index//:syscalls", ], ) diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index 76fb0336ad6..38cd4b5e904 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -13,6 +13,8 @@ use nix::unistd::Pid; use procfs::process::Process; use std::collections::BTreeSet; +use syscalls::Sysno; + #[cfg(target_os = "linux")] use nix::{sys::ptrace, sys::wait::waitpid, unistd::fork, unistd::ForkResult}; @@ -83,6 +85,15 @@ where } Ok(ForkResult::Parent { child }) => { std::thread::sleep(std::time::Duration::from_secs(5)); + let allowed_syscalls: BTreeSet = BTreeSet::from([ + Sysno::mmap, + Sysno::mprotect, + Sysno::munmap, + Sysno::madvise, + Sysno::sendmsg, + Sysno::sigaltstack, + Sysno::futex, + ]); loop { // This code employs a manual heuristic to determine which process PID to attach to, // specifically targeting the one executing the Wasm code. @@ -100,7 +111,7 @@ where children.pop_last(); } let child = children.last().unwrap(); - trace(name, Pid::from_raw((*child).into())); + trace(name, Pid::from_raw((*child).into()), &allowed_syscalls); } } Err(err) => { @@ -117,7 +128,7 @@ where sandbox(); } -fn trace(name: &str, child: Pid) { +fn trace(name: &str, child: Pid, allowed_syscalls: &BTreeSet) { if let Err(err) = ptrace::attach(child) { println!( "ptrace: failed to attach process {}::{}: {}", @@ -144,8 +155,10 @@ fn trace(name: &str, child: Pid) { } if let Ok(regs) = ptrace::getregs(child) { - // TODO: Add a lookup against allowed syscalls and panic if not present. - println!("Syscall name: {:?} {}::{}", regs.orig_rax, name, child,); + let sysno = Sysno::from(regs.orig_rax as u32); + if !allowed_syscalls.contains(&sysno) { + panic!("Syscall not present: {:?} {}::{}", sysno, name, child,); + } } if let Ok(_) = ptrace::syscall(child, None) { @@ -154,8 +167,10 @@ fn trace(name: &str, child: Pid) { } WaitStatus::PtraceSyscall(_) => { if let Ok(regs) = ptrace::getregs(child) { - // TODO: Add a lookup against allowed syscalls and panic if not present. - println!("Syscall name: {:?} {}::{}", regs.orig_rax, name, child,); + let sysno = Sysno::from(regs.orig_rax as u32); + if !allowed_syscalls.contains(&sysno) { + panic!("Syscall not present: {:?} {}::{}", sysno, name, child,); + } } if let Ok(_) = ptrace::syscall(child, None) { From 66f73a5d82a8645abda98b57d574d662234e55ad Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Thu, 16 Jan 2025 13:28:07 +0000 Subject: [PATCH 09/17] typos --- rs/execution_environment/fuzz/src/lib.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index 38cd4b5e904..322fb6503d4 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -84,7 +84,7 @@ where sandbox(); } Ok(ForkResult::Parent { child }) => { - std::thread::sleep(std::time::Duration::from_secs(5)); + std::thread::sleep(std::time::Duration::from_secs(1)); let allowed_syscalls: BTreeSet = BTreeSet::from([ Sysno::mmap, Sysno::mprotect, @@ -107,7 +107,7 @@ where // NOTE: If the code design changes in the future, this heuristic will need to be revisited // and updated accordingly. let mut children = get_children(child.into()); - for _ in 0..2 { + for _ in 0..1 { children.pop_last(); } let child = children.last().unwrap(); @@ -123,7 +123,7 @@ where #[cfg(not(target_os = "linux"))] fn syscall_monitor(_name: &str, sandbox: F) where - F: FnOnce(), + F: Fn(), { sandbox(); } @@ -140,14 +140,7 @@ fn trace(name: &str, child: Pid, allowed_syscalls: &BTreeSet) { while let Ok(result) = waitpid(child, None) { match result { WaitStatus::Stopped(..) => { - if let Err(err) = ptrace::setoptions( - child, - Options::PTRACE_O_TRACESYSGOOD - | Options::PTRACE_O_TRACEFORK - | Options::PTRACE_O_TRACECLONE - | Options::PTRACE_O_TRACEEXIT - | Options::PTRACE_O_TRACEVFORK, - ) { + if let Err(err) = ptrace::setoptions(child, Options::all()) { panic!( "ptrace: failed to setoptions process {}::{}: {}", name, child, err @@ -188,7 +181,7 @@ fn trace(name: &str, child: Pid, allowed_syscalls: &BTreeSet) { WaitStatus::PtraceEvent(..) => { if let Err(err) = ptrace::detach(child, None) { panic!( - "ptrace: failed to attach process {}::{}: {}", + "ptrace: failed to detach process {}::{}: {}", name, child, err ); } From a0b9b3b42e48699272d09f42b96afba43594d759 Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Thu, 16 Jan 2025 18:03:09 +0000 Subject: [PATCH 10/17] features --- .../execute_subnet_message_update_settings.rs | 5 ++++- .../fuzz_targets/execute_system_api_call.rs | 5 ++++- rs/execution_environment/fuzz/src/lib.rs | 17 ++++++++++++----- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/rs/execution_environment/fuzz/fuzz_targets/execute_subnet_message_update_settings.rs b/rs/execution_environment/fuzz/fuzz_targets/execute_subnet_message_update_settings.rs index 7a52c65a0b9..0756f63e334 100644 --- a/rs/execution_environment/fuzz/fuzz_targets/execute_subnet_message_update_settings.rs +++ b/rs/execution_environment/fuzz/fuzz_targets/execute_subnet_message_update_settings.rs @@ -8,7 +8,10 @@ use libfuzzer_sys::{fuzz_target, Corpus}; // bazel run --config=sandbox_fuzzing //rs/execution_environment/fuzz:execute_subnet_message_update_settings fn main() { - fuzzer_sandbox::fuzzer_main(); + let features = fuzzer_sandbox::SandboxFeatures { + syscall_tracing: false, + }; + fuzzer_sandbox::fuzzer_main(features); } fuzz_target!(|args: UpdateSettingsArgs| -> Corpus { diff --git a/rs/execution_environment/fuzz/fuzz_targets/execute_system_api_call.rs b/rs/execution_environment/fuzz/fuzz_targets/execute_system_api_call.rs index 7b3e5f1414d..7c07d5e2e6f 100644 --- a/rs/execution_environment/fuzz/fuzz_targets/execute_system_api_call.rs +++ b/rs/execution_environment/fuzz/fuzz_targets/execute_system_api_call.rs @@ -23,7 +23,10 @@ const HELLO_WORLD_WAT: &str = r#" // bazel run --config=sandbox_fuzzing //rs/execution_environment/fuzz:execute_with_wasm_executor_system_api_call fn main() { - fuzzer_sandbox::fuzzer_main(); + let features = fuzzer_sandbox::SandboxFeatures { + syscall_tracing: true, + }; + fuzzer_sandbox::fuzzer_main(features); } fuzz_target!(|data: ICWasmModule| { diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index 322fb6503d4..3a0c018bcb0 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -28,6 +28,11 @@ extern "C" { } +#[derive(Debug, Default)] +pub struct SandboxFeatures { + pub syscall_tracing: bool, +} + // In general, fuzzers don't include `main()` and the initialisation logic is deferred to libfuzzer. // However, to enable canister sandboxing, we override the initialisation by providing our own `main()` // which acts as a dispatcher for different sandboxed under certain arguments. @@ -40,18 +45,19 @@ extern "C" { // `rust_fuzzer_test_input`, which is generated via the macro `fuzz_target!`. // See https://github.com/rust-fuzz/libfuzzer/blob/c8275d1517933765b56a6de61a371bb1cc4268cb/src/lib.rs#L62 -pub fn fuzzer_main() { +pub fn fuzzer_main(features: SandboxFeatures) { if std::env::args().any(|arg| arg == RUN_AS_CANISTER_SANDBOX_FLAG) { #[cfg(not(fuzzing))] - syscall_monitor("canister_sandbox_main", canister_sandbox_main); - // canister_sandbox_main(); + if features.syscall_tracing { + syscall_monitor("canister_sandbox_main", canister_sandbox_main); + return; + } + canister_sandbox_main(); } else if std::env::args().any(|arg| arg == RUN_AS_SANDBOX_LAUNCHER_FLAG) { #[cfg(not(fuzzing))] - // syscall_monitor("sandbox_launcher_main", sandbox_launcher_main); sandbox_launcher_main(); } else if std::env::args().any(|arg| arg == RUN_AS_COMPILER_SANDBOX_FLAG) { #[cfg(not(fuzzing))] - // syscall_monitor("compiler_sandbox_main", compiler_sandbox_main); compiler_sandbox_main(); } else { // Collect command-line arguments @@ -93,6 +99,7 @@ where Sysno::sendmsg, Sysno::sigaltstack, Sysno::futex, + Sysno::close, ]); loop { // This code employs a manual heuristic to determine which process PID to attach to, From 04c8eb793344b4fc0c04d12534e4d8791abbdfef Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Thu, 16 Jan 2025 18:51:20 +0000 Subject: [PATCH 11/17] repin --- Cargo.Bazel.Fuzzing.json.lock | 2 +- Cargo.Bazel.json.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.Bazel.Fuzzing.json.lock b/Cargo.Bazel.Fuzzing.json.lock index 960fd6fe866..f94f0079ac9 100644 --- a/Cargo.Bazel.Fuzzing.json.lock +++ b/Cargo.Bazel.Fuzzing.json.lock @@ -1,5 +1,5 @@ { - "checksum": "ee07bd5cde20eb057c9baa703b47a96ece7ed32714378e3b62f6cb2a1bde2d94", + "checksum": "a53d96737556099dd585f83042e6bc5d0eb99828d34f4bf0033b0b3583b2789b", "crates": { "abnf 0.12.0": { "name": "abnf", diff --git a/Cargo.Bazel.json.lock b/Cargo.Bazel.json.lock index e22c4b1ef8f..c3c59e9d72d 100644 --- a/Cargo.Bazel.json.lock +++ b/Cargo.Bazel.json.lock @@ -1,5 +1,5 @@ { - "checksum": "af5e4debd1243293865e30a9b64a67f317d54d2087da3adf9fd816ffdd8b1262", + "checksum": "b9642475d0faabe29f70c002aaede852562dae05dad3bda705eee7103ddce811", "crates": { "abnf 0.12.0": { "name": "abnf", From c860cab7317fbc0d5fe739450827a2fe624d14f2 Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Fri, 17 Jan 2025 06:35:26 +0000 Subject: [PATCH 12/17] work --- rs/execution_environment/fuzz/src/lib.rs | 42 +++++++++++++----------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index 3a0c018bcb0..5f26a544e2f 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -4,19 +4,19 @@ use ic_canister_sandbox_backend_lib::{ RUN_AS_SANDBOX_LAUNCHER_FLAG, }; use libfuzzer_sys::test_input_wrap; +use std::collections::BTreeSet; use std::ffi::CString; use std::os::raw::c_char; -use nix::sys::ptrace::Options; -use nix::sys::wait::WaitStatus; -use nix::unistd::Pid; -use procfs::process::Process; -use std::collections::BTreeSet; - -use syscalls::Sysno; - #[cfg(target_os = "linux")] -use nix::{sys::ptrace, sys::wait::waitpid, unistd::fork, unistd::ForkResult}; +use { + nix::{ + sys::ptrace, sys::ptrace::Options, sys::wait::waitpid, sys::wait::WaitStatus, unistd::fork, + unistd::ForkResult, unistd::Pid, + }, + procfs::process::Process, + syscalls::Sysno, +}; #[allow(improper_ctypes)] extern "C" { @@ -118,7 +118,7 @@ where children.pop_last(); } let child = children.last().unwrap(); - trace(name, Pid::from_raw((*child).into()), &allowed_syscalls); + trace(name, Pid::from_raw(*child), &allowed_syscalls); } } Err(err) => { @@ -161,8 +161,11 @@ fn trace(name: &str, child: Pid, allowed_syscalls: &BTreeSet) { } } - if let Ok(_) = ptrace::syscall(child, None) { - continue; + if let Err(err) = ptrace::syscall(child, None) { + panic!( + "ptrace: failed to continue to next syscall {}::{}: {}", + name, child, err + ); } } WaitStatus::PtraceSyscall(_) => { @@ -173,8 +176,11 @@ fn trace(name: &str, child: Pid, allowed_syscalls: &BTreeSet) { } } - if let Ok(_) = ptrace::syscall(child, None) { - continue; + if let Err(err) = ptrace::syscall(child, None) { + panic!( + "ptrace: failed to continue to next syscall {}::{}: {}", + name, child, err + ); } } WaitStatus::Exited(..) => { @@ -204,11 +210,9 @@ fn get_children(parent_pid: i32) -> BTreeSet { if let Ok(process) = Process::new(parent_pid) { if let Ok(tasks) = process.tasks() { - for task in tasks { - if let Ok(task) = task { - let child_pid = task.tid; - pids.insert(child_pid); - } + for task in tasks.flatten() { + let child_pid = task.tid; + pids.insert(child_pid); } } } From c33c14c337b1603fc574c93891633832ab46edf3 Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Fri, 17 Jan 2025 06:55:31 +0000 Subject: [PATCH 13/17] . --- rs/execution_environment/fuzz/BUILD.bazel | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rs/execution_environment/fuzz/BUILD.bazel b/rs/execution_environment/fuzz/BUILD.bazel index 0914ece75c4..05aa659ddf6 100644 --- a/rs/execution_environment/fuzz/BUILD.bazel +++ b/rs/execution_environment/fuzz/BUILD.bazel @@ -23,9 +23,13 @@ rust_library( "//rs/canister_sandbox:backend_lib", "@crate_index//:libfuzzer-sys", "@crate_index//:nix", - "@crate_index//:procfs", - "@crate_index//:syscalls", - ], + ] + select({ + "@rules_rust//rust/platform:linux": [ + "@crate_index//:procfs", + "@crate_index//:syscalls", + ], + "//conditions:default": [], + }), ) rust_fuzz_test_binary( From 595e3fa30fe27f3a94a71727ea016a19e98745b4 Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Fri, 17 Jan 2025 07:17:29 +0000 Subject: [PATCH 14/17] . --- rs/execution_environment/fuzz/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index 5f26a544e2f..efbe45f77bc 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -135,6 +135,7 @@ where sandbox(); } +#[cfg(target_os = "linux")] fn trace(name: &str, child: Pid, allowed_syscalls: &BTreeSet) { if let Err(err) = ptrace::attach(child) { println!( @@ -205,6 +206,7 @@ fn trace(name: &str, child: Pid, allowed_syscalls: &BTreeSet) { } } +#[cfg(target_os = "linux")] fn get_children(parent_pid: i32) -> BTreeSet { let mut pids = BTreeSet::new(); From 547519915500c3c6a4f6084fd2f55b407b7a41b2 Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Fri, 17 Jan 2025 07:22:43 +0000 Subject: [PATCH 15/17] . --- rs/execution_environment/fuzz/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index efbe45f77bc..d4610168fb0 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -4,7 +4,6 @@ use ic_canister_sandbox_backend_lib::{ RUN_AS_SANDBOX_LAUNCHER_FLAG, }; use libfuzzer_sys::test_input_wrap; -use std::collections::BTreeSet; use std::ffi::CString; use std::os::raw::c_char; @@ -15,6 +14,7 @@ use { unistd::ForkResult, unistd::Pid, }, procfs::process::Process, + std::collections::BTreeSet, syscalls::Sysno, }; From 537c8ff943fe82725464423f6e10d1557093fdde Mon Sep 17 00:00:00 2001 From: Venkkatesh Sekar Date: Fri, 17 Jan 2025 14:35:02 +0000 Subject: [PATCH 16/17] review --- rs/execution_environment/fuzz/src/lib.rs | 57 +++++++++++------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/rs/execution_environment/fuzz/src/lib.rs b/rs/execution_environment/fuzz/src/lib.rs index d4610168fb0..9c5cd1bcb3c 100644 --- a/rs/execution_environment/fuzz/src/lib.rs +++ b/rs/execution_environment/fuzz/src/lib.rs @@ -100,25 +100,25 @@ where Sysno::sigaltstack, Sysno::futex, Sysno::close, + Sysno::restart_syscall, ]); - loop { - // This code employs a manual heuristic to determine which process PID to attach to, - // specifically targeting the one executing the Wasm code. - // - // The child process spawns a total of 14 threads. Since PIDs are monotonically increasing - // and the tid are stored in a BTreeSet, they are ordered based on their creation sequence. - // - // By tracing all PIDs and analyzing the associated syscalls, we observe that the critical - // threads to attach to are typically among the last few, specifically [n-2] and [n-1]. - // - // NOTE: If the code design changes in the future, this heuristic will need to be revisited - // and updated accordingly. - let mut children = get_children(child.into()); - for _ in 0..1 { - children.pop_last(); - } - let child = children.last().unwrap(); - trace(name, Pid::from_raw(*child), &allowed_syscalls); + let children = get_children(child.into()); + let threads: Vec<_> = children + .iter() + .map(|child| { + std::thread::spawn({ + let allowed_syscalls = allowed_syscalls.clone(); + let child = *child; + let name = name.to_string(); + move || { + trace(name, Pid::from_raw(child), allowed_syscalls); + } + }) + }) + .collect(); + + for handle in threads { + handle.join().unwrap(); } } Err(err) => { @@ -136,7 +136,7 @@ where } #[cfg(target_os = "linux")] -fn trace(name: &str, child: Pid, allowed_syscalls: &BTreeSet) { +fn trace(name: String, child: Pid, allowed_syscalls: BTreeSet) { if let Err(err) = ptrace::attach(child) { println!( "ptrace: failed to attach process {}::{}: {}", @@ -145,6 +145,7 @@ fn trace(name: &str, child: Pid, allowed_syscalls: &BTreeSet) { return; } + let mut is_syscall_entry = true; while let Ok(result) = waitpid(child, None) { match result { WaitStatus::Stopped(..) => { @@ -155,13 +156,6 @@ fn trace(name: &str, child: Pid, allowed_syscalls: &BTreeSet) { ); } - if let Ok(regs) = ptrace::getregs(child) { - let sysno = Sysno::from(regs.orig_rax as u32); - if !allowed_syscalls.contains(&sysno) { - panic!("Syscall not present: {:?} {}::{}", sysno, name, child,); - } - } - if let Err(err) = ptrace::syscall(child, None) { panic!( "ptrace: failed to continue to next syscall {}::{}: {}", @@ -170,13 +164,16 @@ fn trace(name: &str, child: Pid, allowed_syscalls: &BTreeSet) { } } WaitStatus::PtraceSyscall(_) => { - if let Ok(regs) = ptrace::getregs(child) { - let sysno = Sysno::from(regs.orig_rax as u32); - if !allowed_syscalls.contains(&sysno) { - panic!("Syscall not present: {:?} {}::{}", sysno, name, child,); + if is_syscall_entry { + if let Ok(regs) = ptrace::getregs(child) { + let sysno = Sysno::from(regs.orig_rax as u32); + if !allowed_syscalls.contains(&sysno) { + panic!("Syscall not present: {:?} {}::{}", sysno, name, child,); + } } } + is_syscall_entry = !is_syscall_entry; if let Err(err) = ptrace::syscall(child, None) { panic!( "ptrace: failed to continue to next syscall {}::{}: {}", From 96490a98e3b9c442423ad9aac70b67b4d019090e Mon Sep 17 00:00:00 2001 From: IDX GitHub Automation Date: Fri, 17 Jan 2025 17:00:48 +0000 Subject: [PATCH 17/17] Automatically updated Cargo*.lock --- Cargo.Bazel.Fuzzing.json.lock | 2 +- Cargo.Bazel.json.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.Bazel.Fuzzing.json.lock b/Cargo.Bazel.Fuzzing.json.lock index 5482b9619f5..4a4c36ca861 100644 --- a/Cargo.Bazel.Fuzzing.json.lock +++ b/Cargo.Bazel.Fuzzing.json.lock @@ -1,5 +1,5 @@ { - "checksum": "d14334a6540146e857234f0c2d53dfa2a79f782c6d482bbed88e84b89205e3b5", + "checksum": "47779dd70947956334194045d833b520303bd12424c6ae738db137a5ede73532", "crates": { "abnf 0.12.0": { "name": "abnf", diff --git a/Cargo.Bazel.json.lock b/Cargo.Bazel.json.lock index bd0ff48acb6..fc9e4520644 100644 --- a/Cargo.Bazel.json.lock +++ b/Cargo.Bazel.json.lock @@ -1,5 +1,5 @@ { - "checksum": "f9106b21c4c605032607acabc6e6c407a33a1457ae8fd8acc1b003ba2c0b58b2", + "checksum": "78e6ae0a6f656c3bc2e62f91681c90f7088a556e20471251f4b378d2f917e8f0", "crates": { "abnf 0.12.0": { "name": "abnf",