Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ The async notification supervisor (tokio) handles intercepted syscalls:
Downstream Rust crates can append their own seccomp-notification
handlers to the supervisor chain alongside the builtins, registering
for any syscall they care about via the `Handler` trait and
`Sandbox::run_with_extra_handlers`. The builtin chain runs first, so
`Sandbox::run_with_handlers`. The builtin chain runs first, so
user handlers cannot subvert confinement; the registration step also
rejects handlers on syscalls in the default blocklist or
`extra_deny_syscalls`. See
Expand Down
4 changes: 2 additions & 2 deletions crates/sandlock-core/examples/openat_audit.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Audit every `openat(2)` that a sandboxed process performs.
//!
//! Demonstrates [`Sandbox::run_with_extra_handlers`]: a downstream crate
//! Demonstrates [`Sandbox::run_with_handlers`]: a downstream crate
//! registers a user handler for `SYS_openat` that logs the call and falls
//! through to default (builtin) processing.
//!
Expand Down Expand Up @@ -62,7 +62,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
};

let result = policy.clone().with_name("openat-audit")
.run_with_extra_handlers(
.run_with_handlers(
&cmd_ref,
[(libc::SYS_openat, audit)],
)
Expand Down
4 changes: 2 additions & 2 deletions crates/sandlock-core/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ pub(crate) fn confine_child(args: ChildSpawnArgs<'_>) -> ! {
} else {
// First-level sandbox: notif + deny filter with NEW_LISTENER.
//
// Caller-supplied extra handlers must have their syscalls registered in
// Caller-supplied handlers must have their syscalls registered in
// the BPF filter, otherwise the kernel never raises a notification for
// them and the handler silently never fires. We merge `extra_syscalls`
// into the notif list and dedup so each syscall produces exactly one
Expand All @@ -986,7 +986,7 @@ pub(crate) fn confine_child(args: ChildSpawnArgs<'_>) -> ! {
notif.extend_from_slice(extra_syscalls);
}
// Argv-safety gate (companion to the policy_fn case in
// notif_syscalls): an extra handler bound to execve/execveat
// notif_syscalls): a handler bound to execve/execveat
// can call `read_child_mem` to inspect argv, so the supervisor
// must register newly forked children before they can run user
// code — same invariant policy_fn relies on. Bare fork(2)
Expand Down
38 changes: 19 additions & 19 deletions crates/sandlock-core/src/sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ struct Runtime {
http_acl_handle: Option<crate::http_acl::HttpAclProxyHandle>,
#[allow(clippy::type_complexity)]
on_bind: Option<Box<dyn Fn(&HashMap<u16, u16>) + Send + Sync>>,
extra_handlers: Vec<(i64, Arc<dyn crate::seccomp::dispatch::Handler>)>,
handlers: Vec<(i64, Arc<dyn crate::seccomp::dispatch::Handler>)>,
ready_w: Option<std::os::fd::OwnedFd>,
}

Expand Down Expand Up @@ -805,38 +805,38 @@ impl Sandbox {
}

/// One-shot run with user-supplied syscall handlers.
pub async fn run_with_extra_handlers<I, S, H>(
pub async fn run_with_handlers<I, S, H>(
&mut self,
cmd: &[&str],
extra_handlers: I,
handlers: I,
) -> Result<crate::result::RunResult, crate::error::SandlockError>
where
I: IntoIterator<Item = (S, H)>,
S: TryInto<crate::seccomp::syscall::Syscall, Error = crate::seccomp::syscall::SyscallError>,
H: crate::seccomp::dispatch::Handler,
{
let pending = sandbox_collect_extra_handlers(extra_handlers, self)?;
let pending = sandbox_collect_handlers(handlers, self)?;
self.ensure_runtime()?;
self.rt_mut().extra_handlers = pending;
self.rt_mut().handlers = pending;
self.do_create(cmd, true).await?;
self.do_start()?;
self.wait().await
}

/// Interactive-stdio counterpart of `run_with_extra_handlers`.
pub async fn run_interactive_with_extra_handlers<I, S, H>(
/// Interactive-stdio counterpart of `run_with_handlers`.
pub async fn run_interactive_with_handlers<I, S, H>(
&mut self,
cmd: &[&str],
extra_handlers: I,
handlers: I,
) -> Result<crate::result::RunResult, crate::error::SandlockError>
where
I: IntoIterator<Item = (S, H)>,
S: TryInto<crate::seccomp::syscall::Syscall, Error = crate::seccomp::syscall::SyscallError>,
H: crate::seccomp::dispatch::Handler,
{
let pending = sandbox_collect_extra_handlers(extra_handlers, self)?;
let pending = sandbox_collect_handlers(handlers, self)?;
self.ensure_runtime()?;
self.rt_mut().extra_handlers = pending;
self.rt_mut().handlers = pending;
self.do_create(cmd, false).await?;
self.do_start()?;
self.wait().await
Expand Down Expand Up @@ -1009,7 +1009,7 @@ impl Sandbox {
extra_fds: Vec::new(),
http_acl_handle: None,
on_bind: None,
extra_handlers: Vec::new(),
handlers: Vec::new(),
ready_w: None,
}));
clones.push(clone_sb);
Expand Down Expand Up @@ -1094,7 +1094,7 @@ impl Sandbox {
extra_fds: Vec::new(),
http_acl_handle: None,
on_bind: None,
extra_handlers: Vec::new(),
handlers: Vec::new(),
ready_w: None,
}));
Ok(())
Expand Down Expand Up @@ -1265,7 +1265,7 @@ impl Sandbox {

let gather_keep_fds: Vec<i32> = extra_fds_copy.iter().map(|&(target, _)| target).collect();

let extra_syscalls: Vec<u32> = self.rt().extra_handlers
let extra_syscalls: Vec<u32> = self.rt().handlers
.iter()
.map(|h| h.0 as u32)
.collect();
Expand Down Expand Up @@ -1346,7 +1346,7 @@ impl Sandbox {
has_random_seed: self.random_seed.is_some(),
has_time_start: self.time_start.is_some(),
argv_safety_required: self.policy_fn.is_some()
|| self.rt().extra_handlers.iter().any(|h| {
|| self.rt().handlers.iter().any(|h| {
h.0 == libc::SYS_execve || h.0 == libc::SYS_execveat
}),
time_offset: time_offset_val,
Expand Down Expand Up @@ -1495,10 +1495,10 @@ impl Sandbox {
notif_fd: notif_raw_fd,
});

let extra_handlers = std::mem::take(&mut self.rt_mut().extra_handlers);
let handlers = std::mem::take(&mut self.rt_mut().handlers);
let (startup_tx, startup_rx) = tokio::sync::oneshot::channel();
self.rt_mut().notif_handle = Some(tokio::spawn(
notif::supervisor(notif_fd, ctx, extra_handlers, startup_tx),
notif::supervisor(notif_fd, ctx, handlers, startup_tx),
));
// Wait for the supervisor to register the notif fd with the IO
// driver before we release the child to execve. Otherwise an
Expand Down Expand Up @@ -1696,8 +1696,8 @@ fn sandbox_wait_status_to_exit(status: i32) -> crate::result::ExitStatus {
}
}

fn sandbox_collect_extra_handlers<I, S, H>(
extra_handlers: I,
fn sandbox_collect_handlers<I, S, H>(
handlers: I,
sandbox: &Sandbox,
) -> Result<Vec<(i64, Arc<dyn crate::seccomp::dispatch::Handler>)>, crate::error::SandlockError>
where
Expand All @@ -1707,7 +1707,7 @@ where
{
use crate::seccomp::dispatch::{Handler, HandlerError};

let pending: Vec<(i64, Arc<dyn Handler>)> = extra_handlers
let pending: Vec<(i64, Arc<dyn Handler>)> = handlers
.into_iter()
.map(|(syscall, handler)| {
let nr = syscall.try_into().map_err(HandlerError::from)?.raw();
Expand Down
18 changes: 9 additions & 9 deletions crates/sandlock-core/src/seccomp/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ use tokio::sync::Mutex;
/// Public extension trait for sandlock seccomp-notif handlers.
///
/// Each implementor is registered against a [`crate::seccomp::syscall::Syscall`]
/// through [`crate::Sandbox::run_with_extra_handlers`] /
/// [`crate::Sandbox::run_interactive_with_extra_handlers`]. Receives
/// through [`crate::Sandbox::run_with_handlers`] /
/// [`crate::Sandbox::run_interactive_with_handlers`]. Receives
/// `&HandlerCtx` borrowed for the call; cannot outlive the dispatch
/// invocation.
///
Expand Down Expand Up @@ -99,7 +99,7 @@ where
// Concrete impls for `Box<dyn Handler>` and `Arc<dyn Handler>` so callers
// can erase concrete handler types behind a smart pointer when mixing
// different handler shapes in one `IntoIterator` passed to
// `run_with_extra_handlers` — e.g. `Vec<(i64, Box<dyn Handler>)>` lets a
// `run_with_handlers` — e.g. `Vec<(i64, Box<dyn Handler>)>` lets a
// downstream register handlers of different concrete types without
// writing a per-crate wrapper enum.
//
Expand All @@ -126,7 +126,7 @@ impl Handler for std::sync::Arc<dyn Handler> {
}

/// Errors raised when registering user handlers via
/// [`crate::Sandbox::run_with_extra_handlers`].
/// [`crate::Sandbox::run_with_handlers`].
#[derive(Debug, Error, PartialEq, Eq)]
pub enum HandlerError {
#[error("invalid syscall in handler registration: {0}")]
Expand All @@ -153,7 +153,7 @@ pub enum HandlerError {
/// resolves from Sandlock's default syscall blocklist plus policy extras.
///
/// Takes only the syscall numbers because that's all it needs to check.
/// Called from the `run_with_extra_handlers` entry points before any
/// Called from the `run_with_handlers` entry points before any
/// handler is registered against the dispatch table.
///
/// Returns the offending syscall number on rejection so the caller can
Expand Down Expand Up @@ -203,7 +203,7 @@ impl DispatchTable {
/// Register a pre-`Arc`'d handler. Used both by builtin chunks
/// that share state via `Arc::clone` (one `ForkHandler` instance
/// registers against `SYS_clone`/`SYS_clone3`/`SYS_vfork`) and by
/// `run_with_extra_handlers` when each item already arrives as
/// `run_with_handlers` when each item already arrives as
/// `Arc<dyn Handler>`.
pub(crate) fn register_arc(
&mut self,
Expand Down Expand Up @@ -942,7 +942,7 @@ fn register_cow_handlers(table: &mut DispatchTable, ctx: &Arc<SupervisorCtx>) {
// ============================================================

#[cfg(test)]
mod extra_handler_tests {
mod handler_tests {
//! Unit tests for the user-supplied handler extension API.
//!
//! Drive the actual `DispatchTable::dispatch` walker against a minimal
Expand All @@ -952,7 +952,7 @@ mod extra_handler_tests {
//! short-circuit on first non-`Continue`, append-after-builtin
//! placement) are exercised end-to-end without needing a live
//! Landlock+seccomp sandbox — those scenarios live under
//! `crates/sandlock-core/tests/integration/test_extra_handlers.rs`.
//! `crates/sandlock-core/tests/integration/test_handlers.rs`.
use super::*;
use crate::netlink::NetlinkState;
use crate::seccomp::ctx::SupervisorCtx;
Expand Down Expand Up @@ -1175,7 +1175,7 @@ mod extra_handler_tests {
/// `DEFAULT_BLOCKLIST_SYSCALLS` — putting it into `extra_deny_syscalls` is the only
/// way it ends up on the extra blocklist, so the test isolates the user-supplied
/// path of `blocklist_syscall_numbers` from the default branch covered by
/// `extra_handler_on_default_blocklist_syscall_is_rejected`.
/// `handler_on_default_blocklist_syscall_is_rejected`.
///
/// Pure-logic counterpart to the integration test of the same name —
/// runs without a live sandbox so the contract is enforced even on
Expand Down
2 changes: 1 addition & 1 deletion crates/sandlock-core/src/seccomp/notif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ pub struct NotifPolicy {
pub has_time_start: bool,
/// Argv-safety gate: the supervisor must freeze every task that
/// could mutate argv before any consumer reads it. True when
/// `policy_fn` is active or when an extra handler is bound to
/// `policy_fn` is active or when a handler is bound to
/// execve/execveat (such handlers can call `read_child_mem`).
/// Also gates ptrace fork-event tracking so `ProcessIndex` is
/// complete when the freeze enumerates it.
Expand Down
4 changes: 2 additions & 2 deletions crates/sandlock-core/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ mod test_dry_run;
#[path = "integration/test_http_acl.rs"]
mod test_http_acl;

#[path = "integration/test_extra_handlers.rs"]
mod test_extra_handlers;
#[path = "integration/test_handlers.rs"]
mod test_handlers;
Loading
Loading