security: add seccomp server presets
Jaime Fournier <jaimef@linbsd.org>
1692077b6f99bcaaf7f0b674e05416149e9fd83e
--- a/docs/kimi3-security-recommmendations.md +++ b/docs/kimi3-security-recommmendations.md @@ -723,6 +723,12 @@ Chez cannot heap-cap a thread; `run-safe-eval` rightly refuses audit logs and the release-evidence bundle). - **Accept:** per-platform CI smoke for each mechanism; presets used by P0-02 worker tests. +- **Status:** partially complete. The seccomp preset gap is closed for the + supported syscall tables: `(std security seccomp)` now exports + `http-server-filter`, `dns-server-filter`, and `worker-eval-filter`, and + `(std security sandbox)` accepts `'http-server`, `'dns-server`, and + `'worker-eval` seccomp specs. Native per-platform CI parity and a dedicated + runtime `sandbox-report` entry point remain open. ### K3-P1-09 — Confused-deputy defenses: capability plans enforced at runtime **Serves:** G2. **Effort:** 1 week. --- a/docs/security-reference.md +++ b/docs/security-reference.md @@ -339,7 +339,9 @@ Linux syscall filtering via real BPF bytecode. Generates actual `sock_filter` pr - `(seccomp-available?)` -- check kernel support - `(make-seccomp-filter default-action: action allowed: syscall-list)` -- create a filter - `(seccomp-install! filter)` -- install filter (irreversible) -- Pre-built filters: `compute-only-filter`, `io-only-filter`, `network-server-filter` +- Pre-built filters: `compute-only-filter`, `io-only-filter`, + `network-server-filter`, `http-server-filter`, `dns-server-filter`, + `worker-eval-filter` - Actions: `seccomp-kill`, `seccomp-trap`, `seccomp-errno`, `seccomp-log` BPF program structure: validate architecture, load syscall number, check against allowed list, apply default action for non-matching syscalls. --- a/lib/std/security/sandbox.ss +++ b/lib/std/security/sandbox.ss @@ -241,8 +241,11 @@ [(eq? spec 'compute-only) compute-only-filter] [(eq? spec 'io-only) io-only-filter] [(eq? spec 'network-server) network-server-filter] + [(eq? spec 'http-server) http-server-filter] + [(eq? spec 'dns-server) dns-server-filter] + [(eq? spec 'worker-eval) worker-eval-filter] [else (error 'run-safe - "invalid seccomp spec; expected #f, 'compute-only, 'io-only, 'network-server, or seccomp-filter" + "invalid seccomp spec; expected #f, 'compute-only, 'io-only, 'network-server, 'http-server, 'dns-server, 'worker-eval, or seccomp-filter" spec)])) ;; ========== Seatbelt profile resolution (macOS) ========== --- a/lib/std/security/seccomp.ss +++ b/lib/std/security/seccomp.ss @@ -26,6 +26,9 @@ ;; Pre-built filters compute-only-filter network-server-filter + http-server-filter + dns-server-filter + worker-eval-filter io-only-filter dangerous-syscalls safe-blocklist @@ -506,6 +509,25 @@ ;; File I/O 'openat 'newfstatat 'getdents 'access)) + (def http-server-filter network-server-filter) + + (def dns-server-filter + (make-seccomp-filter seccomp-kill + ;; Compute basics + 'read 'write 'close 'fstat 'mmap 'mprotect + 'munmap 'brk 'rt_sigaction 'rt_sigprocmask 'rt_sigreturn + 'clone 'exit_group 'futex 'nanosleep + 'getrandom 'arch_prctl 'set_tid_address + 'set_robust_list 'sched_yield 'sigaltstack + 'clock_gettime 'prctl 'prlimit64 'rseq 'close_range + ;; DNS server/client UDP and TCP fallback using known syscall-table names + 'socket 'connect 'sendto 'recvfrom + 'bind 'listen 'accept 'getsockname 'setsockopt + 'select 'ioctl 'fcntl + 'epoll_create1 'epoll_ctl 'epoll_wait)) + + (def worker-eval-filter compute-only-filter) + (def io-only-filter (make-seccomp-filter seccomp-kill 'read 'write 'close 'fstat 'mmap 'mprotect --- a/tests/test-phase5-os.ss +++ b/tests/test-phase5-os.ss @@ -44,6 +44,15 @@ (test "seccomp: make network-server filter" (seccomp-filter? network-server-filter)) +(test "seccomp: make http-server filter" + (seccomp-filter? http-server-filter)) + +(test "seccomp: make dns-server filter" + (seccomp-filter? dns-server-filter)) + +(test "seccomp: make worker-eval filter" + (seccomp-filter? worker-eval-filter)) + (test "seccomp: make io-only filter" (seccomp-filter? io-only-filter)) --- a/tests/test-seccomp.ss +++ b/tests/test-seccomp.ss @@ -55,6 +55,18 @@ (seccomp-filter? network-server-filter) #t) +(test "http-server-filter is a filter" + (seccomp-filter? http-server-filter) + #t) + +(test "dns-server-filter is a filter" + (seccomp-filter? dns-server-filter) + #t) + +(test "worker-eval-filter is a filter" + (seccomp-filter? worker-eval-filter) + #t) + (test "io-only-filter is a filter" (seccomp-filter? io-only-filter) #t) @@ -68,6 +80,26 @@ (length (seccomp-filter-allowed-syscalls compute-only-filter))) #t) +(test "http-server-filter includes listener syscalls" + (and (memq 'socket (seccomp-filter-allowed-syscalls http-server-filter)) + (memq 'bind (seccomp-filter-allowed-syscalls http-server-filter)) + (memq 'listen (seccomp-filter-allowed-syscalls http-server-filter)) + (memq 'accept (seccomp-filter-allowed-syscalls http-server-filter)) + #t) + #t) + +(test "dns-server-filter includes DNS transport syscalls" + (and (memq 'socket (seccomp-filter-allowed-syscalls dns-server-filter)) + (memq 'sendto (seccomp-filter-allowed-syscalls dns-server-filter)) + (memq 'recvfrom (seccomp-filter-allowed-syscalls dns-server-filter)) + (memq 'bind (seccomp-filter-allowed-syscalls dns-server-filter)) + #t) + #t) + +(test "worker-eval-filter excludes network syscalls" + (not (memq 'socket (seccomp-filter-allowed-syscalls worker-eval-filter))) + #t) + ;; ========== Availability ========== (printf "~%-- Availability --~%")