'\" t .\" Title: ceccomp .\" Author: dbgbgtf, RocketDev .\" Generator: Asciidoctor 2.0.26 .\" Date: 2026-02-13 .\" Manual: Ceccomp Manual .\" Source: ceccomp 4.0 .\" Language: English .\" .TH "CECCOMP" "1" "2026-02-13" "ceccomp 4.0" "Ceccomp Manual" .ie \n(.g .ds Aq \(aq .el .ds Aq ' .ss \n[.ss] 0 .nh .ad l .de URL \fI\\$2\fP <\\$1>\\$3 .. .als MTO URL .if \n[.g] \{\ . mso www.tmac . am URL . ad l . . . am MTO . ad l . . . LINKSTYLE blue R < > .\} .SH "名称" ceccomp \- 一个分析安全计算 (seccomp) 过滤器的工具 .SH "大纲" .sp .if n .RS 4 .nf .fam C usage: ceccomp [FILE] [\-q|\-\-quiet] [\-f|\-\-format FMT] [\-a|\-\-arch ARCH] [\-p|\-\-pid PID] [\-s|\-\-seize] [\-o|\-\-output FILE] [\-c|\-\-color WHEN] ... .fam .fi .if n .RE .SH "概念" .sp 内核使用BPF过滤器来限制系统调用规则,并使用 \f(CRseccomp\fP 和 \f(CRprctl\fP 两个系统调用来安装过滤器。以下是一个以十六进制表示的限制 \f(CRexecve\fP 系统调用的简单过滤器: .sp .if n .RS 4 .nf .fam C 1: 20 00 00 00 00 00 00 00\& $A = $syscall_nr 2: 15 00 00 01 3b 00 00 00\& if ($A != execve) goto 4 3: 06 00 00 00 00 00 00 00\& return KILL 4: 06 00 00 00 00 00 ff 7f\& return ALLOW .fam .fi .if n .RE .sp 以上十六进制的部分就是内核收到的过滤器,而 \f(CRceccomp\fP 负责把它拿来反汇编为人类可读的文本。 例如左侧的 \fB行号\fP 和右侧的 \fB伪代码\fP 。 .if n .sp .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 .B Important .ps -1 .br .sp 之后我会使用 \fITEXT\fP 作为BPF过滤器人类可读文本(伪代码)的缩写, 使用 \fIRAW\fP 作为BPF过滤器原始格式的缩写,请记住这个约定。 .sp .5v .RE .SH "描述" .sp \f(CRceccomp\fP 有5个主要的功能,它基本上是C版本的 \f(CRseccomp\-tools\fP ,然而, 有一些不同的地方你需要知道,它们会在在每个子命令的章节中被注明。 .SS "asm \- 汇编" .sp .if n .RS 4 .nf .fam C ceccomp asm [\-c WHEN] [\-a ARCH] [\-f FMT] [TEXT] .fam .fi .if n .RE .sp 将 \fITEXT\fP 汇编为 \fIRAW\fP 。适用于将手写的过滤器规则嵌入到C代码中, 或希望观察一些 \fITEXT\fP 对应的原始字节码。 .sp WHEN .RS 4 决定了 \f(CRceccomp\fP 何时输出有颜色的文本。当设置为 \fIauto\fP 时, \f(CRceccomp\fP 会在输出目标是一个“tty”时打印颜色。可以是 \fIauto\fP 、 \fInever\fP 或者 \fIalways\fP 。 默认值是 \fIauto\fP 。 .RE .sp ARCH .RS 4 可以设置为任何 libseccomp 支持的架构。它将被用于决定系统调用名称对应的系统调用号。 例如,在 x86_64 上,就像上面的基本示例,你可以写 \f(CR"execve"\fP 而不是数字 \f(CR59\fP 指代系统调用号。如果不设置这个参数,则通过 \f(CRuname\fP 提取当前系统的架构。 你的系统上的默认值是 x86_64 。 .RE .if n .sp .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 .B Note .ps -1 .br .sp 从 \fI4.0 版本\fP 开始考虑端序。如果目标架构 \fBARCH\fP 的端序与机器端序不同,则会在输出前反转过滤器(CODE 和 K)。 .sp .5v .RE .sp FMT .RS 4 决定了 \f(CRceccomp\fP 如何输出二进制格式的BPF字节码。可以是 \fIhexfmt\fP 、 \fIhexline\fP 或者 \fIraw\fP 。你可以在 CECCOMP 示例 节中找到示例输出。默认值是 \fIhexline\fP 。 .RE .sp TEXT .RS 4 一个可选的文件名,其中存放了需要被汇编的 \fITEXT\fP 。不设置则从 \fI标准输入\fP 中读取。\f(CR\-\fP 被视作 \fI标准输入\fP。 .RE .if n .sp .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 .B Important .ps -1 .br .sp \fI4.0 版本\fP 大幅修改了汇编的语法,请查阅下面的语法参考! .sp .5v .RE .sp 查看 TEXT 语法参考 一节可以找到如何手写规则。一些示例会在 CECCOMP 示例 一节中展示。 .TS allbox tab(:); ltB ltB. T{ .sp 命令 T}:T{ .sp 差别 T} .T& lt lt. T{ .sp \f(CRseccomp\-tools asm\fP T}:T{ .sp 使用它自己的语法汇编,有点像脚本;可以汇编会被内核拒绝的错误 \fITEXT\fP T} T{ .sp \f(CRceccomp asm\fP T}:T{ .sp 你可以直接拿着 \f(CRdisasm\fP 的输出来汇编,不需要学习新语法;默认使用 \fI标准输入\fP 作为输入 T} .TE .sp .SS "disasm \- 反汇编" .sp .if n .RS 4 .nf .fam C ceccomp disasm [\-c WHEN] [\-a ARCH] [RAW] .fam .fi .if n .RE .sp 反汇编 \fIRAW\fP 为 \fITEXT\fP 。适用于当你无法使用 \f(CRtrace\fP 看到过滤器时,必须手动提取过滤器, 然后检查其含义。 .sp WHEN .RS 4 参数描述可以在 asm \- 汇编 一节中找到。 \f(CRdisasm\fP 可能会打印更多有颜色的文本,包括针对 \fITEXT\fP 的语法高亮。 .RE .sp ARCH .RS 4 可以设置为任何 libseccomp 支持的架构。它将被用于决定 \fIRAW\fP 中的系统调用号如何被翻译为系统调用名。 例如,在 x86_64 上,在比较系统调用号时,数字 \f(CR0x3b\fP 将被翻译为 \f(CRexecve\fP ,可以看上面的基本示例。 你的系统上的默认值是 x86_64 。 .RE .sp RAW .RS 4 包含原始 BPF 代码的二进制文件。如果不设置则将 \fI标准输入\fP 作为输入。\f(CR\-\fP 被视作 \fI标准输入\fP。这个文件是与架构有关的,所以它在不同架构之间可能不是通用的。 .RE .if n .sp .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 .B Note .ps -1 .br .sp 从 \fI4.0 版本\fP 开始考虑端序。如果目标架构 \fBARCH\fP 的端序与机器端序不同,则会在解码前反转过滤器(CODE 和 K)。 .sp .5v .RE .if n .sp .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 .B Note .ps -1 .br .sp 当且仅当在某一行的架构可以被确定时,ceccomp 才会尝试用那个架构解析那个系统调用号。 如果是外部架构(不等于你设置的架构),它会被附加到系统调用名前。你可能会注意到在一些情况下, seccomp\-tools 能解析一些系统调用名,而 ceccomp 不能,这可能是因为此时架构不能被确定。 .sp .5v .RE .TS allbox tab(:); ltB ltB. T{ .sp 命令 T}:T{ .sp 差别 T} .T& lt lt. T{ .sp \f(CRseccomp\-tools disasm\fP T}:T{ .sp 用它自己的语法反汇编;永远不会检查 \fIRAW\fP 是否合法 T} T{ .sp \f(CRceccomp disasm\fP T}:T{ .sp 用 ceccomp 语法反汇编,并且默认将 \fI标准输入\fP 作为输入;严格检查架构, 并且永远打印外部架构名 T} .TE .sp .SS "emu \- 模拟" .sp .if n .RS 4 .nf .fam C ceccomp emu [\-c WHEN] [\-a ARCH] [\-q] TEXT SYSCALL_NAME/SYSCALL_NR [ARGS[0] ARGS[1] ... ARGS[5] PC] .fam .fi .if n .RE .sp 按照 \fITEXT\fP 中描述的规则,模拟从 \f(CRPC\fP 调用 \f(CRsyscall(SYSCALL_NR, ARGS[0], ARGS[1], .\|.\|., ARGS[5])\fP 的结果。适用于在不实际运行程序或不想手动检查规则时,查看触发系统调用的结果。 这个子命令适合用来自动检测一个过滤器。 .sp WHEN .RS 4 参数描述可以在 asm \- 汇编 一节中找到。 \f(CRemu\fP 可能会打印更多有颜色的文本,包括针对 \fITEXT\fP 的语法高亮以及跳过的伪代码。 .RE .sp SYSCALL_NAME/SYSCALL_NR .RS 4 如果你设置了 \fBSYSCALL_NAME\fP (比如 \f(CRexecve\fP ),那么它会基于 \fBARCH\fP 先被翻译为对应的 \fBSYSCALL_NR\fP 。或者你可以直接设置 \fBSYSCALL_NR\fP (例如 \f(CR59\fP )。然后会测试这个系统调用号经过 BPF 过滤器处理后的输出并打印出来。这个参数是必填的。 .RE .sp ARGS[0\-5] 和 PC .RS 4 当调用系统调用时对应寄存器的值。例如,在 x86_64 上,它们分别对应了 \f(CRrdi\fP 、 \f(CRrsi\fP 、 \f(CRrdx\fP 、 \f(CRr10\fP 、 \f(CRr8\fP 、 \f(CRr9\fP 和 \f(CRrip\fP 。它们的默认值都是0。 .RE .sp ARCH .RS 4 参数描述可以在 asm \- 汇编 一节中找到。 .RE .sp TEXT .RS 4 一个文件名,其中存放了需要被测试的 \fITEXT\fP 规则。注意文件名 不能 被忽略,因为 ceccomp 无法判断一个位置参数是系统调用号还是文件名。使用 \f(CR\-\fP 可以指代 \fI标准输入\fP。 .RE .sp \-q, \-\-quiet .RS 4 只打印过滤器的模拟结果。例如,最后一行模拟的伪代码是 \f(CRreturn KILL\fP,那么将会打印 \f(CRKILL\fP。 .RE .TS allbox tab(:); ltB ltB. T{ .sp 命令 T}:T{ .sp 差别 T} .T& lt lt. T{ .sp \f(CRseccomp\-tools emu\fP T}:T{ .sp 用 \fIRAW\fP 作为输入 T} T{ .sp \f(CRceccomp emu\fP T}:T{ .sp 用 \fITEXT\fP 作为输入,并默认将 \fI标准输入\fP 作为输入;可以设置 \fBPC\fP T} .TE .sp .SS "trace \- 运行时捕获过滤器" .sp .if n .RS 4 .nf .fam C ceccomp trace [\-c WHEN] [\-o FILE] PROGRAM [program\-args] [\-c WHEN] \-p PID [\-s] .fam .fi .if n .RE .sp 使用第一行的命令可以利用调试在 \fBPROGRAM\fP 运行中加载过滤器时动态捕获过滤器; 第二行的命令可以从 \fBPID\fP 对应的进程中提取出 seccomp 过滤器,或通过调试 \fBPID\fP 捕获后续的 seccomp 过滤器;一旦捕获到了过滤器, 将会以 \fITEXT\fP 的格式将它打印出来。你可以从两个格式中选择一个使用。 适用于运行一个程序是捕获BPF过滤器最简单的方式或者一个安装了 seccomp 过滤器的程序正在等待输入。 .sp WHEN .RS 4 参数描述可以在 asm \- 汇编 一节中找到。 \f(CRtrace\fP 可能会打印更多有颜色的文本,包括针对 \fITEXT\fP 的语法高亮。 .RE .sp FILE .RS 4 当 \fBPROGRAM\fP 会产生很多输出到 \fI标准错误\fP 时可能很有用。 \f(CRceccomp\fP 允许用户关闭 \fI标准输入\fP 和 \fI标准输出\fP 来限制 \fBPROGRAM\fP 的输入和输出,所以 当运行 \fBPROGRAM\fP 时 \f(CRceccomp\fP 使用 \fI标准错误\fP 来打印消息。如果你想在别的文件中看见 \fITEXT\fP 的话请设置 \fBFILE\fP 。\f(CR\-\fP 被视作 \fI标准输出\fP。 .RE .sp PROGRAM .RS 4 设置为你想运行的程序,并且 \fBprogram\-args\fP 将作为它的参数, 就像运行 shell 命令 \f(CRexec PROGRAM program\-args\fP 。 .RE .sp PID .RS 4 设置为你想检查的 pid。 \fBPID\fP 和 \fBPROGRAM\fP 相冲突;你只能在一条命令中动态运行一个程序, 或者检查一个 pid。没有 \f(CR\-s\fP 标志,trace pid 会尝试使用 \f(CRptrace(PTRACE_SECCOMP_GET_FILTER)\fP 从 \fBPID\fP 中提取 seccomp 过滤器,这个操作在一些系统上可能不可用。 .RE .sp \-s, \-\-seize .RS 4 \fB只适用于 TRACE PID 模式。\fP 设置这个标志将会覆盖 trace pid 的行为为像 trace prog 模式一样把调试器挂到 \fBPID\fP 上并持续跟踪 seccomp 过滤器的加载。\fI这个标志引入于 4.0 版本。\fP .RE .sp \-q, \-\-quiet .RS 4 设置这个标志将会在检测到进程分叉、退出或加载 seccomp 过滤器时抑制多余的 \fB[INFO]\fP 输出。 \fI这个标志引入于 4.0 版本。\fP .RE .if n .sp .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 .B Note .ps -1 .br .sp 要想从 \fBPID\fP 中提取过滤器,你需要 \f(CRCAP_SYS_ADMIN\fP (没有 \f(CR\-s\fP 标志),同时还可能需要 \f(CRCAP_SYS_PTRACE\fP ,最简单的获取它们的方法是用 \f(CRsudo\fP 运行 \f(CRceccomp\fP 。 .sp .5v .RE .if n .sp .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 .B Note .ps -1 .br .sp 从 \fI3.1 版本\fP 开始引入了多进程支持,并且当被调试进程 fork/resolve/exit 时,将会打印一条额外的 INFO 信息。你可以使用像 \f(CRceccomp trace \-q PROG 2>/dev/null\fP 这样的命令丢弃它。 .sp .5v .RE .TS allbox tab(:); ltB ltB. T{ .sp 命令 T}:T{ .sp 差别 T} .T& lt lt. T{ .sp \f(CRseccomp\-tools dump\fP T}:T{ .sp 可以设置输出格式;每一个过滤器可以输出到不同的文件;当 \fBPROGRAM\fP 加载了 \fBLIMIT\fP 个过滤器后就杀死程序;将 \fBPROGRAM\fP 包装在 \f(CRsh \-c\fP 中运行 T} T{ .sp \f(CRceccomp trace\fP T}:T{ .sp 所有过滤器被输出到同一个文件;永远不会杀死 \fBPROGRAM\fP ; \fBPROGRAM\fP 是直接被执行的, 所以不需要 \f(CR./\fP ;当 fork 时,显式打印事件;能够附加调试器到 pid 上动态捕捉 seccomp 过滤器 T} .TE .sp .SS "probe \- 快速测试常见的系统调用" .sp .if n .RS 4 .nf .fam C ceccomp probe [\-c WHEN] [\-o FILE] [\-q] PROGRAM [program\-args] .fam .fi .if n .RE .sp 以 \fBprogram\-args\fP 为参数运行 \fBPROGRAM\fP 来捕获 \fB第一个\fP seccomp 过滤器, 然后杀死所有子进程。适用于快速测试一个程序的规则并检测潜在的 seccomp 规则问题。 .sp 所有参数描述都可以在 trace \- 运行时捕获过滤器 一节中找到。 .sp 这个子命令的输出是一系列常见的系统调用的模拟结果,例如 \f(CRexecve\fP 、 \f(CRopen\fP 等。 如果过滤器本身并不能阻拦系统调用,那你一眼就能看出来。 .sp 这个子命令的典型输出如下所示,更多完整的实例可以在 CECCOMP 示例 一节中找到。 .sp .if n .RS 4 .nf .fam C open\& \-> ALLOW read\& \-> ALLOW write\& \-> ALLOW execve\& \-> KILL execveat\& \-> KILL mmap\& \-> ALLOW mprotect\& \-> ALLOW openat\& \-> ALLOW sendfile\& \-> ALLOW ptrace\& \-> ERRNO(1) fork\& \-> ALLOW .fam .fi .if n .RE .if n .sp .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 .B Note .ps -1 .br .sp \f(CRseccomp\-tools\fP 没有等价的子命令。 .sp .5v .RE .SH "TEXT 语法参考" .if n .sp .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 .B Important .ps -1 .br .sp \fI4.0 版本\fP 提高了词法分析器代码的可读性,伴随着大幅修改的语法。前缀为 \f(CR#\fP 的行现在是注释了。同时 \fI行号\fP 被替换为 \fI标签\fP,现在词法分析器根据标签定义来决定跳转到哪里,而不是根据 \fITEXT\fP 文件中的行号。 .sp .5v .RE .sp 这里有正确的 \fITEXT\fP 格式,以类 EBNF 语法描述:https://github.com/dbgbgtf1/Ceccomp/issues/17#issuecomment\-3610531705。 没兴趣了解 EBNF?请继续阅读以下的例子。 .sp 其余未描述到的BPF操作都被内核禁止了。 .SS "注释与标签" .sp \f(CRceccomp disasm\fP 展示了很多东西,但对于 asm 来说有些是可选的。 .sp .if n .RS 4 .nf .fam C #Label\& CODE\& JT\& JF\& K #\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- L0001: 0x06 0x00 0x00 0x7fff0000 return ALLOW #\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- .fam .fi .if n .RE .sp 任何在 \f(CR#\fP 之后的文本将被 asm 丢弃,就像一些脚本语言一样。 .sp 允许空行。 .sp 标签声明是一个从行首开始并以 \f(CR:\fP 结尾的标识符,例如 \f(CRL0001\fP。标识符是一个以字母为首,中间只包含字母、数字和下划线 \f(CR_\fP 的字符串。标签只在它是 \f(CRgoto\fP 的目标时才是必要的,由 disasm 添加的多余的标签知识为了可读性。例如在 \f(CRif ($A == 0) goto somewhere\fP 中,\f(CRsomewhere\fP 是一个标签并且必须在这行伪代码后声明。标签声明可以单独占据一行,也可以放置在伪代码的前面。 .sp 由 disasm 生成的 \f(CRCODE\fP、\f(CRJT\fP、\f(CRJF\fP 和 \f(CRK\fP 值会被 asm 丢弃,asm 之解析 \f(CRK\fP 之后的有效伪代码。 .if n .sp .RS 4 .it 1 an-trap .nr an-no-space-flag 1 .nr an-break-flag 1 .br .ps +1 .B Note .ps -1 .br .sp \f(CRceccomp disasm\fP 和 \f(CRseccomp\-tools disasm\fP 的输出之间有很多细微的差别, 以下是一个典型的输出示例。同时有些伪代码是不同的,所以不要盲目将 seccomp\-tools 的输出管道给 ceccomp。 .sp .5v .RE .sp .if n .RS 4 .nf .fam C line\& CODE\& JT\& JF\& K ================================= 0000: 0x06 0x00 0x00 0x7fff0000\& return ALLOW .fam .fi .if n .RE .SS "赋值" .sp \f(CRA\fP 可以直接赋值为 seccomp 属性。由于内核限制, \f(CRX\fP 不能直接赋值为 seccomp 属性。 .sp .if n .RS 4 .nf .fam C $A = $arch $A = $syscall_nr .fam .fi .if n .RE .sp 要给 \f(CRA\fP 赋值为这些64位长的字段,必须使用 \f(CRlow_\fP 或者 \f(CRhigh_\fP 的前缀。 .sp .if n .RS 4 .nf .fam C $A = $low_pc $A = $high_pc $A = $low_args[0] $A = $high_args[0] \&... $A = $low_args[5] $A = $high_args[5] .fam .fi .if n .RE .sp 一个特殊的属性是 \f(CRsizeof(struct seccomp_data)\fP ,它可以直接赋值给 \f(CRA\fP 或 \f(CRX\fP 。 .sp .if n .RS 4 .nf .fam C $A = $scmp_data_len $X = $scmp_data_len .fam .fi .if n .RE .sp 临时内存是32位的,要想访问它们,你可以使用十六进制或者十进制的索引。 \f(CRA\fP 和 \f(CRX\fP 都是可赋值的。给 \f(CRA\fP 或 \f(CRX\fP 赋值为立即数接受任意格式的数字,只要你使用 "0x" 或者 "0b" 等前缀正确表达数字是几进制的。 .sp .if n .RS 4 .nf .fam C $X = $mem[0] $A = $mem[0xf] $A = $mem[15] # both hex and dec index are OK $A = 0 $X = 0x3b $A = 0b1111 $A = 0333 .fam .fi .if n .RE .sp 你还可以将 \f(CRX\fP 赋值给 \f(CRA\fP 或者反过来。将 \f(CRX\fP 或 \f(CRA\fP 赋值给临时内存当然可以。 .sp .if n .RS 4 .nf .fam C $A = $X $X = $A $mem[3] = $X $mem[0x4] = $A .fam .fi .if n .RE .SS "数学运算" .sp 你可以以多种方式操作 \f(CRA\fP 。 .sp .if n .RS 4 .nf .fam C $A += 30 $A \-= 4 $A *= 9 $A /= 1 $A &= 7 $A >>= 6 .fam .fi .if n .RE .sp 右值也可以是 \f(CRX\fP 。 .sp .if n .RS 4 .nf .fam C $A &= $X $A |= $X $A ^= $X $A <<= $X .fam .fi .if n .RE .sp 想要对 \f(CRA\fP 取反可以这么做。 .sp .if n .RS 4 .nf .fam C $A = \-$A .fam .fi .if n .RE .SS "当.\|.\|.时向下跳转" .sp 无条件跳转: .sp .if n .RS 4 .nf .fam C goto L3 .fam .fi .if n .RE .sp 当.\|.\|.跳转: .sp .if n .RS 4 .nf .fam C if ($A == execve) goto L3 if ($A != 1234) goto L4 if ($A & $X) goto L5 if !($A & 7) goto L6 if ($A <= $X) goto L7 .fam .fi .if n .RE .sp 当条件为真时跳转到.\|.\|.,条件为假时跳转到.\|.\|.: .sp .if n .RS 4 .nf .fam C if ($A > $X) goto L3, else goto L4 if ($A >= 4567) goto L5, else goto L6 .fam .fi .if n .RE .sp \fB只有\fP 在做条件判断时,你才能将数字替换为系统调用号或架构名。在以上的例子中, \f(CR0x3b\fP 被 \f(CRexecve\fP 替换。所有系统调用名将会以你设置的架构解析为系统调用号。 如果你希望解析外部架构(不等于你设置的架构)的系统调用名, 请在前面附加架构名和一个点。例如,你设置的架构是 x86_64,并且你正在写 \fIaarch64\fP 架构的规则,请这样写: .sp .if n .RS 4 .nf .fam C if ($A == aarch64.read) goto 5 .fam .fi .if n .RE .sp 注意当你手动使用 \f(CR\-a aarch64\fP 将架构设置为 \fIaarch64\fP 时, 你可以在伪代码中忽略 \f(CRaarch64.\fP 。 .SS "返回码" .sp 返回寄存器 \f(CRA\fP 的值: .sp .if n .RS 4 .nf .fam C return $A .fam .fi .if n .RE .sp 或者返回一个立即数,多余的字段放在 \f(CR()\fP 里。 \f(CRTRACE\fP 、 \f(CRTRAP\fP 和 \f(CRERRNO\fP 接受一个额外的字段,如果没有 \f(CR()\fP ,它们将被视为 \f(CR行为(0)\fP 。 .sp .if n .RS 4 .nf .fam C return 0x13371337 return KILL return KILL_PROCESS return TRAP(123) return ERRNO(0) return TRACE return TRACE(3) return LOG return NOTIFY .fam .fi .if n .RE .SS "简短的例子" .sp 下面的 \fITEXT\fP 对与 asm 来说是正确的,这段 \fITEXT\fP 阻止了 amd64 的 \f(CRexecve\fP 和 \f(CRexecveat\fP 系统调用: .sp .if n .RS 4 .nf .fam C $A = $syscall_nr if ($A == execve) goto forbid if ($A == execveat) goto forbid return ALLOW forbid: return KILL .fam .fi .if n .RE .SH "限制" .sp 为了更好的性能,Ceccomp asm 对 \fITEXT\fP 有一些限制。 .sp .RS 4 .ie n \{\ \h'-04' 1.\h'+01'\c .\} .el \{\ . sp -1 . IP " 1." 4.2 .\} 由于 \fITEXT\fP 是个文本文件,\f(CR\*(Aq\(rs0\*(Aq\fP 不能出现在 \fITEXT\fP 中。 .RE .sp .RS 4 .ie n \{\ \h'-04' 2.\h'+01'\c .\} .el \{\ . sp -1 . IP " 2." 4.2 .\} 一行必须短于 384 \fB字节\fP。 .RE .sp .RS 4 .ie n \{\ \h'-04' 3.\h'+01'\c .\} .el \{\ . sp -1 . IP " 3." 4.2 .\} 一个 \fITEXT\fP 文件必须短于 4096 行。 .RE .sp .RS 4 .ie n \{\ \h'-04' 4.\h'+01'\c .\} .el \{\ . sp -1 . IP " 4." 4.2 .\} 一个 \fITEXT\fP 文家必须小于 1 MiB。 .RE .sp 并且对于 asm 和 disasm 来说,有效的伪代码(能被编码或解码为 BPF 的)必须少于等于 1024 条,这是内核规定的。 .sp 一个关于 ceccomp asm 有趣的知识:任何在 \fITEXT\fP 文件中基本的 ANSI 颜色,例如 \f(CR\(rsx1b[31m\fP,会在处理时被丢弃。 .SH "CECCOMP 示例" .sp 手册不能显示图片,因此如果想看示例请参阅html版本。 .SH "仓库" .sp 在 \c .URL "https://github.com/dbgbgtf1/Ceccomp" "" "" 可以找到源代码。 欢迎提交 Pull Requests 和 Issues ! .sp Copyright \(co 2025\-现在,基于 GPLv3 或更新版本分发。 .SH "AUTHORS" .sp dbgbgtf .sp RocketDev