1# Seccomp策略使能开发指导
2## 概述
3### 功能简介
4Seccomp(Secure computing mode)是Linux kernel支持的一种安全机制。在Linux系统中,大量的系统调用可以不受限制地向用户态程序开放,但用户态程序并不需要所有的系统调用,此时不安全的代码如果滥用系统调用会对系统造成威胁。例如,一个进程中存在安全漏洞,攻击者可以运行一段Shellcode去触发正常执行中不会触发的系统调用,从而导致提权或者私密信息被窃取。针对这类安全隐患,Seccomp机制通过限制程序可使用的系统调用范围,来减少系统的暴露面,提高安全性。
5
6### 运作机制
71. 基本机制
8
9    Seccomp策略以策略文件的形式存在。在编译构建时,首先相关脚本解析策略文件来生成含BPF指令策略的源文件,然后编译成策略动态库。最后,用户态进程启动过程中,使用Seccomp系统调用将BPF指令策略加载到内核中。
10
112. 基本特点
12    - 子进程继承父进程的Seccomp策略。
13    - 在进程运行时Seccomp策略被加载到内核后,以单向链表的形式存在于内存中,且内容不能被修改。
14    - 进程可多次设置Seccomp策略。进程在执行系统调用时,内核会遍历单向链表中每个节点的策略,比较每个节点策略的返回值,最后得到优先级最高的返回值。
15
16
17### 约束与限制
18- 支持标准系统,且标准系统的内核已开启下列选项。产品的内核选项配置文件路径为//kernel/linux/config/{linux_version}/arch/{target_cpu}/configs/。
19    ```shell
20    CONFIG_HAVE_ARCH_SECCOMP=y
21    CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
22    CONFIG_SECCOMP=y
23    CONFIG_SECCOMP_FILTER=y
24    ```
25
26- 特性限制
27    - 非特权进程Seccomp策略遵循基线黑名单机制。
28    - 若进程需使用基线黑名单系统调用,则要在特权进程策略文件中声明。
29    - 所有应用进程使能同一个Seccomp策略。
30    - 大部分系统服务进程使能同一个Seccomp策略。
31    - 支持init进程孵化的Native service进程使能个性化Seccomp策略。
32
33## 产品使能Seccomp机制
34### 场景介绍
35产品可根据自身对安全性的要求,需要使能Seccomp机制来限制进程可使用的系统调用范围。按照下面的开发步骤,系统可使能Seccomp的基本功能与基本策略。其基本功能满足[约束与限制](#约束与限制)中的特性限制,基本策略文件说明见[策略文件说明](#策略文件说明)。
36### 开发步骤
371. 在vendor/产品厂商/产品名/config.json添加以下字段。
38    ```c
39    "build_seccomp": true
40    ```
41    产品配置文件添加build_seccomp字段的示例如下:
42    ```c
43    {
44        "product_name": "MyProduct",
45        "version": "3.0",
46        "type": "standard",
47        "target_cpu": "arm",
48        "ohos_version": "OpenHarmony 1.0",
49        "device_company": "MyProductVendor",
50        "board": "MySOC",
51        "enable_ramdisk": true,
52        "build_seccomp": true
53        "subsystems": [
54        {
55            "subsystem": "ace",
56            "components": [
57            { "component": "ace_engine_lite","features":[""] }
58            ]
59        },
60        ...
61        ]
62    }
63    ```
642. 产品代码进行全量编译,生成镜像。
65    ```
66    ./build.sh --product-name 产品名称 --ccache --build-target make_all --target-cpu 指定CPU
67    ```
683. 设备烧写镜像。
69
70### 调测验证
71查看应用进程与系统服务进程是否使能Seccomp机制。
721. 使用Shell命令获取目标进程的进程号target pid。
73    ```
74    ps -ef | grep xxx
75    ```
76    显示信息示例如下,其中1686为target pid。
77    ```
78    media         1686     1 0 08:16:12 ?     00:00:00 xxx
79    root          1869  1678 4 10:32:29 pts/0 00:00:00 grep xxx
80    ```
81
822. 查看进程状态信息来判断Seccomp机制是否使能。
83    ```shell
84    cat /proc/[target pid]/status | grep Seccomp
85    ```
86    显示信息示例如下。
87    ```
88    Seccomp:        2
89    Seccomp_filters:        1
90    ```
91    **表1**  Seccomp使能状态说明
92    |  字段  |  说明  |
93    |  ---  |  ---  |
94    |  Seccomp  |  - 0:未使能;<br>- 1:使能,为严格模式,只允许使用read/write/exit/sigreturn四个系统调用;<br>- 2:使能,filter模式,可通过加载BPF指令集合来使能自定义策略。  |
95    |  Seccomp_filters  |  进程设置Seccomp策略的个数  |
96
97## 进程使能个性化Seccomp策略
98### 场景介绍
99产品已使能Seccomp基本策略的情况下,某个init孵化的Native service进程可以根据实际需要使能自定义的个性化Seccomp策略,以适配进程自身所需的安全要求,此时其它Native service进程的Seccomop策略不变。
100### 开发步骤
1011. 统计32位架构与64架构位需要使用的系统调用,先使用[统计系统调用方法](#统计系统调用方法)的静态分析方法与Strace统计方法,得到Seccomp初始策略。
1022. 编写策略文件,见[普通策略文件编写规则](#普通策略文件编写规则)。
1033. 编写编译BUILD.gn104
105    1.  在业务子系统代码仓内存放编写完成的策略文件,创建BUILD.gn。例如,在业务代码仓创建seccomp_policy文件夹,在该文件中创建策略文件与BUILD.gn106
107        ```shell
108        //path/to/code/seccomp_policy
109        ├── BUILD.gn
110        └── example.seccomp.policy
111        ```
112    2. 为了解析策略文件以及构建策略动态库,在BUILD.gn中需要使用ohos_prebuilt_seccomp模板声明进程的Seccomp策略文件路径等内容。ohos_prebuilt_seccomp模板在//base/startup/init/services/modules/seccomp/scripts/seccomp_policy_fixer.gni中定义,下表为该模板的字段说明。
113
114        **表2**  ohos_prebuilt_seccomp模板字段说明
115        |  字段  |  说明  |
116        |  ---  |  ---  |
117        |  sources  |  必填,策略配置文件的路径。 |
118        |  filtername  |  必填,该内容与进程[引导启动配置文件](subsys-boot-init-cfg.md)中的services name保持一致,否则会使能失败。该字段决定了动态库的名称。例如,将filtername设置为xxx,则编译生成的策略动态库名称为libxxx_filter.z.so。  |
119        |  process_type  |  必填,根据使能进程类型填写不同的字符串。若使能的进程为init孵化的进程,则该字段赋值"system";若是应用进程,则该字段赋值"app"。 |
120        |  part_name  |  必填,部件名。  |
121        |  subsystem_name  |  必填,子系统名。  |
122        |  install_enable  |  必填,是否安装到镜像,为true。  |
123        |  install_images  |  必填,安装的镜像位置。  |
124
125        示例
126        ```python
127        #引入模板文件
128        import("//base/startup/init/services/modules/seccomp/scripts/seccomp_policy_fixer.gni")
129
130        #使用gn模板
131        ohos_prebuilt_seccomp("xxxx_seccomp_filter") {
132            sources = [ "xxxx.seccomp.policy" ]
133
134            filtername = "xxx"
135
136            process_type = "system"
137
138            part_name = "xx_part_name"
139            subsystem_name = "x_subsystem_name"
140
141            install_enable = true
142            install_images = [ "xxxxx" ]
143        }
144        ```
145    3. 在其它BUILD.gn中添加上xxxx_seccomp_filter的编译目标。
146        ```python
147        if (build_seccomp) {
148            deps += [ "path:xxxx_seccomp_filter" ]
149        }
150        ```
1514. 构建策略动态库libxxx_filter.z.so
152    ```shell
153    ./build.sh --product-name 产品名称 --ccache --build-target xxxx_seccomp_filter --target-cpu 指定CPU
154    ```
155    若构建报错,且报错提示信息含以下内容,则该进程需要使用基线黑名单里的系统调用。所以将xx系统调用声明在privileged_process.seccomp.policy中,规则见[特权进程声明名单编写规则](#特权进程声明名单编写规则)。添加声明后,重复此步动作直到编译成功。
156    ```shell
157    xx of allow list is in block list
158    ```
1595. 利用hdc工具将策略动态库推入设备中,并重启。
160    ```shell
161    # 根据安装的镜像位置,推入不同的库路径,例如,安装镜像为system,系统架构为32位,则策略动态库的路径为/system/lib/seccomp/
162    hdc shell mount -rw -o remount /
163    hdc file send /path/to/libxxx_filter.z.so /path/to/lib(or lib64)/seccomp/
164    hdc shell reboot
165    ```
1666. 使用[Audit统计](#audit统计)对Seccomp策略进行查漏补缺,重复执行4-6步直到进程能正常运行。
167
168### 调测验证
1691. 若目标进程原先未使能Seccomp机制,则[查看目标进程的Seccomp状态](#调测验证)来判断其是否使能。
1702. 若进程被终止,且内核日志里有相关Audit审计日志,则说明Seccomp策略已使能,但统计的策略名单不完整。Audit审计日志示例在[Audit统计](#audit统计)章节中。
1713. 若进程未被终止,则进程注释Seccomp策略文件中uid设置相关的系统调用(例如,setuid)。重新进行编译策略动态库、推库以及重启进程,查看该进程是否会被Seccomp机制终止。若进程被终止,则说明Seccomp策略已使能。
172
173## 常见问题
174### 如何确定进程终止的是Seccomp机制引起的
175**现象描述**
176
177当发生一定条件时进程被终止,但不确定该情况是否是由Seccomp机制引起。
178
179**解决方法**
180
181以下为两种解决方法。
182
183- 查看进程的崩溃栈回溯的内容,若内容中显示的原因信号为SIGSYS,则是Seccomp机制引起。利用Shell查看崩溃回溯的内容。
184    ```shell
185    cat /data/log/faultlog/faultlogger/进程的崩溃栈回溯日志
186    ```
187    示例信息
188    ```shell
189    Generated by HiviewDFX@OpenHarmony
190    ================================================================
191    Device info:xxx
192    Build info:xxx
193    Module name:xxx
194    Pid:xxxx
195    Uid:xxxxx
196    Reason:Signal:SIGSYS(UNKNOWN)
197    ...
198    ```
199- 查看Seccomp机制关闭后进程是否依旧被终止。若Seccomp机制被关闭后进程能正常运行,则进程终止由Seccomp机制引起。
200
201    Seccomp机制默认打开,当设备操作模式为root模式时,利用Shell命令行设置系统参数关闭整个系统的Seccomp机制。
202    ```shell
203    # 设置相关系统参数关闭Seccomp机制后重启
204    param set persist.init.debug.seccomp.enable 0; reboot
205    # 设置相关系统参数开启Seccomp机制后重启
206    param set persist.init.debug.seccomp.enable 1; reboot
207    ```
208
209## 参考
210### Seccomp代码目录结构
211```
212base/startup/init/services/modules/seccomp
213├── BUILD.gn
214├── gen_syscall_name_nrs.c
215├── scripts
216│   ├── generate_code_from_policy.py        # 策略文件的解析脚本
217│   ├── seccomp_policy_fixer.gni            # 生成策略动态库的gn模板定义
218│   └── tools                               # 存放辅助统计系统调用脚本
219├── seccomp_policy                          # 存放基础策略文件的文件夹
220│   ├── app.blocklist.seccomp.policy
221│   ├── app.seccomp.policy
222│   ├── privileged_process.seccomp.policy
223│   ├── renderer.seccomp.policy
224│   ├── spawn.seccomp.policy
225│   ├── system.blocklist.seccomp.policy
226│   └── system.seccomp.policy
227├── seccomp_policy.c                        # Seccomp实现核心源码
228└── seccomp_policy_static.c                 # Seccomp插件化源码
229```
230
231### 策略文件说明
232- 存放位置在//base/startup/init/services/modules/seccomp/seccomp_policy233- 策略基础文件
234
235    **表3**  策略文件说明
236    |  策略文件  |  说明  |
237    |  ---  |  ---  |
238    |  system.seccomp.policy  | 大部分系统服务进程使能的Seccomp策略 |
239    |  system.blocklist.seccomp.policy  | 系统进程的系统调用基线黑名单,即非特权进程禁止使用的系统调用名单。 |
240    |  app.seccomp.policy  | 所有应用进程使能的Seccomp策略 |
241    |  app.blocklist.seccomp.policy  | 应用进程的系统调用基线黑名单,即应用进程禁止使用的系统调用名单。 |
242    |  spawn.seccomp.policy  | appspawn进程与nwebspawn进程使能的Seccomp策略 |
243    |  renderer.seccomp.policy  | 由nwebspawn孵化的渲染进程使能的Seccomp策略 |
244    |  privileged_process.seccomp.policy  | 特权进程声明名单,即某些进程需使用基线黑名单系统调用时,可在此文件中声明进程标识符与需使用的基线黑名单。 |
245
246### 普通策略文件编写规则
247- 若要声明配置项,以“@”加配置项的形式书写,例如,@returnValue。
248- 配置项的下一行开始到下一个配置项开始之前为配置项内容。
249- 若要在文件中增加注释,在行首添加“#”。
250- 目前支持的架构为arm/arm64251- 系统调用与架构用“;”隔开,all表示支持的所有架构会使用该系统调用。
252- 除了returnValue字段,其它都是选填项。
253
254**表4**  策略文件配置项说明
255
256|  配置项  |  说明  | 规则  |
257|  ---  |  ---  |  --  |
258|  returnValue  |  返回值  |  必填,范围为:<br>- LOG:宽容模式,只记录Audit日志,不会终止进程;<br>- TRAP:终止进程,且可交给faultloggerd处理;<br>- KILL_PROCESS:终止进程。 <br>- KILL_THREAD:终止线程。  |
259|  headFiles  |  头文件,用于声明allowListWithArgs与priorityWithArgs字段中出现的宏。 |  格式上:用""、<>来包含头文件名称,例如 <abc.h>、"cde.h" 默认有的头文件:<linux/filter.h>、<stddef.h>、<linux/seccomp.h>、<audit.h>。  |
260|  priority  |  频繁使用的系统调用白名单  |  在策略中优先判断,用于提高性能。  |
261|  priorityWithArgs  |  频繁使用的带参数限制的系统调用白名单  |  在策略中优先判断,用于提高性能。  |
262|  allowList  |  白名单  |  进程允许的系统调用  |
263|  allowListWithArgs  |  带参数限制白名单  |  其中系统调用名称与参数限制说明用“:”隔开,判断符号可用<、<=、>、>=、==、!=、&,逻辑符号可用&&、\|\|。<br>系统调用的第几个参数,使用argn表示,n的范围为0~5。判断语句用“if”开头,else语句结尾。语句结束后需声明返回值,判断语句与返回值使用“;”隔开。<br>声明返回值的样式为“return xxx”,xxx的范围与returnValue一致。若有多重判断条件,判断条件之间可使用elif隔开。 |
264|  blockList  |  黑名单  |  在解析策略过程中,生成BPF指令前会检查白名单中的系统调用会不会存在于黑名单中。若存在,则会出现解析错误的信息。 |
265|  selfDefineSyscall  |  自定义系统调用  |  填写的内容为数字。  |
266
267举例说明example.seccomp.policy
268
269```
270@returnValue
271TRAP
272
273@headFiles
274"time.h"
275
276@priority
277ioctl;all
278
279@allowList
280openat;all
281close;all
282lseek;all
283read;all
284write;all
285setresuid;arm64
286setresgid;arm64
287setresuid32;arm
288setresgid32;arm
289
290@allowListWithArgs
291clock_getres:if arg0 >= CLOCK_REALTIME && arg0 <= CLOCK_BOOTTIME; return ALLOW; else return TRAP;all
292
293@blockList
294swapon;all
295
296@selfDefineSyscall
297787
298```
299
300### 特权进程声明名单编写规则
301- 若要声明配置项,以“@”+配置项的形式书写,例如,@allowBlockList。
302- 配置项的下一行开始到下一个配置项开始之前为配置项内容。
303- 若要在文件中增加注释,在行首添加“#”。
304- 目前支持的架构为arm/arm64305- 系统调用与架构用“;”隔开,all表示支持的所有架构会使用该系统调用。
306
307**表5**  特权进程策略文件配置项说明
308|  配置项  |  说明  | 规则  |
309|  ---  |  ---  |  --  |
310|  privilegedProcessName  |  进程名标识符  |  native service进程的启动引导文件中services内容中name对应的字符串 |
311|  allowBlockList  |  可使用的基线黑名单  |  填写系统调用与架构 |
312
313举例,以下表示process1和process2进程需要使用基线黑名单中的swapon系统调用。
314```
315@privilegedProcessName
316process1
317
318@allowBlockList
319swapon;all
320
321@privilegedProcessName
322process2
323
324@allowBlockList
325swapon;all
326```
327
328### 统计系统调用方法
329**表6**  统计方法对比说明
330|  统计方法  |  基本方法  |  优点  |  缺点  |
331|  ---  |  ---  |  ---  |  ---  |
332|  <div style="width: 50pt">静态分析  | <div style="width: 300pt">分析ELF反汇编代码得到调用关系,统计调用libc库的接口集合,解析libc库得到libc接口与系统调用号的调用关系,从而得到ELF文件使用的系统调用号。 |  <div style="width: 100pt">可以统计到异常分支的系统调用。  |  <div style="width: 100pt">不支持解析指针函数的调用关系。  |
333|  Strace工具统计  | 设备运行时,使用Strace跟踪业务进程。跟踪过程中会将系统调用的执行记录下来。收集日志后使用脚本解析日志生成Seccomp策略文件。 |  操作简单  |  代码分支全部覆盖才能完整统计使用的系统调用。  |
334|  Audit统计  | 进程使能Seccomp策略后,Seccomp机制会拦截非法系统调用,在内核日志生成含系统调用号信息的Audit日志。收集日志后使用脚本解析日志生成Seccomp策略文件。 |  可对上面两个方法进行查漏补缺。  |  日志有丢失的风险。<br>代码分支全部覆盖才能完整统计使用的系统调用。  |
335
336#### 静态分析
3371. 环境准备
338    1. 准备linux环境。
339    2. 下载交叉编译器arm-linux-musleabi与aarch64-linux-musl。
340        ```shell
341        wget https://musl.cc/arm-linux-musleabi-cross.tgz
342        wget https://musl.cc/aarch64-linux-musl-cross.tgz
343
344        tar -zxvf arm-linux-musleabi-cross.tgz
345        tar -zxvf aarch64-linux-musl-cross.tgz
346
347        # 将执行工具路径加入环境变量。
348        export PATH=$PATH:/path/to/arm-linux-musleabi-cross/bin
349        export PATH=$PATH:/path/to/aarch64-linux-musl-cross/bin
350        ```
351
352    3. 下载OpenHarmony源代码,见[下载说明](../get-code/sourcecode-acquire.md)。
353
3542. 通过编译seccomp_filter得到静态分析的依赖文件libsyscall_to_nr_arm与libsyscall_to_nr_arm64。
355
356    seccomp_filter在base/startup/init/services/modules/seccomp/BUILD.gn中声明,用于构建Seccomp的基础策略动态库。依赖文件最终会生成在//out/产品名称/gen/base/startup/init/services/modules/seccomp/gen_system_filter/路径中。
357    ```shell
358    ./build.sh --product-name 产品名称 --ccache --build-target seccomp_filter --target-cpu 指定CPU
359
360    # 将统计所依赖的文件复制到工具文件夹以备使用
361    cp out/产品名称/gen/base/startup/init/services/modules/seccomp/gen_system_filter/libsyscall_to_nr_arm* base/startup/init/services/modules/seccomp/scripts/tools/
362    ```
363
3643. 复制generate_code_from_policy.py到统计系统调用工具的文件夹内。该脚本存在于//base/startup/init/services/modules/seccomp/scripts/路径下
365    ```shell
366    # 进入OpenHarmony代码根目录
367    cd /root/to/OpenHarmonyCode;
368    # 进入generate_code_from_policy.py所在目录
369    cd base/startup/init/services/modules/seccomp/scripts/;
370    # 复制generate_code_from_policy.py
371    cp generate_code_from_policy.py tools/;
372    ```
373
3744. 编译业务代码相关的ELF文件,由于32位架构的ELF文件反汇编代码跳转机制较复杂,故统一编译成64位ELF文件用来解析函数调用关系。
375    ```shell
376    ./build.sh --product-name 产品文件 --ccache --target-cpu arm64 --build-target 目标文件
377    ```
378
3795. 若此前未进行全量编译,且第4步依赖的动态库未在//out文件夹下,则通过执行以下命令将业务依赖的相关动态库复制到//out目录下。以下为参考操作,若还依赖其它动态库,请自行复制。
380    ```shell
381    # 先进入代码根目录
382    cd /root/to/OpenHarmonyCode
383    # 在out/产品名称/lib.unstripped/下创建aarch64-linux-ohos文件夹存放依赖的动态库
384    mkdir out/产品名称/lib.unstripped/aarch64-linux-ohos
385    # 复制相关动态库到out目录下
386    cp prebuilts/clang/ohos/${host_platform_dir}/llvm/lib/clang/${clang_version}/lib/aarch64-linux-ohos/*.so out/产品名称/lib.unstripped/aarch64-linux-ohos/
387    cp prebuilts/clang/ohos/${host_platform_dir}/${clang_version}/llvm/lib/aarch64-linux-ohos/*.so out/产品名称/lib.unstripped/aarch64-linux-ohos/
388    ```
389
3906. 修改collect_elf_syscall.py脚本文件,将objdump与readelf工具的路径从空修改为工具在linux环境下的绝对路径。脚本文件存放在base/startup/init/services/modules/seccomp/scripts/tools/下。objdump与readelf工具存放在//prebuilts文件夹内部。
391    ```python
392    #modified the path of objdump and readelf path
393    def get_obj_dump_path():
394        obj_dump_path = '/path/to/llvm-objdump'
395        return obj_dump_path
396
397
398    def get_read_elf_path():
399        read_elf_path = '/path/to/llvm-readelf'
400        return read_elf_path
401    ```
402
4037. 使用脚本解析生成对应的策略文件xxx.seccomp.policy
404
405    **表7**  collect_elf_syscall.py的参数说明
406    |  参数  |  说明  |
407    |  ---  |  ---  |
408    |  --src-elf-path  | ELF文件所在文件夹,例如,~/ohcode/out/rk3568,不以'/'结尾。|
409    |  --elf-name| ELF文件名,例如,libmedia_service.z.so。|
410    |  --src-syscall-path  |  libsyscall_to_nr_arm或libsyscall_to_nr_arm64,与--target-cpu架构对应。  |
411    |  --target-cpu  |  架构号,表示需要统计系统调用的对应架构,该参数影响解析何种架构的libc文件,arm或arm64。  |
412    |  --filter-name  | 生成的策略文件名名称,例如,输入值为test,生成的文件名为test.seccomp.policy。  |
413
414    使用collect_elf_syscall.py解析ELF文件。
415
416        ```
417        # 产品以rk3568,ELF文件以libmedia_service.z.so为示例
418        python3 collect_elf_syscall.py --src-elf-path ~/ohcode/out/rk3568 --elf-name libmedia_service.z.so --src-syscall-path libsyscall_to_nr_arm64 --target-cpu arm64 --filter-name media_service
419        ```
420
421        xxx.seccomp.policy结果示例
422        ```
423        @allowList
424        getcwd;arm64
425        eventfd2;arm64
426        epoll_create1;arm64
427        epoll_ctl;arm64
428        dup;arm64
429        dup3;arm64
430        fcntl;arm64
431        ioctl;arm64
432        ...
433        ```
434
435#### Strace统计
4361. 使用arm-linux-musleabi与aarch64-linux-musl交叉编译器分别构建32位与64的Strace工具。
4372. [跟踪业务进程](#跟踪业务进程),得到Strace日志。
4383. 利用脚本[解析Strace日志](#解析strace日志文件),得到Seccomp策略文件。
439##### 跟踪业务进程
4401. 在init仓代码中进行嵌入式修改,修改文件为//base/startup/init/services/init/init_common_service.c,在执行SetSystemseccompPolicy函数设置Seccomp策略前增加以下内容。以下为修改内容。其中行首符号为“+”,则该行为新增内容,若符号为“-”,则是需删除的内容,“xxxx”与进程[引导启动配置文件](subsys-boot-init-cfg.md)中的Services name保持一致。
441    ```c
442    --- a/services/init/init_common_service.c
443    +++ b/services/init/init_common_service.c
444    @@ -155,7 +155,19 @@ static int SetPerms(const Service *service)
445        // set seccomp policy before setuid
446        INIT_ERROR_CHECK(SetSystemseccompPolicy(service) == SERVICE_SUCCESS, return SERVICE_FAILURE,
447            "set seccomp policy failed for service %s", service->name);
448    -
449    +    if (strncmp(service->name, "xxxx", strlen("xxxx")) == 0) {
450    +        pid_t pid = getpid();
451    +        pid_t pid_child = fork();
452    +        if (pid_child == 0) {
453    +            char pidStr[9] = {0};
454    +            sprintf_s(pidStr, 6, "%d", pid);
455    +            if (execl("/system/bin/strace", "/system/bin/strace", "-p", (const char *)pidStr, "-ff", "-o", "/data/strace/xxxx.strace.log", NULL) !=0 ) {
456    +                INIT_LOGE("strace failed");
457    +            }
458    +        }
459    +        sleep(5);
460    +    }
461        if (service->servPerm.uID != 0) {
462            if (setuid(service->servPerm.uID) != 0) {
463                INIT_LOGE("setuid of service: %s failed, uid = %d", service->name, service->servPerm.uID);
464    ```
4652. 修改文件后进行全量编译,并烧写镜像。
4663. 关闭SElinux机制,将Strace工具推入设备中。
467    ```shell
468    hdc shell setenforce 0
469    hdc shell mount -rw -o remount /
470    hdc file send /path/to/strace /system/bin/
471    hdc shell chmod a+x /system/bin/strace
472    ```
4734. 创建存放Strace日志的的文件夹。
474    ```shell
475    hdc shell mkdir -p /data/strace
476    ```
4775. 终止业务进程,令其重启。可使用以下命令,xxx为业务进程名。
478    ```shell
479    kill -9 $(pidof xxx)
480    ```
4816. 对设备进行相关业务操作,尽量使代码全量覆盖。
4827. 从设备中/data/strace文件夹取出Strace日志到解析脚本的路径下。
483    ```shell
484    hdc file recv /data/strace /path/to/base/startup/init/services/modules/seccomp/scripts/tools/
485    ```
486
487##### 解析Strace日志文件
4881. 将解析日志时所依赖的文件复制到Strace日志文件夹,该依赖文件为[静态分析](#静态分析)第2步的产物。
489    ```shell
490    cp out/产品名称/gen/base/startup/init/services/modules/seccomp/gen_system_filter/libsyscall_to_nr_arm* base/startup/init/services/modules/seccomp/scripts/tools/strace/
491    ```
492
4932. 使用脚本解析生成对应的策略文件xxx.seccomp.policy494
495    脚本strace_log_analysis.py在//base/startup/init/services/modules/seccomp/scripts/tools/路径下
496
497    **表8**  strace_log_analysis.py的参数说明
498    |  参数  |  说明  |
499    |  ---  |  ---  |
500    |  --src-path  | 日志文件所在文件夹,需含libsyscall_to_nr_arm与libsyscall_to_nr_arm64例如,./strace,不以'/'结尾。|
501    |  --target-cpu  |  架构号,与跟踪进程的对应的架构一致,arm或arm64。  |
502    |  --filter-name  | 生成的策略文件名名称,例如,输入值为test,生成的文件名为test.seccomp.policy。  |
503
504    使用strace_log_analysis.py解析Strace日志。
505    ```shell
506    cd base/startup/init/services/modules/seccomp/scripts/tools;
507    python3 strace_log_analysis.py --src-path strace --target-cpu 指定CPU --filter-name xxx
508    ```
509    xxx.seccomp.policy结果示例
510    ```
511    @allowList
512    getcwd;arm64
513    eventfd2;arm64
514    epoll_create1;arm64
515    epoll_ctl;arm64
516    dup;arm64
517    dup3;arm64
518    fcntl;arm64
519    ioctl;arm64
520    ...
521    ```
522
523#### Audit统计
5241. 使能初始Seccomp策略,使能方法见[进程使能个性化Seccomp策略](#进程使能个性化seccomp策略)章节的开发步骤。
5252. 获取日志
526    1. 利用Shell命令创建存放日志的文件夹。
527        ```shell
528        mkdir -p /data/audit
529        ```
530    2. 利用Shell命令获取内核日志中与Seccomp相关的Audit日志,存放的日志以“.audit.log”结尾。
531        ```shell
532        cat /proc/kmsg | grep type=1326 > /data/audit/media_service.audit.log
533        ```
5343. 进行业务相关操作与触发段错误操作。
535    1. 执行触发段错误的方法:在业务代码加入以下代码,并在某处调用TriggerSegmentFault,对镜像重新进行构建及烧写。
536        ```c
537        static void TriggerSegmentFault(void)
538        {
539            pid_t pid_child = fork();
540            if (pid_child == 0) {
541                char *test = (char *)0x1234;
542                *test = 1;
543            }
544        }
545        ```
546    2. 设备启动后,利用Shell临时关闭SElinux,并终止业务进程,该进程会自动重启。
547        ```shell
548        setenforce 0
549        ```
550
5514. 利用hdc命令从设备的/data/audit文件夹取出Audit日志到解析脚本的路径下。
552    ```shell
553    hdc file recv /data/audit /path/to/base/startup/init/services/modules/seccomp/scripts/tools/
554    ```
5555. 解析Audit日志。
556
557    Audit日志示例
558    ```shell
559    <5>[  198.963101] audit: type=1326 audit(1659528178.748:27): auid=4294967295 uid=0 gid=1000 ses=4294967295 subj=u:r:appspawn:s0 pid=2704 comm="config_dialog_s" exe="/system/bin/appspawn" sig=31 arch=40000028 syscall=208 compat=1 ip=0xf7b79400 code=0x80000000
560    ```
561    **表9**  Audit日志关键字段说明
562    |  参数  |  说明  |
563    |  ---  |  ---  |
564    |  type  |  类型,值为1326说明是seccomop类型日志。  |
565    |  sig  |  信号量,31为SIGSYS,表示Seccomp发生拦截时给进程发出的信号。  |
566    |  arch  |  架构标识,值为40000028表示arm,值为c00000b7表示arm64。  |
567    |  syscall  |  系统调用号  |
568    |  compat  |  1表示为兼容模式,即arm64的内核使用了arm的系统调用。 |
569
570
571    1. 将解析日志时所依赖的文件复制到日志文件夹以备使用,该依赖文件为[静态分析](#静态分析)第2步的产物。
572        ```shell
573        cp out/产品名称/gen/base/startup/init/services/modules/seccomp/gen_system_filter/libsyscall_to_nr_arm* base/startup/init/services/modules/seccomp/scripts/tools/audit/
574        ```
575    2. 使用audit_log_analysis.py脚本解析日志生成xxx.seccomp.policy。工具路径在//base/startup/init/services/modules/seccomp/scripts/tools/下。
576
577        **表10**  audit_log_analysis.py的参数说明
578        |  参数  |  说明  |
579        |  ---  |  ---  |
580        |  --src-path  | 日志文件所在文件夹,需含libsyscall_to_nr_arm与libsyscall_to_nr_arm64。例如,./audit,不以'/'结尾。|
581        |  --filter-name  | 生成的策略文件名名称,例如,输入值为test,生成的文件名为test.seccomp.policy。 |
582
583        ```shell
584        cd base/startup/init/services/modules/seccomp/scripts/tools
585        python3 audit_log_analysis.py --src-path audit --filter-name xxx
586        ```
587
588### 合并多个策略文件
589[统计系统调用](#统计系统调用方法)的执行过程中,可能会生成多个策略文件,这些策略文件中系统调用可能会有重复或者乱序。通过以下步骤可将多个策略文件进行合并、去重,按照arm64/arm顺序,系统调用号从小到大排序。
590
591**表11**  merge_policy.py的参数说明
592|  参数  |  说明  |
593|  ---  |  ---  |
594|  --src-files  | 需处理的文件,需含libsyscall_to_nr_arm与libsyscall_to_nr_arm64。 |
595|  --filter-name  | 生成的策略文件名名称,例如,输入值为test,生成的文件名为test.seccomp.policy。  |
5961. 将合并文件所依赖的文件复制到日志文件夹以备使用。
597    ```shell
598    cp out/产品名称/gen/base/startup/init/services/modules/seccomp/gen_system_filter/libsyscall_to_nr_arm* base/startup/init/services/modules/seccomp/scripts/tools/
599    ```
6002. 使用merge_policy.pypolicy1.seccomp.policypolicy2.seccomp.policy策略文件合并成xxxx.seccomp.policy601    ```shell
602    python3 merge_policy.py --src-files libsyscall_to_nr_arm --src-files libsyscall_to_nr_arm64 --src-files policy1.seccomp.policy --src-files policy2.seccomp.policy --filter-name xxxx
603    ```