Lion Cipher Lab
Build a syscall sandbox from scratch with seccomp-BPF
- Cyber / Security Engineer
- Advanced
- ~75 min
- Free · no account required
Why it matters
Every meaningful thing a program does — read a file, open a socket, start a process, allocate memory — is a syscall: a request across the boundary from userspace into the kernel. That boundary is also the attack surface. A huge share of privilege-escalation and container-escape exploits work by reaching a buggy or dangerous syscall the program never actually needed. seccomp (SECure COMPuting) is the kernel's answer: a process installs a filter, and the kernel consults it on EVERY syscall, deciding to allow it, fake an error, trap it, log it, or kill the process. Shrinking the set of syscalls…
What you'll learn
- what a syscall is and where seccomp sits: a kernel-enforced filter consulted on every syscall a process makes
- the seccomp actions ALLOW / ERRNO / TRAP / KILL / LOG and strict mode vs FILTER (BPF) mode
- writing a default-deny syscall allowlist in C the easy way with libseccomp (seccomp_init / seccomp_rule_add / seccomp_load)
- proving confinement dynamically: an allowed workload completes, a forbidden syscall trips SIGSYS and kills the process
- reading the kill: seeing the SIGSYS audit line in dmesg/journalctl and the killed syscall in strace
- hand-building a raw seccomp-BPF filter: load the nr from struct seccomp_data, ALLOW by BPF_JEQ, default SECCOMP_RET_KILL_PROCESS
- the mandatory architecture check (AUDIT_ARCH_X86_64) that defeats the x32/ABI-confusion bypass
- prctl(PR_SET_NO_NEW_PRIVS) + prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER) to install the filter unprivileged
- the named failure modes: missing NO_NEW_PRIVS, the ABI bypass, TOCTOU on pointer args, blocking a libc-needed syscall, KILL_PROCESS vs KILL_THREAD
- the judgment of when to reach for seccomp, why it reduces kernel attack surface, and when NOT to hand-roll it in production
Steps in this lab
- What a syscall is, and what seccomp does about it
- Set up a scratch box and tools
- The easy path: a default-deny allowlist with libseccomp
- Prove it dynamically: run it, watch SIGSYS, read the audit line
- The raw path: hand-build the seccomp-BPF filter
- The named failure modes (this is the advanced part)
- The judgment: when to reach for seccomp — and when NOT to hand-roll it