From 5c44033302f7b1c59e76757ae26fb1ba00593e5d Mon Sep 17 00:00:00 2001 From: weitengchen Date: Thu, 23 Apr 2026 18:13:40 -0700 Subject: [PATCH 1/7] enable seccomp filter --- Cargo.lock | 10 +++ litebox_platform_linux_userland/Cargo.toml | 1 + litebox_platform_linux_userland/src/lib.rs | 78 ++++++++++++++++++++++ litebox_runner_linux_userland/src/lib.rs | 3 + 4 files changed, 92 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index ad0c763ca..56f2fa7be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1537,6 +1537,7 @@ dependencies = [ "litebox", "litebox_common_linux", "litebox_common_optee", + "seccompiler", "spin 0.9.8", "syscalls", "zerocopy", @@ -2521,6 +2522,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "seccompiler" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4ae55de56877481d112a559bbc12667635fdaf5e005712fd4e2b2fa50ffc884" +dependencies = [ + "libc", +] + [[package]] name = "security-framework" version = "2.11.1" diff --git a/litebox_platform_linux_userland/Cargo.toml b/litebox_platform_linux_userland/Cargo.toml index 1c4d96ed6..25b389443 100644 --- a/litebox_platform_linux_userland/Cargo.toml +++ b/litebox_platform_linux_userland/Cargo.toml @@ -13,6 +13,7 @@ litebox_common_optee = { path = "../litebox_common_optee", version = "0.1.0", de spin = "0.9.8" syscalls = { version = "0.6", default-features = false } zerocopy = { version = "0.8", default-features = false } +seccompiler = { version = "0.5.0" } [features] default = ["linux_syscall"] diff --git a/litebox_platform_linux_userland/src/lib.rs b/litebox_platform_linux_userland/src/lib.rs index a1ccf7fdc..a9df9d75d 100644 --- a/litebox_platform_linux_userland/src/lib.rs +++ b/litebox_platform_linux_userland/src/lib.rs @@ -412,6 +412,84 @@ impl LinuxUserland { ) }; } + + #[cfg(target_arch = "x86_64")] + #[allow( + clippy::missing_panics_doc, + reason = "the seccomp filter rules are hardcoded and not expected to fail" + )] + pub fn enable_seccomp_filter() { + use seccompiler::{ + BpfProgram, SeccompAction, SeccompCmpArgLen, SeccompCmpOp, SeccompCondition, + SeccompFilter, SeccompRule, + }; + + let rules = vec![ + // TUN and terminal + (libc::SYS_read, vec![]), + (libc::SYS_write, vec![]), + (libc::SYS_poll, vec![]), + // memory management + (libc::SYS_mmap, vec![]), + (libc::SYS_mprotect, vec![]), + (libc::SYS_munmap, vec![]), + (libc::SYS_mremap, vec![]), + // signal + (libc::SYS_rt_sigreturn, vec![]), + (libc::SYS_sigaltstack, vec![]), + (libc::SYS_tgkill, vec![]), + (libc::SYS_timer_create, vec![]), + (libc::SYS_timer_settime, vec![]), + (libc::SYS_timer_delete, vec![]), + // thread management + (libc::SYS_exit, vec![]), + (libc::SYS_exit_group, vec![]), + (libc::SYS_clone3, vec![]), + // sync + (libc::SYS_futex, vec![]), + // misc + (libc::SYS_getrandom, vec![]), + // required by std spawn + (libc::SYS_rseq, vec![]), + (libc::SYS_set_robust_list, vec![]), + (libc::SYS_get_robust_list, vec![]), + (libc::SYS_sched_getaffinity, vec![]), + (libc::SYS_gettid, vec![]), + (libc::SYS_madvise, vec![]), + // required by libc allocator + (libc::SYS_brk, vec![]), + (libc::SYS_getpid, vec![]), + // TODO: could be removed if we pre-open files (see `try_allocate_cow_pages`) + ( + libc::SYS_open, + vec![ + SeccompRule::new(vec![ + SeccompCondition::new( + 1, + SeccompCmpArgLen::Dword, + SeccompCmpOp::Eq, + u64::from(OFlags::RDONLY.bits()), + ) + .unwrap(), + ]) + .unwrap(), + ], + ), + ]; + let rule_map: std::collections::BTreeMap> = + rules.into_iter().collect(); + let filter = SeccompFilter::new( + rule_map, + SeccompAction::Errno(libc::EINVAL.cast_unsigned()), + SeccompAction::Allow, + seccompiler::TargetArch::x86_64, + ) + .unwrap(); + // TODO: bpf program can be compiled offline + let bpf_prog: BpfProgram = filter.try_into().unwrap(); + + seccompiler::apply_filter(&bpf_prog).unwrap(); + } } impl litebox::platform::Provider for LinuxUserland {} diff --git a/litebox_runner_linux_userland/src/lib.rs b/litebox_runner_linux_userland/src/lib.rs index 90b24878b..376857072 100644 --- a/litebox_runner_linux_userland/src/lib.rs +++ b/litebox_runner_linux_userland/src/lib.rs @@ -388,6 +388,9 @@ pub fn run(cli_args: CliArgs) -> Result<()> { envp, )?; + #[cfg(target_arch = "x86_64")] + litebox_platform_linux_userland::LinuxUserland::enable_seccomp_filter(); + #[cfg(feature = "lock_tracing")] litebox::sync::start_recording(); From 0dce904e4c586c325bb5601281e5123eccd266f8 Mon Sep 17 00:00:00 2001 From: weitengchen Date: Fri, 24 Apr 2026 18:09:04 +0000 Subject: [PATCH 2/7] add test --- litebox_platform_linux_userland/src/lib.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/litebox_platform_linux_userland/src/lib.rs b/litebox_platform_linux_userland/src/lib.rs index a9df9d75d..f4e2939bd 100644 --- a/litebox_platform_linux_userland/src/lib.rs +++ b/litebox_platform_linux_userland/src/lib.rs @@ -2394,4 +2394,18 @@ mod tests { prev = page.end; } } + + #[test] + fn test_seccomp_filter() { + let _platform = LinuxUserland::new(None); + LinuxUserland::enable_seccomp_filter(); + let pathname = "/tmp/test_seccomp"; + let res = unsafe { + syscalls::syscall2(syscalls::Sysno::mkdir, pathname.as_ptr() as usize, 0o755) + }; + assert!( + res.is_err() && res.unwrap_err() == syscalls::Errno::EINVAL, + "mkdir should be blocked by seccomp filter" + ); + } } From 1b6f2ec51dd9dc21e63c826a402a3768ce17bf57 Mon Sep 17 00:00:00 2001 From: weitengchen Date: Fri, 24 Apr 2026 18:30:42 +0000 Subject: [PATCH 3/7] update test --- litebox_platform_linux_userland/src/lib.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/litebox_platform_linux_userland/src/lib.rs b/litebox_platform_linux_userland/src/lib.rs index f4e2939bd..dd8da569c 100644 --- a/litebox_platform_linux_userland/src/lib.rs +++ b/litebox_platform_linux_userland/src/lib.rs @@ -2355,7 +2355,7 @@ mod tests { use core::sync::atomic::AtomicU32; use std::thread::sleep; - use litebox::platform::RawMutex; + use litebox::{fs::OFlags, platform::RawMutex}; use crate::LinuxUserland; use litebox::platform::PageManagementProvider; @@ -2399,7 +2399,7 @@ mod tests { fn test_seccomp_filter() { let _platform = LinuxUserland::new(None); LinuxUserland::enable_seccomp_filter(); - let pathname = "/tmp/test_seccomp"; + let pathname = c"/tmp/test_seccomp"; let res = unsafe { syscalls::syscall2(syscalls::Sysno::mkdir, pathname.as_ptr() as usize, 0o755) }; @@ -2407,5 +2407,19 @@ mod tests { res.is_err() && res.unwrap_err() == syscalls::Errno::EINVAL, "mkdir should be blocked by seccomp filter" ); + + let pathname = + std::ffi::CString::new(format!("{}/Cargo.toml", env!("CARGO_MANIFEST_DIR"))).unwrap(); + let res = unsafe { + syscalls::syscall2( + syscalls::Sysno::open, + pathname.as_ptr() as usize, + OFlags::RDWR.bits() as usize, + ) + }; + assert!( + res.is_err() && res.unwrap_err() == syscalls::Errno::EINVAL, + "open with RDWR should be blocked by seccomp filter" + ); } } From 30e523f9f42fd30e725ee0c314fdc0f1498b5341 Mon Sep 17 00:00:00 2001 From: weitengchen Date: Fri, 24 Apr 2026 22:15:08 +0000 Subject: [PATCH 4/7] log violation in debug mode --- litebox_platform_linux_userland/src/lib.rs | 126 +++++++++++++++++++-- litebox_runner_linux_userland/src/lib.rs | 6 +- 2 files changed, 117 insertions(+), 15 deletions(-) diff --git a/litebox_platform_linux_userland/src/lib.rs b/litebox_platform_linux_userland/src/lib.rs index dd8da569c..513f475d0 100644 --- a/litebox_platform_linux_userland/src/lib.rs +++ b/litebox_platform_linux_userland/src/lib.rs @@ -480,7 +480,14 @@ impl LinuxUserland { rules.into_iter().collect(); let filter = SeccompFilter::new( rule_map, - SeccompAction::Errno(libc::EINVAL.cast_unsigned()), + // In debug builds, log violations instead of silently returning an error so that + // it won't fail silently during development (which may hard to debug) and we can + // tell there are missing seccomp rules to be added by comparing debug and release runs. + if cfg!(debug_assertions) { + SeccompAction::Log + } else { + SeccompAction::Errno(libc::EINVAL.cast_unsigned()) + }, SeccompAction::Allow, seccompiler::TargetArch::x86_64, ) @@ -2397,29 +2404,124 @@ mod tests { #[test] fn test_seccomp_filter() { - let _platform = LinuxUserland::new(None); + let _platform: &LinuxUserland = LinuxUserland::new(None); + + // In debug builds the default action is `SeccompAction::Log`, which only + // emits an `AUDIT_SECCOMP` record (visible via auditd or `dmesg`) but lets + // the syscall proceed. In release builds the default action is + // `SeccompAction::Errno(EINVAL)`, which blocks the syscall. + let expect_blocked = !cfg!(debug_assertions); + + // In Log mode, try to open `/dev/kmsg` *before* installing the filter so + // that we can later read the seccomp audit messages emitted by the + // kernel. This requires `CAP_SYSLOG` (or `dmesg_restrict=0`); if it is + // not available we just skip the log-content check. + // + // We also seek to the end of the buffer here (`lseek` isn't in the + // seccomp allowlist, so this must happen before installing the filter). + let kmsg_fd: Option = if expect_blocked { + None + } else { + let path = c"/dev/kmsg"; + let r = unsafe { + syscalls::syscall3( + syscalls::Sysno::open, + path.as_ptr() as usize, + (OFlags::RDONLY | OFlags::NONBLOCK).bits() as usize, + 0, + ) + }; + match r { + Ok(fd) => { + // Seek to the end so we only see new messages. + let _ = unsafe { + syscalls::syscall3(syscalls::Sysno::lseek, fd, 0, libc::SEEK_END as usize) + }; + Some(fd) + } + Err(_) => None, + } + }; + LinuxUserland::enable_seccomp_filter(); + let pathname = c"/tmp/test_seccomp"; - let res = unsafe { + let mkdir_res = unsafe { syscalls::syscall2(syscalls::Sysno::mkdir, pathname.as_ptr() as usize, 0o755) }; - assert!( - res.is_err() && res.unwrap_err() == syscalls::Errno::EINVAL, - "mkdir should be blocked by seccomp filter" - ); + if expect_blocked { + assert_eq!( + mkdir_res.unwrap_err(), + syscalls::Errno::EINVAL, + "mkdir should be blocked by seccomp filter" + ); + } else { + // In Log mode the syscall proceeds; clean up (also generates a Log record). + let _ = + unsafe { syscalls::syscall1(syscalls::Sysno::rmdir, pathname.as_ptr() as usize) }; + } let pathname = std::ffi::CString::new(format!("{}/Cargo.toml", env!("CARGO_MANIFEST_DIR"))).unwrap(); - let res = unsafe { + let open_res = unsafe { syscalls::syscall2( syscalls::Sysno::open, pathname.as_ptr() as usize, OFlags::RDWR.bits() as usize, ) }; - assert!( - res.is_err() && res.unwrap_err() == syscalls::Errno::EINVAL, - "open with RDWR should be blocked by seccomp filter" - ); + if expect_blocked { + assert_eq!( + open_res.unwrap_err(), + syscalls::Errno::EINVAL, + "open with RDWR should be blocked by seccomp filter" + ); + } + + // In Log mode, drain `/dev/kmsg` and verify that the kernel emitted an + // `audit: type=1326 ... seccomp ...` record for one of our offending + // syscalls. If we couldn't open `/dev/kmsg` (no `CAP_SYSLOG`), skip. + if let Some(fd) = kmsg_fd { + let mut found = false; + let mut buf = [0u8; 4096]; + loop { + let n = unsafe { + syscalls::syscall3( + syscalls::Sysno::read, + fd, + buf.as_mut_ptr() as usize, + buf.len(), + ) + }; + match n { + Ok(0) | Err(_) => break, + Ok(n) => { + let line = String::from_utf8_lossy(&buf[..n]); + // Audit seccomp records have type=1326 and the offending + // syscall number, e.g. `syscall=83` for mkdir or + // `syscall=2` for open on x86_64. + if line.contains("type=1326") + && (line.contains(&format!("syscall={}", libc::SYS_mkdir)) + || line.contains(&format!("syscall={}", libc::SYS_open))) + { + found = true; + } + } + } + } + let _ = unsafe { syscalls::syscall1(syscalls::Sysno::close, fd) }; + assert!( + found, + "expected an AUDIT_SECCOMP (type=1326) record for mkdir/open in /dev/kmsg" + ); + eprintln!( + "test_seccomp_filter: found AUDIT_SECCOMP record for mkdir/open in /dev/kmsg" + ); + } else if !expect_blocked { + eprintln!( + "test_seccomp_filter: /dev/kmsg not readable (need CAP_SYSLOG \ + or dmesg_restrict=0); skipping log-content check" + ); + } } } diff --git a/litebox_runner_linux_userland/src/lib.rs b/litebox_runner_linux_userland/src/lib.rs index 376857072..ff0dcfef2 100644 --- a/litebox_runner_linux_userland/src/lib.rs +++ b/litebox_runner_linux_userland/src/lib.rs @@ -380,6 +380,9 @@ pub fn run(cli_args: CliArgs) -> Result<()> { envp }; + #[cfg(target_arch = "x86_64")] + litebox_platform_linux_userland::LinuxUserland::enable_seccomp_filter(); + let program = shim.load_program( initial_file_system, platform.init_task(), @@ -388,9 +391,6 @@ pub fn run(cli_args: CliArgs) -> Result<()> { envp, )?; - #[cfg(target_arch = "x86_64")] - litebox_platform_linux_userland::LinuxUserland::enable_seccomp_filter(); - #[cfg(feature = "lock_tracing")] litebox::sync::start_recording(); From b9dda664ab32080f4c99cdd1bd60bf5b910cade9 Mon Sep 17 00:00:00 2001 From: weitengchen Date: Mon, 27 Apr 2026 15:10:32 -0700 Subject: [PATCH 5/7] trap and log syscalls --- Cargo.lock | 1 + litebox_platform_linux_userland/Cargo.toml | 1 + litebox_platform_linux_userland/src/lib.rs | 152 +++++++-------------- litebox_runner_linux_userland/src/lib.rs | 10 +- 4 files changed, 52 insertions(+), 112 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 56f2fa7be..138a14b97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1531,6 +1531,7 @@ dependencies = [ name = "litebox_platform_linux_userland" version = "0.1.0" dependencies = [ + "arrayvec", "cfg-if", "getrandom 0.3.4", "libc", diff --git a/litebox_platform_linux_userland/Cargo.toml b/litebox_platform_linux_userland/Cargo.toml index 25b389443..a4e5ef9a2 100644 --- a/litebox_platform_linux_userland/Cargo.toml +++ b/litebox_platform_linux_userland/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +arrayvec = { version = "0.7.6", default-features = false } cfg-if = "1.0.0" getrandom = "0.3.4" libc = { version = "0.2.169", default-features = false } diff --git a/litebox_platform_linux_userland/src/lib.rs b/litebox_platform_linux_userland/src/lib.rs index 513f475d0..bb54c4bf5 100644 --- a/litebox_platform_linux_userland/src/lib.rs +++ b/litebox_platform_linux_userland/src/lib.rs @@ -441,6 +441,13 @@ impl LinuxUserland { (libc::SYS_timer_create, vec![]), (libc::SYS_timer_settime, vec![]), (libc::SYS_timer_delete, vec![]), + // called by [pthread_create](https://codebrowser.dev/glibc/glibc/nptl/pthread_create.c.html#83) to set up signal handler + // to support setuid et.al. functions (which we probably don't need, but include them in debug mode to suppress the warnings + // about missing seccomp rules for these syscalls). + #[cfg(debug_assertions)] + (libc::SYS_rt_sigaction, vec![]), + // TODO: also called by `next_signal_handler`, but I'm not sure if it's really needed. + (libc::SYS_rt_sigprocmask, vec![]), // thread management (libc::SYS_exit, vec![]), (libc::SYS_exit_group, vec![]), @@ -475,16 +482,16 @@ impl LinuxUserland { .unwrap(), ], ), + (libc::SYS_close, vec![]), ]; let rule_map: std::collections::BTreeMap> = rules.into_iter().collect(); let filter = SeccompFilter::new( rule_map, // In debug builds, log violations instead of silently returning an error so that - // it won't fail silently during development (which may hard to debug) and we can - // tell there are missing seccomp rules to be added by comparing debug and release runs. + // it won't fail silently during development (which may be hard to debug). if cfg!(debug_assertions) { - SeccompAction::Log + SeccompAction::Trap } else { SeccompAction::Errno(libc::EINVAL.cast_unsigned()) }, @@ -1838,6 +1845,9 @@ fn register_exception_handlers() { libc::SIGFPE, libc::SIGILL, libc::SIGTRAP, + // We'd like to log forbidden syscalls in debug mode + #[cfg(debug_assertions)] + libc::SIGSYS, ]; for &sig in exception_signals { unsafe { @@ -2072,6 +2082,30 @@ unsafe extern "C" fn exception_signal_handler( info: &mut libc::siginfo_t, context: &mut libc::ucontext_t, ) { + // Return an error code for the syscall and log it in debug mode. + #[cfg(debug_assertions)] + if signum == libc::SIGSYS { + use core::fmt::Write as _; + #[cfg(target_arch = "x86_64")] + let eax_idx = libc::REG_RAX as usize; + let sysno = context.uc_mcontext.gregs[eax_idx]; + context.uc_mcontext.gregs[eax_idx] = i64::from(-libc::EINVAL); + // Signal-safe: format on the stack via arrayvec (no heap allocation). + let mut buf = arrayvec::ArrayString::<64>::new(); + if sysno == libc::SYS_openat { + #[cfg(target_arch = "x86_64")] + let rsi = context.uc_mcontext.gregs[libc::REG_RSI as usize] as *const i8; + let c_path = unsafe { core::ffi::CStr::from_ptr(rsi) }; + // libc may call `openat` for certain files that we can ignore, e.g., /proc/sys/vm/overcommit_memory. + // Log the paths in case we need to allow some of them in the future. + writeln!(buf, "INFO: openat with {c_path:?}").unwrap(); + } else { + writeln!(buf, "WARNING: disallowed syscall invoked: {sysno}").unwrap(); + } + let _ = unsafe { libc::write(libc::STDERR_FILENO, buf.as_ptr().cast(), buf.len()) }; + return; + } + let Some(regs) = signal_handler_exit_guest(context, false) else { return unsafe { next_signal_handler(signum, info, context) }; }; @@ -2405,61 +2439,17 @@ mod tests { #[test] fn test_seccomp_filter() { let _platform: &LinuxUserland = LinuxUserland::new(None); - - // In debug builds the default action is `SeccompAction::Log`, which only - // emits an `AUDIT_SECCOMP` record (visible via auditd or `dmesg`) but lets - // the syscall proceed. In release builds the default action is - // `SeccompAction::Errno(EINVAL)`, which blocks the syscall. - let expect_blocked = !cfg!(debug_assertions); - - // In Log mode, try to open `/dev/kmsg` *before* installing the filter so - // that we can later read the seccomp audit messages emitted by the - // kernel. This requires `CAP_SYSLOG` (or `dmesg_restrict=0`); if it is - // not available we just skip the log-content check. - // - // We also seek to the end of the buffer here (`lseek` isn't in the - // seccomp allowlist, so this must happen before installing the filter). - let kmsg_fd: Option = if expect_blocked { - None - } else { - let path = c"/dev/kmsg"; - let r = unsafe { - syscalls::syscall3( - syscalls::Sysno::open, - path.as_ptr() as usize, - (OFlags::RDONLY | OFlags::NONBLOCK).bits() as usize, - 0, - ) - }; - match r { - Ok(fd) => { - // Seek to the end so we only see new messages. - let _ = unsafe { - syscalls::syscall3(syscalls::Sysno::lseek, fd, 0, libc::SEEK_END as usize) - }; - Some(fd) - } - Err(_) => None, - } - }; - LinuxUserland::enable_seccomp_filter(); let pathname = c"/tmp/test_seccomp"; let mkdir_res = unsafe { syscalls::syscall2(syscalls::Sysno::mkdir, pathname.as_ptr() as usize, 0o755) }; - if expect_blocked { - assert_eq!( - mkdir_res.unwrap_err(), - syscalls::Errno::EINVAL, - "mkdir should be blocked by seccomp filter" - ); - } else { - // In Log mode the syscall proceeds; clean up (also generates a Log record). - let _ = - unsafe { syscalls::syscall1(syscalls::Sysno::rmdir, pathname.as_ptr() as usize) }; - } + assert_eq!( + mkdir_res.unwrap_err(), + syscalls::Errno::EINVAL, + "mkdir should be blocked by seccomp filter" + ); let pathname = std::ffi::CString::new(format!("{}/Cargo.toml", env!("CARGO_MANIFEST_DIR"))).unwrap(); @@ -2470,58 +2460,10 @@ mod tests { OFlags::RDWR.bits() as usize, ) }; - if expect_blocked { - assert_eq!( - open_res.unwrap_err(), - syscalls::Errno::EINVAL, - "open with RDWR should be blocked by seccomp filter" - ); - } - - // In Log mode, drain `/dev/kmsg` and verify that the kernel emitted an - // `audit: type=1326 ... seccomp ...` record for one of our offending - // syscalls. If we couldn't open `/dev/kmsg` (no `CAP_SYSLOG`), skip. - if let Some(fd) = kmsg_fd { - let mut found = false; - let mut buf = [0u8; 4096]; - loop { - let n = unsafe { - syscalls::syscall3( - syscalls::Sysno::read, - fd, - buf.as_mut_ptr() as usize, - buf.len(), - ) - }; - match n { - Ok(0) | Err(_) => break, - Ok(n) => { - let line = String::from_utf8_lossy(&buf[..n]); - // Audit seccomp records have type=1326 and the offending - // syscall number, e.g. `syscall=83` for mkdir or - // `syscall=2` for open on x86_64. - if line.contains("type=1326") - && (line.contains(&format!("syscall={}", libc::SYS_mkdir)) - || line.contains(&format!("syscall={}", libc::SYS_open))) - { - found = true; - } - } - } - } - let _ = unsafe { syscalls::syscall1(syscalls::Sysno::close, fd) }; - assert!( - found, - "expected an AUDIT_SECCOMP (type=1326) record for mkdir/open in /dev/kmsg" - ); - eprintln!( - "test_seccomp_filter: found AUDIT_SECCOMP record for mkdir/open in /dev/kmsg" - ); - } else if !expect_blocked { - eprintln!( - "test_seccomp_filter: /dev/kmsg not readable (need CAP_SYSLOG \ - or dmesg_restrict=0); skipping log-content check" - ); - } + assert_eq!( + open_res.unwrap_err(), + syscalls::Errno::EINVAL, + "open with RDWR should be blocked by seccomp filter" + ); } } diff --git a/litebox_runner_linux_userland/src/lib.rs b/litebox_runner_linux_userland/src/lib.rs index ff0dcfef2..d0cfe6e2c 100644 --- a/litebox_runner_linux_userland/src/lib.rs +++ b/litebox_runner_linux_userland/src/lib.rs @@ -380,16 +380,12 @@ pub fn run(cli_args: CliArgs) -> Result<()> { envp }; + let task_params = platform.init_task(); + #[cfg(target_arch = "x86_64")] litebox_platform_linux_userland::LinuxUserland::enable_seccomp_filter(); - let program = shim.load_program( - initial_file_system, - platform.init_task(), - prog_path, - argv, - envp, - )?; + let program = shim.load_program(initial_file_system, task_params, prog_path, argv, envp)?; #[cfg(feature = "lock_tracing")] litebox::sync::start_recording(); From 3888a602509b075544af829929ef29fff0745f5e Mon Sep 17 00:00:00 2001 From: weitengchen Date: Mon, 27 Apr 2026 15:18:31 -0700 Subject: [PATCH 6/7] update log --- litebox_platform_linux_userland/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litebox_platform_linux_userland/src/lib.rs b/litebox_platform_linux_userland/src/lib.rs index bb54c4bf5..e281485d8 100644 --- a/litebox_platform_linux_userland/src/lib.rs +++ b/litebox_platform_linux_userland/src/lib.rs @@ -2098,7 +2098,7 @@ unsafe extern "C" fn exception_signal_handler( let c_path = unsafe { core::ffi::CStr::from_ptr(rsi) }; // libc may call `openat` for certain files that we can ignore, e.g., /proc/sys/vm/overcommit_memory. // Log the paths in case we need to allow some of them in the future. - writeln!(buf, "INFO: openat with {c_path:?}").unwrap(); + writeln!(buf, "INFO: openat with {c_path:?} is not allowed").unwrap(); } else { writeln!(buf, "WARNING: disallowed syscall invoked: {sysno}").unwrap(); } From 1a51d6e76fb8776673b0e603d59b0c9c33eaad37 Mon Sep 17 00:00:00 2001 From: weitengchen Date: Mon, 27 Apr 2026 16:18:42 -0700 Subject: [PATCH 7/7] address unwrap panic --- litebox_platform_linux_userland/src/lib.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/litebox_platform_linux_userland/src/lib.rs b/litebox_platform_linux_userland/src/lib.rs index e281485d8..a88432c90 100644 --- a/litebox_platform_linux_userland/src/lib.rs +++ b/litebox_platform_linux_userland/src/lib.rs @@ -2091,18 +2091,25 @@ unsafe extern "C" fn exception_signal_handler( let sysno = context.uc_mcontext.gregs[eax_idx]; context.uc_mcontext.gregs[eax_idx] = i64::from(-libc::EINVAL); // Signal-safe: format on the stack via arrayvec (no heap allocation). - let mut buf = arrayvec::ArrayString::<64>::new(); + let mut buf = arrayvec::ArrayString::<320>::new(); if sysno == libc::SYS_openat { #[cfg(target_arch = "x86_64")] let rsi = context.uc_mcontext.gregs[libc::REG_RSI as usize] as *const i8; let c_path = unsafe { core::ffi::CStr::from_ptr(rsi) }; // libc may call `openat` for certain files that we can ignore, e.g., /proc/sys/vm/overcommit_memory. // Log the paths in case we need to allow some of them in the future. - writeln!(buf, "INFO: openat with {c_path:?} is not allowed").unwrap(); + let _ = writeln!(buf, "INFO: openat with {c_path:?} is not allowed"); } else { - writeln!(buf, "WARNING: disallowed syscall invoked: {sysno}").unwrap(); + let _ = writeln!(buf, "WARNING: disallowed syscall invoked: {sysno}"); } - let _ = unsafe { libc::write(libc::STDERR_FILENO, buf.as_ptr().cast(), buf.len()) }; + let _ = unsafe { + syscalls::syscall3( + syscalls::Sysno::write, + libc::STDERR_FILENO as usize, + buf.as_ptr() as usize, + buf.len(), + ) + }; return; }