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.gn。 104 105 1. 在业务子系统代码仓内存放编写完成的策略文件,创建BUILD.gn。例如,在业务代码仓创建seccomp_policy文件夹,在该文件中创建策略文件与BUILD.gn。 106 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_policy中 233- 策略基础文件 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/arm64。 251- 系统调用与架构用“;”隔开,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/arm64。 305- 系统调用与架构用“;”隔开,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.policy。 494 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.py将policy1.seccomp.policy,policy2.seccomp.policy策略文件合并成xxxx.seccomp.policy。 601 ```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 ```