From 82053ff37574c486c2cbfdb6fab98653ec279498 Mon Sep 17 00:00:00 2001 From: Sangho Lee Date: Tue, 18 Aug 2026 16:00:04 +0000 Subject: [PATCH 1/2] restrict exception fixups to synchronous faults --- litebox_platform_linux_userland/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/litebox_platform_linux_userland/src/lib.rs b/litebox_platform_linux_userland/src/lib.rs index 7006a876d..1d596e01b 100644 --- a/litebox_platform_linux_userland/src/lib.rs +++ b/litebox_platform_linux_userland/src/lib.rs @@ -2139,7 +2139,9 @@ unsafe fn next_signal_handler( info: &mut libc::siginfo_t, context: &mut libc::ucontext_t, ) { - if signum == libc::SIGSEGV { + // An asynchronous `SIGSEGV` (`info.si_code <= 0`) can interrupt a fixup range. + // Do not interpret it as a memory fault. + if signum == libc::SIGSEGV && info.si_code > 0 { let ip: usize = { #[cfg(target_arch = "x86_64")] { From a473b5180f18b6e349370b9d6a1189922192206c Mon Sep 17 00:00:00 2001 From: Sangho Lee Date: Tue, 18 Aug 2026 17:42:11 +0000 Subject: [PATCH 2/2] add a test --- litebox_platform_linux_userland/src/lib.rs | 57 +++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/litebox_platform_linux_userland/src/lib.rs b/litebox_platform_linux_userland/src/lib.rs index 1d596e01b..4173364a3 100644 --- a/litebox_platform_linux_userland/src/lib.rs +++ b/litebox_platform_linux_userland/src/lib.rs @@ -2420,7 +2420,7 @@ impl litebox::mm::linux::VmemPageFaultHandler for LinuxUserland { #[cfg(test)] mod tests { - use core::sync::atomic::AtomicU32; + use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use std::thread::sleep; use litebox::{fs::OFlags, platform::RawMutex}; @@ -2463,6 +2463,61 @@ mod tests { } } + #[test] + fn asynchronous_sigsegv_does_not_trigger_exception_fixup() { + const CHILD_ENV: &str = "LITEBOX_ASYNC_SIGSEGV_TEST_CHILD"; + + if std::env::var_os(CHILD_ENV).is_none() { + let status = std::process::Command::new(std::env::current_exe().unwrap()) + .args([ + "--exact", + "tests::asynchronous_sigsegv_does_not_trigger_exception_fixup", + "--nocapture", + ]) + .env(CHILD_ENV, "1") + .status() + .unwrap(); + assert!(status.success(), "subprocess failed: {status}"); + return; + } + + unsafe { + let mut action: libc::sigaction = core::mem::zeroed(); + action.sa_sigaction = libc::SIG_IGN; + assert_eq!( + libc::sigaction(libc::SIGSEGV, &raw const action, core::ptr::null_mut(),), + 0 + ); + } + let _platform = LinuxUserland::new(None); + + let target = unsafe { libc::pthread_self() }; + let stop = std::sync::Arc::new(AtomicBool::new(false)); + let sender_stop = stop.clone(); + let sender = std::thread::spawn(move || { + while !sender_stop.load(Ordering::Relaxed) { + assert_eq!(unsafe { libc::pthread_kill(target, libc::SIGSEGV) }, 0); + std::thread::yield_now(); + } + }); + + let src = vec![0x5a; 16 * 1024 * 1024]; + let mut dst = vec![0; src.len()]; + for _ in 0..16 { + assert!(unsafe { + litebox::mm::exception_table::memcpy_fallible( + dst.as_mut_ptr(), + src.as_ptr(), + src.len(), + ) + .is_ok() + }); + } + stop.store(true, Ordering::Relaxed); + sender.join().unwrap(); + assert_eq!(dst, src); + } + #[test] fn test_seccomp_filter() { let _platform: &LinuxUserland = LinuxUserland::new(None);