Seccomp 过滤器
在 Linux 上,go-judge 默认对沙箱任务应用内置的、按架构区分的 seccomp 过滤器。该过滤器以 vendored 的 Moby 默认配置快照为基础,再转换为 go-judge 使用的格式并收紧规则。默认动作是 errno:不在允许列表中的系统调用会返回错误。被拒绝的系统调用通常会使命令以 Dangerous Syscall 状态结束。
过滤器的应用时机
容器 init 进程先完成命名空间、文件系统和 cgroup 设置,再安装过滤器。工作负载进程启动时继承该过滤器;go-judge 不会为每个命令单独安装过滤器。安装工作负载过滤器之前,init 设置流程可能需要使用 clone、clone3、unshare 和 kill 等操作。
生成的配置包含通用规则和架构专用规则,支持 x86-64、i386、AArch64 和 ARM。生成和加载配置时,会根据目标架构解析系统调用名称。
与 Moby 默认配置的差异
转换器会移除依赖容器 capability 的 Moby 规则。go-judge 在执行提交的程序前会移除 capability,因此这些条件规则不能代表工作负载实际拥有的权限。架构选择规则会被转换为明确的架构专用规则。
策略还会移除在用于构建配置的编译器和运行时工作负载中没有观察到、且会增加权限或内核攻击面的系统调用组:
- 跨进程检查与控制:
ptrace、process_vm_readv、process_vm_writev、process_mrelease和get_robust_list可读取或影响其他进程。 - 替代可执行文件加载方式:
execveat、memfd_create和memfd_secret增加了无文件可执行文件的加载或暂存路径。 - 旧式 x86 执行状态接口:
modify_ldt、get_thread_area和set_thread_area暴露旧式兼容接口。 - 设备节点和文件系统事件监控:
mknod、mknodat和fanotify_mark可能暴露设备,或监控常规文件访问之外的文件系统活动。 - 跨进程信号与调度:
getsid、rt_sigqueueinfo、rt_tgsigqueueinfo、sched_setattr、sched_setparam和tkill可识别或影响其他进程。Shell 的作业控制需要查询自身进程组,因此getpgid仅允许查询当前进程。 - 旧式异步 I/O:
io_setup、io_submit、io_getevents、io_pgetevents、io_destroy和io_cancel提供了工作负载未使用的 I/O 接口。 - 替代文件系统和挂载接口:
openat2、name_to_handle_at、listmount和statmount增加了工作负载所需文件操作之外的接口。 - 由内核转发数据:
copy_file_range、sendfile、splice、tee和vmsplice提供了文件描述符之间的数据传输路径,工作负载不需要这些操作。
配置还会拒绝 personality,并通过阻止终端输入注入和 Linux 虚拟控制台请求来限制 ioctl。创建 socket 仅允许 AF_UNIX、AF_INET 和 AF_INET6;socketpair 仅允许 AF_UNIX。在 i386 上,seccomp 无法检查旧式 socketcall 接口通过指针传入的参数,因此会拒绝其中的 socket 和 socketpair 操作。这些规则减少了可用的内核接口,但本身不提供网络命名空间隔离。
允许的系统调用及编译器观察结果
以下列表包含当前生成配置的通用部分和架构专用部分中的系统调用名称。架构专用部分包含 ABI 别名;某个调用在其他架构上可能不可用。部分调用通过参数过滤,而非完全开放:socket 仅允许 AF_UNIX、AF_INET 和 AF_INET6;socketpair 仅允许 AF_UNIX;ioctl 排除 TIOCSTI 和 TIOCLINUX;getpgid 仅允许查询当前进程。i386 的 socketcall 路径会拒绝创建套接字的操作。
下方编译器关联记录的是 16 种语言配置样本中观察到的调用,不代表每个编译器的所有功能只需要这些调用。样本中普遍观察到常规文件、内存、进程、身份和资源管理调用。上游观察记录按语言以及编译/运行阶段列出了调用。
编译器观察结果
| 观察到的工作负载 | 跟踪中较有代表性的调用 |
|---|---|
| Go 编译器 | 编译期间观察到 clone、pidfd_open、pidfd_send_signal 和 fallocate。 |
| Java 编译器/运行时 | 编译和运行期间都使用了 socket。配置仅允许 AF_UNIX、AF_INET 和 AF_INET6;Java 编译期间观察到 AF_UNIX 和互联网协议族套接字,运行期间观察到 AF_UNIX。 |
| Rust 编译器 | 编译期间观察到 socketpair(AF_UNIX)。 |
| 其他样本工作负载 | 16 种语言配置样本中均观察到常用文件、内存、进程、身份和资源管理调用。上游观察记录按语言和阶段列出了详细情况。 |
文件与目录操作
_llseek, access, chdir, chmod, chown, chown32, close, close_range, creat, faccessat, faccessat2, fadvise64, fadvise64_64, fallocate, fchdir, fchmod, fchmodat, fchmodat2, fchown, fchown32, fchownat, fcntl, fcntl64, fdatasync, fgetxattr, flistxattr, flock, fremovexattr, fsetxattr, fstat, fstat64, fstatat, fstatat64, fstatfs, fstatfs64, fsync, ftruncate, ftruncate64, getcwd, getdents, getdents64, getxattr, getxattrat, lgetxattr, link, linkat, listxattr, listxattrat, llistxattr, lremovexattr, lseek, lsetxattr, lstat, lstat64, mkdir, mkdirat, newfstatat, open, openat, read, readahead, readlink, readlinkat, readv, removexattr, removexattrat, rename, renameat, renameat2, rmdir, setxattr, setxattrat, stat, stat64, statfs, statfs64, statx, sync, sync_file_range, syncfs, truncate, truncate64, umask, unlink, unlinkat, utime, utimensat, utimensat_time64, utimes, write, writev
内存管理
brk, madvise, mincore, mlock, mlock2, mlockall, mmap, mmap2, mprotect, mremap, mseal, munlock, munlockall, munmap, pkey_alloc, pkey_free, pkey_mprotect, remap_file_pages
进程、线程与信号控制
clone, clone3, execve, exit, exit_group, fork, getpgid, getpgrp, getpid, getppid, gettid, kill, pidfd_open, pidfd_send_signal, prctl, rt_sigaction, rt_sigpending, rt_sigprocmask, rt_sigreturn, rt_sigsuspend, rt_sigtimedwait, rt_sigtimedwait_time64, set_robust_list, set_tid_address, setpgid, setsid, sigaltstack, tgkill, vfork, wait4, waitid, waitpid
时间与定时器
alarm, clock_adjtime, clock_adjtime64, clock_getres, clock_getres_time64, clock_gettime, clock_gettime64, clock_nanosleep, clock_nanosleep_time64, getcpu, getrusage, gettimeofday, nanosleep, setitimer, sysinfo, timer_create, timer_delete, timer_getoverrun, timer_gettime, timer_gettime64, timer_settime, timer_settime64, timerfd_create, timerfd_gettime, timerfd_gettime64, timerfd_settime, timerfd_settime64, times
调度与资源限制
getpriority, getrlimit, ioprio_get, ioprio_set, prlimit64, sched_get_priority_max, sched_get_priority_min, sched_getaffinity, sched_getattr, sched_getparam, sched_getscheduler, sched_rr_get_interval, sched_rr_get_interval_time64, sched_setaffinity, sched_setscheduler, sched_yield, setpriority, setrlimit, ugetrlimit
同步、进程间通信与轮询
epoll_create, epoll_create1, epoll_ctl, epoll_ctl_old, epoll_pwait, epoll_pwait2, epoll_wait, epoll_wait_old, eventfd, eventfd2, futex, futex_requeue, futex_time64, futex_wait, futex_waitv, futex_wake, inotify_add_watch, inotify_init, inotify_init1, inotify_rm_watch, ipc, mq_getsetattr, mq_notify, mq_open, mq_timedreceive, mq_timedreceive_time64, mq_timedsend, mq_timedsend_time64, mq_unlink, msgctl, msgget, msgrcv, msgsnd, pipe, pipe2, poll, pselect6, pselect6_time64, select, semctl, semget, semop, semtimedop, semtimedop_time64, shmat, shmctl, shmdt, shmget, signalfd, signalfd4
套接字与网络
accept, accept4, bind, connect, getpeername, getsockname, getsockopt, listen, recv, recvfrom, recvmmsg, recvmmsg_time64, recvmsg, send, sendfile64, sendmmsg, sendmsg, sendto, setsockopt, shutdown, socket, socketcall, socketpair
凭据与系统信息
capget, capset, getegid, getegid32, geteuid, geteuid32, getgid, getgid32, getgroups, getgroups32, getrandom, getresgid, getresgid32, getresuid, getresuid32, getuid, getuid32, setfsgid, setfsgid32, setfsuid, setfsuid32, setgid, setgid32, setgroups, setgroups32, setregid, setregid32, setresgid, setresgid32, setresuid, setresuid32, setreuid, setreuid32, setuid, setuid32, uname
架构专用及其他操作
_newselect, adjtimex, arch_prctl, arm_fadvise64_64, arm_sync_file_range, breakpoint, cacheflush, cachestat, dup, dup2, dup3, futimesat, getitimer, io_pgetevents_time64, ioctl, landlock_add_rule, landlock_create_ruleset, landlock_restrict_self, lchown, lchown32, map_shadow_stack, membarrier, msync, pause, ppoll, ppoll_time64, pread64, preadv, preadv2, pwrite64, pwritev, pwritev2, restart_syscall, rseq, seccomp, set_tls, sigprocmask, sigreturn, symlink, symlinkat, time, unshare, uretprobe
配置方式
使用 -seccomp-conf <path> 可用自定义配置替换内置配置,格式为 go-judge 使用的架构专用 YAML。使用 -no-seccomp 可在排查问题或性能测试时关闭过滤器;这会移除一层隔离,不适合常规服务运行。
配置源文件、生成说明和实现理由见 go-judge seccomp 目录。