sandbox_rs/isolation/
seccomp_bpf.rs

1//! Seccomp BPF filter compilation and loading using seccompiler
2
3use super::seccomp::SeccompFilter;
4use crate::errors::{Result, SandboxError};
5use log::warn;
6use seccompiler::{BpfProgram, SeccompAction, SeccompFilter as SeccompilerFilter, apply_filter};
7use std::collections::BTreeMap;
8use std::convert::TryInto;
9
10/// Seccomp BPF filter compiler and loader
11pub struct SeccompBpf;
12
13impl SeccompBpf {
14    /// Compile a filter to BPF bytecode
15    pub fn compile(filter: &SeccompFilter) -> Result<Vec<u8>> {
16        let bpf_program = Self::compile_to_bpf(filter)?;
17        let bpf_bytes: Vec<u8> = unsafe {
18            let ptr = bpf_program.as_ptr() as *const u8;
19            let len = bpf_program.len() * std::mem::size_of::<seccompiler::sock_filter>();
20            std::slice::from_raw_parts(ptr, len).to_vec()
21        };
22        Ok(bpf_bytes)
23    }
24
25    /// Compile filter to BpfProgram with validation
26    fn compile_to_bpf(filter: &SeccompFilter) -> Result<BpfProgram> {
27        filter.validate()?;
28
29        let allowed = filter.allowed_syscalls();
30        let blocked = filter.blocked_syscalls();
31        let mut rules: BTreeMap<i64, Vec<seccompiler::SeccompRule>> = BTreeMap::new();
32        let is_unrestricted = filter.profile() == super::seccomp::SeccompProfile::Unrestricted;
33
34        if is_unrestricted {
35            for syscall_name in blocked.iter() {
36                match get_syscall_number_from_name(syscall_name) {
37                    Some(num) => {
38                        rules.entry(num).or_default();
39                    }
40                    None => {
41                        if filter.allows_unknown_syscalls() {
42                            warn!("Unknown syscall '{}' in block list (ignored)", syscall_name);
43                        } else {
44                            return Err(SandboxError::Seccomp(format!(
45                                "Unknown syscall to block: '{}'. This syscall is not supported on this architecture.",
46                                syscall_name
47                            )));
48                        }
49                    }
50                }
51            }
52        } else {
53            for syscall_name in allowed.iter() {
54                if blocked.contains(syscall_name) {
55                    continue;
56                }
57
58                match get_syscall_number_from_name(syscall_name) {
59                    Some(num) => {
60                        rules.entry(num).or_default();
61                    }
62                    None => {
63                        if filter.allows_unknown_syscalls() {
64                            warn!("Unknown syscall '{}' in allow list (ignored)", syscall_name);
65                        } else {
66                            return Err(SandboxError::Seccomp(format!(
67                                "Unknown syscall to allow: '{}'. This syscall is not supported on this architecture.",
68                                syscall_name
69                            )));
70                        }
71                    }
72                }
73            }
74        }
75
76        // Configure actions based on mode
77        let (mismatch_action, match_action) = if is_unrestricted {
78            (SeccompAction::Allow, SeccompAction::Trap)
79        } else {
80            let deny_action = if filter.is_kill_on_violation() {
81                SeccompAction::KillProcess
82            } else {
83                SeccompAction::Trap
84            };
85            (deny_action, SeccompAction::Allow)
86        };
87
88        let seccompiler_filter = SeccompilerFilter::new(
89            rules,
90            mismatch_action,
91            match_action,
92            seccompiler::TargetArch::x86_64,
93        )
94        .map_err(|e| SandboxError::Seccomp(format!("Failed to create filter: {}", e)))?;
95
96        let bpf_program: BpfProgram = seccompiler_filter
97            .try_into()
98            .map_err(|e| SandboxError::Seccomp(format!("Failed to compile filter: {}", e)))?;
99
100        Ok(bpf_program)
101    }
102
103    /// Load BPF filter via seccompiler's apply_filter
104    pub fn load(filter: &SeccompFilter) -> Result<()> {
105        filter.validate()?;
106        unsafe {
107            if libc::prctl(libc::PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0 {
108                return Err(SandboxError::Seccomp(format!(
109                    "Failed to set PR_SET_NO_NEW_PRIVS: {}",
110                    std::io::Error::last_os_error()
111                )));
112            }
113        }
114
115        let bpf_program = Self::compile_to_bpf(filter)?;
116
117        apply_filter(&bpf_program)
118            .map_err(|e| SandboxError::Seccomp(format!("Failed to apply seccomp filter: {}", e)))?;
119
120        Ok(())
121    }
122}
123
124/// Get syscall number from name using libc constants
125fn get_syscall_number_from_name(name: &str) -> Option<i64> {
126    match name {
127        "read" => Some(libc::SYS_read),
128        "write" => Some(libc::SYS_write),
129        "open" => Some(libc::SYS_open),
130        "close" => Some(libc::SYS_close),
131        "stat" => Some(libc::SYS_stat),
132        "fstat" => Some(libc::SYS_fstat),
133        "lstat" => Some(libc::SYS_lstat),
134        "poll" => Some(libc::SYS_poll),
135        "lseek" => Some(libc::SYS_lseek),
136        "mmap" => Some(libc::SYS_mmap),
137        "mprotect" => Some(libc::SYS_mprotect),
138        "munmap" => Some(libc::SYS_munmap),
139        "brk" => Some(libc::SYS_brk),
140        "rt_sigaction" => Some(libc::SYS_rt_sigaction),
141        "rt_sigprocmask" => Some(libc::SYS_rt_sigprocmask),
142        "rt_sigpending" => Some(libc::SYS_rt_sigpending),
143        "rt_sigtimedwait" => Some(libc::SYS_rt_sigtimedwait),
144        "rt_sigqueueinfo" => Some(libc::SYS_rt_sigqueueinfo),
145        "rt_sigreturn" => Some(libc::SYS_rt_sigreturn),
146        "ioctl" => Some(libc::SYS_ioctl),
147        "pread64" => Some(libc::SYS_pread64),
148        "pwrite64" => Some(libc::SYS_pwrite64),
149        "readv" => Some(libc::SYS_readv),
150        "writev" => Some(libc::SYS_writev),
151        "access" => Some(libc::SYS_access),
152        "pipe" => Some(libc::SYS_pipe),
153        "select" => Some(libc::SYS_select),
154        "sched_yield" => Some(libc::SYS_sched_yield),
155        "mremap" => Some(libc::SYS_mremap),
156        "msync" => Some(libc::SYS_msync),
157        "mincore" => Some(libc::SYS_mincore),
158        "madvise" => Some(libc::SYS_madvise),
159        "shmget" => Some(libc::SYS_shmget),
160        "shmat" => Some(libc::SYS_shmat),
161        "shmctl" => Some(libc::SYS_shmctl),
162        "dup" => Some(libc::SYS_dup),
163        "dup2" => Some(libc::SYS_dup2),
164        "pause" => Some(libc::SYS_pause),
165        "nanosleep" => Some(libc::SYS_nanosleep),
166        "getitimer" => Some(libc::SYS_getitimer),
167        "alarm" => Some(libc::SYS_alarm),
168        "setitimer" => Some(libc::SYS_setitimer),
169        "getpid" => Some(libc::SYS_getpid),
170        "sendfile" => Some(libc::SYS_sendfile),
171        "socket" => Some(libc::SYS_socket),
172        "connect" => Some(libc::SYS_connect),
173        "accept" => Some(libc::SYS_accept),
174        "sendto" => Some(libc::SYS_sendto),
175        "recvfrom" => Some(libc::SYS_recvfrom),
176        "sendmsg" => Some(libc::SYS_sendmsg),
177        "recvmsg" => Some(libc::SYS_recvmsg),
178        "shutdown" => Some(libc::SYS_shutdown),
179        "bind" => Some(libc::SYS_bind),
180        "listen" => Some(libc::SYS_listen),
181        "getsockname" => Some(libc::SYS_getsockname),
182        "getpeername" => Some(libc::SYS_getpeername),
183        "socketpair" => Some(libc::SYS_socketpair),
184        "setsockopt" => Some(libc::SYS_setsockopt),
185        "getsockopt" => Some(libc::SYS_getsockopt),
186        "clone" => Some(libc::SYS_clone),
187        "fork" => Some(libc::SYS_fork),
188        "vfork" => Some(libc::SYS_vfork),
189        "execve" => Some(libc::SYS_execve),
190        "exit" => Some(libc::SYS_exit),
191        "wait4" => Some(libc::SYS_wait4),
192        "waitpid" => Some(libc::SYS_wait4),
193        "kill" => Some(libc::SYS_kill),
194        "uname" => Some(libc::SYS_uname),
195        "fcntl" => Some(libc::SYS_fcntl),
196        "flock" => Some(libc::SYS_flock),
197        "fsync" => Some(libc::SYS_fsync),
198        "fdatasync" => Some(libc::SYS_fdatasync),
199        "truncate" => Some(libc::SYS_truncate),
200        "ftruncate" => Some(libc::SYS_ftruncate),
201        "getdents" => Some(libc::SYS_getdents),
202        "getcwd" => Some(libc::SYS_getcwd),
203        "chdir" => Some(libc::SYS_chdir),
204        "fchdir" => Some(libc::SYS_fchdir),
205        "rename" => Some(libc::SYS_rename),
206        "mkdir" => Some(libc::SYS_mkdir),
207        "rmdir" => Some(libc::SYS_rmdir),
208        "creat" => Some(libc::SYS_creat),
209        "link" => Some(libc::SYS_link),
210        "unlink" => Some(libc::SYS_unlink),
211        "symlink" => Some(libc::SYS_symlink),
212        "readlink" => Some(libc::SYS_readlink),
213        "chmod" => Some(libc::SYS_chmod),
214        "fchmod" => Some(libc::SYS_fchmod),
215        "chown" => Some(libc::SYS_chown),
216        "fchown" => Some(libc::SYS_fchown),
217        "lchown" => Some(libc::SYS_lchown),
218        "umask" => Some(libc::SYS_umask),
219        "gettimeofday" => Some(libc::SYS_gettimeofday),
220        "getrlimit" => Some(libc::SYS_getrlimit),
221        "getrusage" => Some(libc::SYS_getrusage),
222        "sysinfo" => Some(libc::SYS_sysinfo),
223        "times" => Some(libc::SYS_times),
224        "ptrace" => Some(libc::SYS_ptrace),
225        "getuid" => Some(libc::SYS_getuid),
226        "syslog" => Some(libc::SYS_syslog),
227        "getgid" => Some(libc::SYS_getgid),
228        "setuid" => Some(libc::SYS_setuid),
229        "setgid" => Some(libc::SYS_setgid),
230        "geteuid" => Some(libc::SYS_geteuid),
231        "getegid" => Some(libc::SYS_getegid),
232        "setpgid" => Some(libc::SYS_setpgid),
233        "getppid" => Some(libc::SYS_getppid),
234        "getpgrp" => Some(libc::SYS_getpgrp),
235        "setsid" => Some(libc::SYS_setsid),
236        "setreuid" => Some(libc::SYS_setreuid),
237        "setregid" => Some(libc::SYS_setregid),
238        "getgroups" => Some(libc::SYS_getgroups),
239        "setgroups" => Some(libc::SYS_setgroups),
240        "setresuid" => Some(libc::SYS_setresuid),
241        "getresuid" => Some(libc::SYS_getresuid),
242        "setresgid" => Some(libc::SYS_setresgid),
243        "getresgid" => Some(libc::SYS_getresgid),
244        "getpgid" => Some(libc::SYS_getpgid),
245        "setfsuid" => Some(libc::SYS_setfsuid),
246        "setfsgid" => Some(libc::SYS_setfsgid),
247        "getsid" => Some(libc::SYS_getsid),
248        "capget" => Some(libc::SYS_capget),
249        "capset" => Some(libc::SYS_capset),
250        "rt_sigsuspend" => Some(libc::SYS_rt_sigsuspend),
251        "sigaltstack" => Some(libc::SYS_sigaltstack),
252        "utime" => Some(libc::SYS_utime),
253        "mknod" => Some(libc::SYS_mknod),
254        "uselib" => Some(libc::SYS_uselib),
255        "personality" => Some(libc::SYS_personality),
256        "ustat" => Some(libc::SYS_ustat),
257        "statfs" => Some(libc::SYS_statfs),
258        "fstatfs" => Some(libc::SYS_fstatfs),
259        "sysfs" => Some(libc::SYS_sysfs),
260        "getpriority" => Some(libc::SYS_getpriority),
261        "setpriority" => Some(libc::SYS_setpriority),
262        "sched_setparam" => Some(libc::SYS_sched_setparam),
263        "sched_getparam" => Some(libc::SYS_sched_getparam),
264        "sched_setscheduler" => Some(libc::SYS_sched_setscheduler),
265        "sched_getscheduler" => Some(libc::SYS_sched_getscheduler),
266        "sched_get_priority_max" => Some(libc::SYS_sched_get_priority_max),
267        "sched_get_priority_min" => Some(libc::SYS_sched_get_priority_min),
268        "sched_rr_get_interval" => Some(libc::SYS_sched_rr_get_interval),
269        "mlock" => Some(libc::SYS_mlock),
270        "munlock" => Some(libc::SYS_munlock),
271        "mlockall" => Some(libc::SYS_mlockall),
272        "munlockall" => Some(libc::SYS_munlockall),
273        "vhangup" => Some(libc::SYS_vhangup),
274        "modify_ldt" => Some(libc::SYS_modify_ldt),
275        "_sysctl" => Some(libc::SYS__sysctl),
276        "prctl" => Some(libc::SYS_prctl),
277        "arch_prctl" => Some(libc::SYS_arch_prctl),
278        "adjtimex" => Some(libc::SYS_adjtimex),
279        "setrlimit" => Some(libc::SYS_setrlimit),
280        "chroot" => Some(libc::SYS_chroot),
281        "sync" => Some(libc::SYS_sync),
282        "acct" => Some(libc::SYS_acct),
283        "settimeofday" => Some(libc::SYS_settimeofday),
284        "mount" => Some(libc::SYS_mount),
285        "pivot_root" => Some(libc::SYS_pivot_root),
286        "umount2" => Some(libc::SYS_umount2),
287        "swapon" => Some(libc::SYS_swapon),
288        "swapoff" => Some(libc::SYS_swapoff),
289        "reboot" => Some(libc::SYS_reboot),
290        "sethostname" => Some(libc::SYS_sethostname),
291        "setdomainname" => Some(libc::SYS_setdomainname),
292        "iopl" => Some(libc::SYS_iopl),
293        "ioperm" => Some(libc::SYS_ioperm),
294        "init_module" => Some(libc::SYS_init_module),
295        "delete_module" => Some(libc::SYS_delete_module),
296        "quotactl" => Some(libc::SYS_quotactl),
297        "nfsservctl" => Some(libc::SYS_nfsservctl),
298        "getpmsg" => Some(libc::SYS_getpmsg),
299        "putpmsg" => Some(libc::SYS_putpmsg),
300        "afs_syscall" => Some(libc::SYS_afs_syscall),
301        "tuxcall" => Some(libc::SYS_tuxcall),
302        "security" => Some(libc::SYS_security),
303        "gettid" => Some(libc::SYS_gettid),
304        "readahead" => Some(libc::SYS_readahead),
305        "setxattr" => Some(libc::SYS_setxattr),
306        "lsetxattr" => Some(libc::SYS_lsetxattr),
307        "fsetxattr" => Some(libc::SYS_fsetxattr),
308        "getxattr" => Some(libc::SYS_getxattr),
309        "lgetxattr" => Some(libc::SYS_lgetxattr),
310        "fgetxattr" => Some(libc::SYS_fgetxattr),
311        "listxattr" => Some(libc::SYS_listxattr),
312        "llistxattr" => Some(libc::SYS_llistxattr),
313        "flistxattr" => Some(libc::SYS_flistxattr),
314        "removexattr" => Some(libc::SYS_removexattr),
315        "lremovexattr" => Some(libc::SYS_lremovexattr),
316        "fremovexattr" => Some(libc::SYS_fremovexattr),
317        "tkill" => Some(libc::SYS_tkill),
318        "time" => Some(libc::SYS_time),
319        "futex" => Some(libc::SYS_futex),
320        "sched_setaffinity" => Some(libc::SYS_sched_setaffinity),
321        "sched_getaffinity" => Some(libc::SYS_sched_getaffinity),
322        "set_thread_area" => Some(libc::SYS_set_thread_area),
323        "io_setup" => Some(libc::SYS_io_setup),
324        "io_destroy" => Some(libc::SYS_io_destroy),
325        "io_getevents" => Some(libc::SYS_io_getevents),
326        "io_submit" => Some(libc::SYS_io_submit),
327        "io_cancel" => Some(libc::SYS_io_cancel),
328        "get_thread_area" => Some(libc::SYS_get_thread_area),
329        "lookup_dcookie" => Some(libc::SYS_lookup_dcookie),
330        "epoll_create" => Some(libc::SYS_epoll_create),
331        "epoll_ctl_old" => Some(libc::SYS_epoll_ctl_old),
332        "epoll_wait_old" => Some(libc::SYS_epoll_wait_old),
333        "remap_file_pages" => Some(libc::SYS_remap_file_pages),
334        "getdents64" => Some(libc::SYS_getdents64),
335        "set_tid_address" => Some(libc::SYS_set_tid_address),
336        "restart_syscall" => Some(libc::SYS_restart_syscall),
337        "semtimedop" => Some(libc::SYS_semtimedop),
338        "fadvise64" => Some(libc::SYS_fadvise64),
339        "timer_create" => Some(libc::SYS_timer_create),
340        "timer_settime" => Some(libc::SYS_timer_settime),
341        "timer_gettime" => Some(libc::SYS_timer_gettime),
342        "timer_getoverrun" => Some(libc::SYS_timer_getoverrun),
343        "timer_delete" => Some(libc::SYS_timer_delete),
344        "clock_settime" => Some(libc::SYS_clock_settime),
345        "clock_gettime" => Some(libc::SYS_clock_gettime),
346        "clock_getres" => Some(libc::SYS_clock_getres),
347        "clock_nanosleep" => Some(libc::SYS_clock_nanosleep),
348        "exit_group" => Some(libc::SYS_exit_group),
349        "epoll_wait" => Some(libc::SYS_epoll_wait),
350        "epoll_ctl" => Some(libc::SYS_epoll_ctl),
351        "tgkill" => Some(libc::SYS_tgkill),
352        "utimes" => Some(libc::SYS_utimes),
353        "vserver" => Some(libc::SYS_vserver),
354        "mbind" => Some(libc::SYS_mbind),
355        "set_mempolicy" => Some(libc::SYS_set_mempolicy),
356        "get_mempolicy" => Some(libc::SYS_get_mempolicy),
357        "mq_open" => Some(libc::SYS_mq_open),
358        "mq_unlink" => Some(libc::SYS_mq_unlink),
359        "mq_timedsend" => Some(libc::SYS_mq_timedsend),
360        "mq_timedreceive" => Some(libc::SYS_mq_timedreceive),
361        "mq_notify" => Some(libc::SYS_mq_notify),
362        "mq_getsetattr" => Some(libc::SYS_mq_getsetattr),
363        "kexec_load" => Some(libc::SYS_kexec_load),
364        "waitid" => Some(libc::SYS_waitid),
365        "add_key" => Some(libc::SYS_add_key),
366        "request_key" => Some(libc::SYS_request_key),
367        "keyctl" => Some(libc::SYS_keyctl),
368        "ioprio_set" => Some(libc::SYS_ioprio_set),
369        "ioprio_get" => Some(libc::SYS_ioprio_get),
370        "inotify_init" => Some(libc::SYS_inotify_init),
371        "inotify_add_watch" => Some(libc::SYS_inotify_add_watch),
372        "inotify_rm_watch" => Some(libc::SYS_inotify_rm_watch),
373        "migrate_pages" => Some(libc::SYS_migrate_pages),
374        "openat" => Some(libc::SYS_openat),
375        "mkdirat" => Some(libc::SYS_mkdirat),
376        "mknodat" => Some(libc::SYS_mknodat),
377        "fchownat" => Some(libc::SYS_fchownat),
378        "futimesat" => Some(libc::SYS_futimesat),
379        "newfstatat" => Some(libc::SYS_newfstatat),
380        "unlinkat" => Some(libc::SYS_unlinkat),
381        "renameat" => Some(libc::SYS_renameat),
382        "linkat" => Some(libc::SYS_linkat),
383        "symlinkat" => Some(libc::SYS_symlinkat),
384        "readlinkat" => Some(libc::SYS_readlinkat),
385        "fchmodat" => Some(libc::SYS_fchmodat),
386        "faccessat" => Some(libc::SYS_faccessat),
387        "pselect6" => Some(libc::SYS_pselect6),
388        "ppoll" => Some(libc::SYS_ppoll),
389        "unshare" => Some(libc::SYS_unshare),
390        "set_robust_list" => Some(libc::SYS_set_robust_list),
391        "get_robust_list" => Some(libc::SYS_get_robust_list),
392        "splice" => Some(libc::SYS_splice),
393        "tee" => Some(libc::SYS_tee),
394        "sync_file_range" => Some(libc::SYS_sync_file_range),
395        "vmsplice" => Some(libc::SYS_vmsplice),
396        "move_pages" => Some(libc::SYS_move_pages),
397        "utimensat" => Some(libc::SYS_utimensat),
398        "epoll_pwait" => Some(libc::SYS_epoll_pwait),
399        "signalfd" => Some(libc::SYS_signalfd),
400        "timerfd_create" => Some(libc::SYS_timerfd_create),
401        "eventfd" => Some(libc::SYS_eventfd),
402        "fallocate" => Some(libc::SYS_fallocate),
403        "timerfd_settime" => Some(libc::SYS_timerfd_settime),
404        "timerfd_gettime" => Some(libc::SYS_timerfd_gettime),
405        "accept4" => Some(libc::SYS_accept4),
406        "signalfd4" => Some(libc::SYS_signalfd4),
407        "eventfd2" => Some(libc::SYS_eventfd2),
408        "epoll_create1" => Some(libc::SYS_epoll_create1),
409        "dup3" => Some(libc::SYS_dup3),
410        "pipe2" => Some(libc::SYS_pipe2),
411        "inotify_init1" => Some(libc::SYS_inotify_init1),
412        "preadv" => Some(libc::SYS_preadv),
413        "pwritev" => Some(libc::SYS_pwritev),
414        "rt_tgsigqueueinfo" => Some(libc::SYS_rt_tgsigqueueinfo),
415        "perf_event_open" => Some(libc::SYS_perf_event_open),
416        "recvmmsg" => Some(libc::SYS_recvmmsg),
417        "fanotify_init" => Some(libc::SYS_fanotify_init),
418        "fanotify_mark" => Some(libc::SYS_fanotify_mark),
419        "prlimit64" => Some(libc::SYS_prlimit64),
420        "name_to_handle_at" => Some(libc::SYS_name_to_handle_at),
421        "open_by_handle_at" => Some(libc::SYS_open_by_handle_at),
422        "clock_adjtime" => Some(libc::SYS_clock_adjtime),
423        "syncfs" => Some(libc::SYS_syncfs),
424        "sendmmsg" => Some(libc::SYS_sendmmsg),
425        "setns" => Some(libc::SYS_setns),
426        "getcpu" => Some(libc::SYS_getcpu),
427        "process_vm_readv" => Some(libc::SYS_process_vm_readv),
428        "process_vm_writev" => Some(libc::SYS_process_vm_writev),
429        "kcmp" => Some(libc::SYS_kcmp),
430        "finit_module" => Some(libc::SYS_finit_module),
431        "sched_setattr" => Some(libc::SYS_sched_setattr),
432        "sched_getattr" => Some(libc::SYS_sched_getattr),
433        "renameat2" => Some(libc::SYS_renameat2),
434        "seccomp" => Some(libc::SYS_seccomp),
435        "getrandom" => Some(libc::SYS_getrandom),
436        "memfd_create" => Some(libc::SYS_memfd_create),
437        "kexec_file_load" => Some(libc::SYS_kexec_file_load),
438        "bpf" => Some(libc::SYS_bpf),
439        "execveat" => Some(libc::SYS_execveat),
440        "userfaultfd" => Some(libc::SYS_userfaultfd),
441        "membarrier" => Some(libc::SYS_membarrier),
442        "mlock2" => Some(libc::SYS_mlock2),
443        "copy_file_range" => Some(libc::SYS_copy_file_range),
444        "preadv2" => Some(libc::SYS_preadv2),
445        "pwritev2" => Some(libc::SYS_pwritev2),
446        "pkey_mprotect" => Some(libc::SYS_pkey_mprotect),
447        "pkey_alloc" => Some(libc::SYS_pkey_alloc),
448        "pkey_free" => Some(libc::SYS_pkey_free),
449        "statx" => Some(libc::SYS_statx),
450        "rseq" => Some(libc::SYS_rseq),
451        "pidfd_send_signal" => Some(libc::SYS_pidfd_send_signal),
452        "io_uring_setup" => Some(libc::SYS_io_uring_setup),
453        "io_uring_enter" => Some(libc::SYS_io_uring_enter),
454        "io_uring_register" => Some(libc::SYS_io_uring_register),
455        "open_tree" => Some(libc::SYS_open_tree),
456        "move_mount" => Some(libc::SYS_move_mount),
457        "fsopen" => Some(libc::SYS_fsopen),
458        "fsconfig" => Some(libc::SYS_fsconfig),
459        "fsmount" => Some(libc::SYS_fsmount),
460        "fspick" => Some(libc::SYS_fspick),
461        "pidfd_open" => Some(libc::SYS_pidfd_open),
462        "clone3" => Some(libc::SYS_clone3),
463        "close_range" => Some(libc::SYS_close_range),
464        "openat2" => Some(libc::SYS_openat2),
465        "pidfd_getfd" => Some(libc::SYS_pidfd_getfd),
466        "faccessat2" => Some(libc::SYS_faccessat2),
467        "process_madvise" => Some(libc::SYS_process_madvise),
468        "epoll_pwait2" => Some(libc::SYS_epoll_pwait2),
469        "mount_setattr" => Some(libc::SYS_mount_setattr),
470        "quotactl_fd" => Some(libc::SYS_quotactl_fd),
471        "landlock_create_ruleset" => Some(libc::SYS_landlock_create_ruleset),
472        "landlock_add_rule" => Some(libc::SYS_landlock_add_rule),
473        "landlock_restrict_self" => Some(libc::SYS_landlock_restrict_self),
474        "memfd_secret" => Some(libc::SYS_memfd_secret),
475        "process_mrelease" => Some(libc::SYS_process_mrelease),
476        "futex_waitv" => Some(libc::SYS_futex_waitv),
477        "set_mempolicy_home_node" => Some(libc::SYS_set_mempolicy_home_node),
478        "fchmodat2" => Some(libc::SYS_fchmodat2),
479        _ => None,
480    }
481}
482
483#[cfg(test)]
484mod tests {
485    use super::super::seccomp::{SeccompFilter, SeccompProfile};
486    use super::*;
487
488    #[test]
489    fn test_compile_minimal_filter() {
490        let filter = SeccompFilter::minimal();
491        let result = SeccompBpf::compile(&filter);
492        assert!(result.is_ok());
493        let bpf_code = result.unwrap();
494        assert!(!bpf_code.is_empty());
495    }
496
497    #[test]
498    fn test_compile_io_heavy_filter() {
499        let filter = SeccompFilter::from_profile(SeccompProfile::IoHeavy);
500        let result = SeccompBpf::compile(&filter);
501        assert!(result.is_ok());
502        let bpf_code = result.unwrap();
503        assert!(!bpf_code.is_empty());
504    }
505
506    #[test]
507    fn test_compile_network_filter() {
508        let filter = SeccompFilter::from_profile(SeccompProfile::Network);
509        let result = SeccompBpf::compile(&filter);
510        assert!(result.is_ok());
511        let bpf_code = result.unwrap();
512        assert!(!bpf_code.is_empty());
513    }
514
515    #[test]
516    fn test_all_allowed_syscalls_have_numbers() {
517        for profile in SeccompProfile::all() {
518            let filter = SeccompFilter::from_profile(profile);
519            for syscall in filter.allowed_syscalls() {
520                assert!(
521                    get_syscall_number_from_name(syscall).is_some(),
522                    "missing number for syscall '{}'",
523                    syscall
524                );
525            }
526        }
527    }
528
529    #[test]
530    fn test_compile_compute_filter() {
531        let filter = SeccompFilter::from_profile(SeccompProfile::Compute);
532        let result = SeccompBpf::compile(&filter);
533        assert!(result.is_ok());
534        let bpf_code = result.unwrap();
535        assert!(!bpf_code.is_empty());
536    }
537
538    #[test]
539    fn test_compile_with_blocked_syscall() {
540        let mut filter = SeccompFilter::minimal();
541        filter.block_syscall("ptrace");
542        let result = SeccompBpf::compile(&filter);
543        assert!(result.is_ok());
544    }
545
546    #[test]
547    fn test_compile_kill_on_violation_true() {
548        let filter = SeccompFilter::minimal();
549        assert!(filter.is_kill_on_violation());
550        let result = SeccompBpf::compile(&filter);
551        assert!(result.is_ok());
552    }
553
554    #[test]
555    fn test_compile_kill_on_violation_false() {
556        let mut filter = SeccompFilter::minimal();
557        filter.set_kill_on_violation(false);
558        assert!(!filter.is_kill_on_violation());
559        let result = SeccompBpf::compile(&filter);
560        assert!(result.is_ok());
561    }
562
563    #[test]
564    fn test_compile_unrestricted_profile() {
565        let filter = SeccompFilter::from_profile(SeccompProfile::Unrestricted);
566        let result = SeccompBpf::compile(&filter);
567        assert!(result.is_ok());
568        let bpf_code = result.unwrap();
569        assert!(!bpf_code.is_empty());
570    }
571
572    #[test]
573    fn test_get_syscall_number_returns_none_for_invalid() {
574        let result = get_syscall_number_from_name("nonexistent_syscall_xyz");
575        assert!(result.is_none());
576    }
577
578    #[test]
579    fn test_get_syscall_number_returns_some_for_valid() {
580        let result = get_syscall_number_from_name("read");
581        assert!(result.is_some());
582        assert_eq!(result.unwrap(), libc::SYS_read);
583    }
584
585    #[test]
586    fn test_compile_with_blocked_syscalls() {
587        let mut filter = SeccompFilter::minimal();
588        filter.block_syscall("ptrace");
589        let result = SeccompBpf::compile(&filter);
590        assert!(result.is_ok());
591    }
592
593    #[test]
594    fn test_compile_io_heavy_profile() {
595        let filter = SeccompFilter::from_profile(SeccompProfile::IoHeavy);
596        let result = SeccompBpf::compile(&filter);
597        assert!(result.is_ok());
598        let bpf_code = result.unwrap();
599        assert!(!bpf_code.is_empty());
600    }
601
602    #[test]
603    fn test_compile_network_profile() {
604        let filter = SeccompFilter::from_profile(SeccompProfile::Network);
605        let result = SeccompBpf::compile(&filter);
606        assert!(result.is_ok());
607        let bpf_code = result.unwrap();
608        assert!(!bpf_code.is_empty());
609    }
610
611    #[test]
612    fn test_load_rejects_unknown_syscalls() {
613        let mut filter = SeccompFilter::minimal();
614        filter.allow_syscall("syscall_que_nao_existe_xyz_123");
615
616        let result = SeccompBpf::compile(&filter);
617        assert!(result.is_err());
618        let err_msg = result.unwrap_err().to_string();
619        assert!(err_msg.contains("Unknown syscall"));
620    }
621
622    #[test]
623    fn test_load_with_unknown_syscalls_allowed() {
624        let mut filter = SeccompFilter::minimal();
625        filter.allow_syscall("syscall_inexistente");
626        filter.set_allow_unknown_syscalls(true);
627        let result = SeccompBpf::compile(&filter);
628        assert!(result.is_ok());
629    }
630
631    #[test]
632    fn test_unrestricted_blocks_specified_syscalls() {
633        let mut filter = SeccompFilter::from_profile(SeccompProfile::Unrestricted);
634        filter.block_syscall("ptrace");
635
636        let result = SeccompBpf::compile(&filter);
637        assert!(result.is_ok());
638    }
639
640    #[test]
641    fn test_unknown_blocked_syscall_error() {
642        let mut filter = SeccompFilter::from_profile(SeccompProfile::Unrestricted);
643        filter.block_syscall("syscall_invalida_xyz");
644
645        let result = SeccompBpf::compile(&filter);
646        assert!(result.is_err());
647        let err_msg = result.unwrap_err().to_string();
648        assert!(err_msg.contains("Unknown syscall to block"));
649    }
650}