1use 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
10pub struct SeccompBpf;
12
13impl SeccompBpf {
14 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 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 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 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
124fn 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}