Skip to content

Commit cfdddee

Browse files
chore(fuzzing): extend syscall whitelist in sandbox fuzzers (dfinity#3659)
In the sandbox monitor function, the parent thread calls `std::thread::sleep(std::time::Duration::from_secs(1))` to allow the sandbox to spawn all its threads before tracing begins. However, this approach is unreliable—the sleep duration is arbitrary, and attachment can occur at any point in execution. This led to `getrandom` failures in CI. This PR removes the sleep timer and instead continuously fetches `tid`s as threads spawn, attaching to them dynamically. The trade-off is that it requires knowing the number of sandbox threads in advance.
1 parent 4f0fa46 commit cfdddee

File tree

1 file changed

+29
-12
lines changed
  • rs/execution_environment/fuzz/src

1 file changed

+29
-12
lines changed

rs/execution_environment/fuzz/src/lib.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use std::os::raw::c_char;
1010
#[cfg(target_os = "linux")]
1111
use {
1212
nix::{
13-
sys::ptrace, sys::ptrace::Options, sys::wait::waitpid, sys::wait::WaitStatus, unistd::fork,
14-
unistd::ForkResult, unistd::Pid,
13+
sys::ptrace, sys::ptrace::Options, sys::wait::waitpid, sys::wait::WaitPidFlag,
14+
sys::wait::WaitStatus, unistd::fork, unistd::ForkResult, unistd::Pid,
1515
},
1616
procfs::process::Process,
1717
std::collections::BTreeSet,
@@ -90,8 +90,16 @@ where
9090
sandbox();
9191
}
9292
Ok(ForkResult::Parent { child }) => {
93-
std::thread::sleep(std::time::Duration::from_secs(1));
9493
let allowed_syscalls: BTreeSet<Sysno> = BTreeSet::from([
94+
// Init
95+
Sysno::gettid,
96+
Sysno::rt_sigprocmask,
97+
Sysno::clone,
98+
Sysno::sched_yield,
99+
Sysno::sched_getaffinity,
100+
Sysno::prctl,
101+
Sysno::getrandom, // probably due to hashbrown dependency
102+
// Execution
95103
Sysno::mmap,
96104
Sysno::mprotect,
97105
Sysno::munmap,
@@ -102,20 +110,29 @@ where
102110
Sysno::close,
103111
Sysno::restart_syscall,
104112
]);
105-
let children = get_children(child.into());
106-
let threads: Vec<_> = children
107-
.iter()
108-
.map(|child| {
109-
std::thread::spawn({
113+
114+
let mut threads: Vec<_> = vec![];
115+
let mut visited = BTreeSet::new();
116+
while let Ok(WaitStatus::StillAlive) = waitpid(child, Some(WaitPidFlag::WNOHANG)) {
117+
let children = get_children(child.into());
118+
119+
for pid in children {
120+
if visited.contains(&pid) {
121+
continue;
122+
}
123+
124+
visited.insert(pid);
125+
126+
threads.push(std::thread::spawn({
110127
let allowed_syscalls = allowed_syscalls.clone();
111-
let child = *child;
128+
let child = pid;
112129
let name = name.to_string();
113130
move || {
114131
trace(name, Pid::from_raw(child), allowed_syscalls);
115132
}
116-
})
117-
})
118-
.collect();
133+
}));
134+
}
135+
}
119136

120137
for handle in threads {
121138
handle.join().unwrap();

0 commit comments

Comments
 (0)