嵌入式Linux安全加固:SELinux、Capabilities与Seccomp——强制访问控制与沙箱

文章目录


每日一句正能量

人生要活得洒脱,就是三要素,无所谓,没必要,不至于。

对别人的评价、无伤大雅的得失,不必挂心。对消耗你的人、争不出对错的事,及时止损。把灾难化想象拉回现实------天塌不下来,别自己吓自己。用好这三词,能省下90%的内耗。

摘要

摘要: 在物联网和边缘计算时代,嵌入式Linux设备面临日益严峻的安全威胁。本文系统性地剖析Linux安全架构的四层防御体系------从DAC到MAC、Capabilities再到Seccomp,深入讲解SELinux的类型强制机制、Capabilities的细粒度权限拆分以及Seccomp的系统调用沙箱技术,结合嵌入式场景提供可直接落地的配置代码与安全策略。


一、引言:嵌入式设备的安全困境

嵌入式Linux设备正成为网络攻击的主要目标:

  • 攻击面扩大:IoT设备数量预计2026年超过300亿,每个设备都是潜在入口
  • 资源受限:ARM SoC通常只有512MB~2GB RAM,无法运行重量级安全软件
  • 生命周期长:工业设备运行10年以上,安全补丁难以持续更新
  • 物理暴露:边缘设备部署在不可控环境,易被物理接触
  • 传统方案不足:仅靠UGO权限(DAC)无法阻止被攻破后的横向移动

Linux内核提供了四层安全防御体系:DAC(自主访问控制)→ MAC(强制访问控制)→ Capabilities(细粒度权限)→ Seccomp(系统调用沙箱)。本文将逐层深入讲解。


二、Linux安全架构全景

2.1 四层防御体系

图1:嵌入式 Linux 安全架构层次

各层安全机制对比:

层次 机制 控制粒度 核心思想 嵌入式适用性
L1 DAC (UGO) 用户/组级别 资源所有者决定权限 基础,但不足
L2 MAC (SELinux) 进程/文件类型 策略决定一切,无视所有者 强烈推荐
L3 Capabilities 单个权限位 拆分root为41个独立权限 强烈推荐
L4 Seccomp 系统调用级别 白名单过滤,禁止未授权调用 强烈推荐

安全的核心原则:纵深防御(Defense in Depth)。单一安全机制无法阻止所有攻击,多层叠加才能最大限度降低风险。


三、SELinux:强制访问控制的基石

3.1 SELinux核心机制

SELinux(Security-Enhanced Linux)由美国国家安全局(NSA)开发,是Linux上最成熟的MAC实现。其核心是类型强制(Type Enforcement, TE):

图2:SELinux 安全上下文与访问决策流程

安全上下文格式:

复制代码
user:role:type:level
  │     │    │     │
  │     │    │     └─ MLS/MCS安全级别(如s0-s15)
  │     │    └─ 类型(最关键,如httpd_t)
  │     └─ 角色(如system_r)
  └─ 用户标识(如system_u)

类型强制(TE)规则示例:

te 复制代码
# httpd进程(httpd_t)可以读取httpd_sys_content_t类型的文件
allow httpd_t httpd_sys_content_t:file { read getattr open };

# httpd进程不能读取shadow_t类型的文件(密码文件)
# 无allow规则 = 默认拒绝
# 尝试读取将产生AVC拒绝日志

3.2 嵌入式设备SELinux配置

bash 复制代码
# 1. 内核配置启用SELinux
# File systems → Security options
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SELINUX_BOOTPARAM=y
CONFIG_SECURITY_SELINUX_DISABLE=y
CONFIG_SECURITY_SELINUX_DEVELOP=y
CONFIG_SECURITY_SELINUX_AVC_STATS=y
CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=0

# 2. 启动参数配置(bootargs)
selinux=1 enforcing=0  # 首次启用建议Permissive模式
# 或
selinux=1 enforcing=1  # 生产环境强制模式

# 3. 安装SELinux工具
# Yocto/Buildroot添加:
# IMAGE_INSTALL:append = " libselinux libsemanage policycoreutils"
# 或
# apt-get install selinux-utils selinux-basics policycoreutils

# 4. 查看SELinux状态
getenforce              # 查看当前模式:Enforcing/Permissive/Disabled
sestatus                # 详细状态
cat /proc/1/attr/current # 查看init进程的安全上下文

# 5. 切换模式(运行时)
setenforce 0            # 切换到Permissive(仅记录,不阻止)
setenforce 1            # 切换到Enforcing(强制模式)

# 6. 查看安全上下文
ls -Z /etc/passwd       # 文件上下文
ps -eZ | head           # 进程上下文
id -Z                   # 当前用户上下文

3.3 自定义嵌入式策略

te 复制代码
# embedded_device.te - 嵌入式设备自定义SELinux策略

policy_module(embedded_device, 1.0.0)

# 定义类型
type embedded_app_t;           # 应用进程类型
type embedded_app_exec_t;        # 应用可执行文件类型
type embedded_data_t;            # 应用数据文件类型
type embedded_conf_t;            # 配置文件类型
type embedded_log_t;             # 日志文件类型
type embedded_device_t;          # 设备文件类型

# 定义角色
role system_r types embedded_app_t;

# 应用可执行文件类型
typeattribute embedded_app_exec_t file_type, exec_type;

# 文件类型属性
typeattribute embedded_data_t file_type;
typeattribute embedded_conf_t file_type;
typeattribute embedded_log_t file_type;

# 规则:应用进程可以执行应用二进制
allow embedded_app_t embedded_app_exec_t:file { read execute execute_no_trans };

# 规则:应用可以读写自己的数据
allow embedded_app_t embedded_data_t:file { create read write getattr unlink };
allow embedded_app_t embedded_data_t:dir { create read write getattr search add_name remove_name };

# 规则:应用可以读取配置
allow embedded_app_t embedded_conf_t:file { read getattr open };

# 规则:应用可以写日志
allow embedded_app_t embedded_log_t:file { create append getattr };
allow embedded_app_t embedded_log_t:dir { create read write getattr search add_name };

# 规则:应用可以访问设备
allow embedded_app_t embedded_device_t:chr_file { read write ioctl getattr };
allow embedded_app_t embedded_device_t:blk_file { read write ioctl getattr };

# 规则:应用可以网络通信(可选)
allow embedded_app_t self:tcp_socket { create connect read write getattr setopt getopt };
allow embedded_app_t self:udp_socket { create connect read write getattr };

# 规则:应用可以发送信号给自己
allow embedded_app_t self:process { signal };

# 禁止:应用不能访问其他应用数据
# 无allow规则 = 默认拒绝

# 禁止:应用不能访问系统密码文件
# 无allow规则 = 默认拒绝

# 文件上下文规则
# /opt/myapp/bin/myapp  -> embedded_app_exec_t
# /data/myapp/*           -> embedded_data_t
# /etc/myapp/*            -> embedded_conf_t
# /var/log/myapp/*        -> embedded_log_t
# /dev/mydevice           -> embedded_device_t
bash 复制代码
# 编译和加载自定义策略
# 1. 编译模块
checkmodule -M -m -o embedded_device.mod embedded_device.te
semodule_package -o embedded_device.pp -m embedded_device.mod

# 2. 加载模块
semodule -i embedded_device.pp

# 3. 设置文件上下文
semanage fcontext -a -t embedded_app_exec_t "/opt/myapp/bin/myapp"
semanage fcontext -a -t embedded_data_t "/data/myapp(/.*)?"
semanage fcontext -a -t embedded_conf_t "/etc/myapp(/.*)?"
semanage fcontext -a -t embedded_log_t "/var/log/myapp(/.*)?"

# 4. 应用上下文
restorecon -R /opt/myapp /data/myapp /etc/myapp /var/log/myapp

# 5. 验证
ls -Z /opt/myapp/bin/myapp
ps -eZ | grep myapp

3.4 AVC日志分析与故障排查

bash 复制代码
# 1. 查看AVC拒绝日志
cat /var/log/audit/audit.log | grep AVC
ausearch -m avc -ts recent

# 2. 使用audit2why分析原因
cat /var/log/audit/audit.log | audit2why

# 3. 使用audit2allow生成策略模块(谨慎使用!)
cat /var/log/audit/audit.log | audit2allow -M mylocal
semodule -i mylocal.pp

# 4. 查看详细审计日志
ausearch -m avc -ts today -i

# 5. 嵌入式设备日志转发(资源受限)
# 配置rsyslog将audit日志发送到远程服务器
cat <<EOF >> /etc/rsyslog.conf
:programname, isequal, "audit" @@logserver:514
EOF

3.5 SELinux与其他LSM对比

特性 SELinux AppArmor Smack TOMOYO
控制粒度 对象级(类型) 路径级 标签级 路径级
学习曲线 陡峭 中等 平缓 平缓
性能影响 较高 中等 低 低
嵌入式适用 高安全需求 通用 IoT设备 分析用途
策略维护 复杂 中等 简单 简单
容器支持 优秀 良好 一般 一般

对于高安全需求的嵌入式设备(如工业控制、医疗设备),推荐SELinux;对于资源极度受限的IoT设备,Smack是更轻量的选择。


四、Capabilities:拆分root权限

4.1 从root到41个独立权限

传统Linux中,root用户拥有所有权限。Capabilities机制将root的特权拆分为41个独立的权限位,实现最小权限原则:

图3:Linux Capabilities 权限拆分

核心Capabilities列表:

Capability 功能 嵌入式场景
CAP_NET_ADMIN 网络配置(接口/IP/路由) 网络管理应用
CAP_NET_RAW 原始套接字(ping/抓包) 网络诊断工具
CAP_DAC_OVERRIDE 绕过文件权限检查 备份/恢复工具
CAP_SYS_ADMIN 系统管理(挂载/命名空间) 容器运行时
CAP_SYS_TIME 修改系统时间 NTP服务
CAP_SYSLOG 读取内核日志 日志收集器
CAP_IPC_LOCK 锁定共享内存 实时应用
CAP_CHOWN 修改文件所有者 文件管理器

4.2 嵌入式设备Capabilities配置

bash 复制代码
# 1. 查看进程的Capabilities
getcap /usr/bin/ping
# 输出:/usr/bin/ping = cap_net_raw+ep

# 2. 查看当前进程的Capabilities
capsh --print

# 3. 为应用分配Capabilities(替代setuid root)
# 示例:网络监控工具需要原始套接字,但不需要root
setcap cap_net_raw,cap_net_admin=+ep /usr/bin/my-network-tool

# 4. 查看文件Capabilities
getcap /usr/bin/my-network-tool

# 5. 移除Capabilities
setcap -r /usr/bin/my-network-tool

# 6. 在systemd服务中使用Capabilities
cat <<EOF > /etc/systemd/system/my-app.service
[Unit]
Description=My Embedded Application

[Service]
Type=simple
ExecStart=/usr/bin/my-app
User=appuser
Group=appuser

# 分配Capabilities(比root更安全)
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_DAC_READ_SEARCH
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_DAC_READ_SEARCH

# 安全加固
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable my-app.service

4.3 编程接口:动态管理Capabilities

c 复制代码
// capabilities_demo.c
// 演示如何在程序中动态管理Capabilities

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/capability.h>
#include <sys/prctl.h>

// 打印当前Capabilities
void print_capabilities() {
    cap_t caps = cap_get_proc();
    if (!caps) {
        perror("cap_get_proc");
        return;
    }
    
    char *cap_text = cap_to_text(caps, NULL);
    printf("Current capabilities: %s\n", cap_text);
    
    cap_free(cap_text);
    cap_free(caps);
}

// 丢弃所有Capabilities(进入最小权限模式)
int drop_all_capabilities() {
    cap_t empty = cap_init();
    if (!empty) {
        perror("cap_init");
        return -1;
    }
    
    if (cap_set_proc(empty) != 0) {
        perror("cap_set_proc");
        cap_free(empty);
        return -1;
    }
    
    cap_free(empty);
    printf("All capabilities dropped\n");
n    return 0;
n}

// 只保留指定的Capabilities
int retain_capabilities(cap_value_t caps_to_keep[], int num_caps) {
    cap_t new_caps = cap_init();
    if (!new_caps) {
       perror("cap_init");
       return -1;
        }
    // 设置有效集和允许集
    if (cap_set_flag(new_caps, CAP_PERMITTED, num_caps, caps_to_keep, CAP_SET) != 0 ||
    cap_set_flag(new_caps, CAP_EFFECTIVE, num_caps, caps_to_keep, CAP_SET) != 0) {
          perror("cap_set_flag");
          cap_free(new_caps);
          return -1;
          }
     if (cap_set_proc(new_caps) != 0) {
       perror("cap_set_proc");
       cap_free(new_caps);
       return -1;
       }
     cap_free(new_caps);
     printf("Retained only specified capabilities\n");
     return 0;
     }

// 提升特定Capability(从允许集到有效集)
int raise_capability(cap_value_t cap) {
    cap_t caps = cap_get_proc();
    if (!caps) {
        perror("cap_get_proc");
        return -1;
        }
   // 检查是否在允许集中
   cap_flag_value_t flag;
   if (cap_get_flag(caps, cap, CAP_PERMITTED, &flag) != 0 || flag != CAP_SET) {
         fprintf(stderr, "Capability not permitted\n");
         cap_free(caps);
         return -1;
         }
   // 添加到有效集
   cap_value_t cap_list[1] = {cap};
   if (cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET) != 0) {
       perror("cap_set_flag");
       cap_free(caps);
       return -1;
        }
    if (cap_set_proc(caps) != 0) {
       perror("cap_set_proc");
       cap_free(caps);
       return -1;
        }
     cap_free(caps);
     printf("Raised capability: %s\n", cap_to_name(cap));
     return 0;
     }

// 降低特定Capability(从有效集移除)
int lower_capability(cap_value_t cap) {
    cap_t caps = cap_get_proc();
    if (!caps) {
        perror("cap_get_proc");
        return -1;
        }
     cap_value_t cap_list[1] = {cap};
     if (cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_CLEAR) != 0) {
        perror("cap_set_flag");
        cap_free(caps);
        return -1;
        }
    if (cap_set_proc(caps) != 0) {
        perror("cap_set_proc");
        cap_free(caps);
        return -1;
        }
    cap_free(caps);
    printf("Lowered capability: %s\n", cap_to_name(cap));
    return 0;
    }

int main(int argc, char *argv[]) {
    printf("=== Capabilities Demo ===\n\n");
    // 初始状态
    printf("Initial state:\n");
    print_capabilities();
    // 场景1:网络服务初始化后丢弃不需要的权限
    if (argc > 1 && strcmp(argv[1], "network") == 0) {
       printf("\n--- Network Service Scenario ---\n");
       // 初始化网络接口(需要CAP_NET_ADMIN)
       // ... 网络配置代码 ...
       // 初始化完成后,只保留CAP_NET_RAW(用于接收数据包)
       cap_value_t keep[] = {CAP_NET_RAW};
       retain_capabilities(keep, 1);
       print_capabilities();
       // 运行主循环(只能接收数据包,不能修改网络配置)
       // ... 主循环代码 ...
       }
    // 场景2:完全沙箱化
    if (argc > 1 && strcmp(argv[1], "sandbox") == 0) {
        printf("\n--- Full Sandbox Scenario ---\n");
        // 初始化完成后丢弃所有Capabilities
        drop_all_capabilities();
        print_capabilities();
        printf("Running in sandbox mode (no capabilities)\n");
        // ... 沙箱内代码 ...
        }
      return 0;
      }
bash 复制代码
# 编译Capabilities演示程序
gcc -o capabilities_demo capabilities_demo.c -lcap

# 设置文件Capabilities
setcap cap_net_admin,cap_net_raw=+ep capabilities_demo

# 运行
./capabilities_demo network
./capabilities_demo sandbox

五、Seccomp:系统调用沙箱

5.1 Seccomp核心机制

Seccomp(Secure Computing Mode)通过BPF程序过滤系统调用,实现进程级别的沙箱。它有两种模式:

图4:Seccomp 系统调用过滤模式

两种模式对比:

模式 特点 适用场景
Strict 仅允许read/write/exit/sigreturn 纯计算任务
Filter BPF程序自定义过滤规则 通用沙箱
Embedded Seccomp + Capabilities + Namespaces IoT/边缘设备

5.2 嵌入式设备Seccomp实现

c 复制代码
// seccomp_sandbox.c
// 嵌入式应用Seccomp沙箱实现

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/prctl.h>
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <linux/audit.h>

// 定义BPF指令宏(简化)
#define BPF_STMT(code, k) { (unsigned short)(code), 0, 0, k }
#define BPF_JUMP(code, k, jt, jf) { (unsigned short)(code), jt, jf, k }

// 允许的系统调用白名单(嵌入式IoT应用典型需求)
// 根据应用实际需求定制

// x86_64架构系统调用号
#ifdef __x86_64__
#define SYSCALL_READ        0
#define SYSCALL_WRITE       1
#define SYSCALL_OPEN        2
#define SYSCALL_CLOSE       3
#define SYSCALL_STAT        4
#define SYSCALL_FSTAT       5
#define SYSCALL_LSEEK       8
#define SYSCALL_MMAP        9
#define SYSCALL_MPROTECT    10
#define SYSCALL_MUNMAP      11
#define SYSCALL_BRK         12
#define SYSCALL_RT_SIGACTION 13
#define SYSCALL_RT_SIGPROCMASK 14
#define SYSCALL_IOCTL       16
#define SYSCALL_PREAD64     17
#define SYSCALL_PWRITE64    18
#define SYSCALL_EXIT        60
#define SYSCALL_EXIT_GROUP  231
#define SYSCALL_SOCKET      41
#define SYSCALL_CONNECT     42
#define SYSCALL_ACCEPT      43
#define SYSCALL_SENDTO      44
#define SYSCALL_RECVFROM    45
#define SYSCALL_BIND        49
#define SYSCALL_GETSOCKOPT  55
#define SYSCALL_CLONE       56
#define SYSCALL_FORK        57
#define SYSCALL_VFORK       58
#define SYSCALL_EXECVE      59
#define SYSCALL_WAIT4       61
#define SYSCALL_KILL        62
#define SYSCALL_FCNTL       72
#define SYSCALL_FLOCK       73
#define SYSCALL_FSYNC       74
#define SYSCALL_MKDIR       83
#define SYSCALL_RMDIR       84
#define SYSCALL_CREAT       85
#define SYSCALL_UNLINK      87
#define SYSCALL_READLINK    89
#define SYSCALL_CHMOD       90
#define SYSCALL_CHOWN       92
#define SYSCALL_GETTIMEOFDAY 96
#define SYSCALL_CLOCK_GETTIME 228
#define SYSCALL_NANOSLEEP   35
#define SYSCALL_GETPID      39
#define SYSCALL_GETPPID     110
#define SYSCALL_GETUID      102
#define SYSCALL_GETGID      104
#define SYSCALL_GETEUID     107
#define SYSCALL_GETEGID     108
#define SYSCALL_SETUID      105
#define SYSCALL_SETGID      106
#define SYSCALL_SETRLIMIT   160
#define SYSCALL_GETRLIMIT   97
#define SYSCALL_PRCTL       157
#define SYSCALL_ARCH_PRCTL  158
#define SYSCALL_SYSINFO     99
#define SYSCALL_GETRANDOM   318
#define SYSCALL_MADVISE     28
#define SYSCALL_FUTEX       202
#define SYSCALL_SET_TID_ADDRESS 218
#define SYSCALL_SET_ROBUST_LIST 273
#define SYSCALL_GET_ROBUST_LIST 274
#define SYSCALL_RT_SIGRETURN 15
#define SYSCALL_TGKILL      234
#define SYSCALL_TKILL       200
#define SYSCALL_GETDENTS64  217
#define SYSCALL_OPENAT      257
#define SYSCALL_MKDIRAT     258
#define SYSCALL_UNLINKAT    263
#define SYSCALL_RENAMEAT    264
#define SYSCALL_FSTATAT     262
#define SYSCALL_READLINKAT  267
#define SYSCALL_FCHMODAT    268
#define SYSCALL_FCHOWNAT    260
#define SYSCALL_NEWFSTATAT  262
#define SYSCALL_PIPE2       293
#define SYSCALL_DUP3        292
#define SYSCALL_EPOLL_CREATE1 291
#define SYSCALL_EPOLL_CTL   233
#define SYSCALL_EPOLL_PWAIT 281
#define SYSCALL_EVENTFD2    290
#define SYSCALL_INOTIFY_INIT1 294
#define SYSCALL_INOTIFY_ADD_WATCH 254
#define SYSCALL_TIMERFD_CREATE 283
#define SYSCALL_TIMERFD_SETTIME 286
#define SYSCALL_TIMERFD_GETTIME 287
#define SYSCALL_PSELECT6    270
#define SYSCALL_PPOLL       271
#define SYSCALL_SIGNalfd4   289
#define SYSCALL_ACCEPT4     288
#define SYSCALL_RECVMMSG    337
#define SYSCALL_SENDMMSG    345
#define SYSCALL_GETSOCKNAME 51
#define SYSCALL_GETPEERNAME 52
#define SYSCALL_SHUTDOWN    48
#define SYSCALL_SETSOCKOPT  54
#define SYSCALL_LISTEN      50
#define SYSCALL_MREMAP      25
#define SYSCALL_SCHED_YIELD 24
#define SYSCALL_SCHED_GETAFFINITY 204
#define SYSCALL_SCHED_SETAFFINITY 203
#define SYSCALL_GETCPU      309
#define SYSCALL_MEMBARRIER  324
#define SYSCALL_COPY_FILE_RANGE 326
#define SYSCALL_SYNCFS      306
#define SYSCALL_STATFS      137
#define SYSCALL_FSTATFS     138
#define SYSCALL_UTIMENSAT   280
#define SYSCALL_RENAMEAT2   316
#define SYSCALL_EXECVEAT    322
#define SYSCALL_PREADV2     327
#define SYSCALL_PWRITEV2    328
#define SYSCALL_PKEY_ALLOC  330
#define SYSCALL_PKEY_FREE   331
#define SYSCALL_PKEY_MPROTECT 329
#define SYSCALL_RSEQ        334
#define SYSCALL_CLONE3      435
#define SYSCALL_OPENAT2     437
#define SYSCALL_PIDFD_OPEN  434
#define SYSCALL_FACCESSAT2  439
#define SYSCALL_PROCESS_MADVISE 440
#define SYSCALL_EPOLL_PWAIT2 441
#define SYSCALL_MOUNT_SETATTR 442
#define SYSCALL_QUOTACTL_FD 443
#define SYSCALL_LANDLOCK_CREATE_RULESET 444
#define SYSCALL_LANDLOCK_ADD_RULE 445
#define SYSCALL_LANDLOCK_RESTRICT_SELF 446
#define SYSCALL_MEMFD_SECRET 447
#define SYSCALL_PROCESS_MRELEASE 448
#define SYSCALL_FUTEX_WAITV 449
#define SYSCALL_SET_MPOLICY_HOME_NODE 450
#define SYSCALL_CACHESTAT   451
#define SYSCALL_FCHMODAT2   452
#define SYSCALL_MAP_SHADOW_STACK 453
#define SYSCALL_FUTEX_WAKE  454
#define SYSCALL_FUTEX_WAIT  455
#define SYSCALL_FUTEX_REQUEUE 456
#define SYSCALL_STATMOUNT   457
#define SYSCALL_LISTMOUNT   458
#define SYSCALL_LSM_GET_SELF_ATTR 459
#define SYSCALL_LSM_SET_SELF_ATTR 460
#define SYSCALL_LSM_LIST_MODULES 461
#define SYSCALL_MSEAL       462
#endif

// ARM64架构系统调用号
#ifdef __aarch64__
#define SYSCALL_READ        63
#define SYSCALL_WRITE       64
#define SYSCALL_OPENAT      56
#define SYSCALL_CLOSE       57
#define SYSCALL_FSTAT       80
#define SYSCALL_LSEEK       62
#define SYSCALL_MMAP        222
#define SYSCALL_MPROTECT    226
#define SYSCALL_MUNMAP      215
#define SYSCALL_BRK         214
#define SYSCALL_RT_SIGACTION 134
#define SYSCALL_RT_SIGPROCMASK 135
#define SYSCALL_IOCTL       29
#define SYSCALL_EXIT        93
#define SYSCALL_EXIT_GROUP  94
#define SYSCALL_SOCKET      198
#define SYSCALL_CONNECT     203
#define SYSCALL_BIND        200
#define SYSCALL_SENDTO      206
#define SYSCALL_RECVFROM    207
#define SYSCALL_GETSOCKOPT  209
#define SYSCALL_CLONE       220
#define SYSCALL_FORK        220  // clone on ARM64
#define SYSCALL_EXECVE      221
#define SYSCALL_WAIT4       260
#define SYSCALL_KILL        129
#define SYSCALL_FCNTL       25
#define SYSCALL_FSYNC       82
#define SYSCALL_MKDIRAT     258
#define SYSCALL_UNLINKAT    263
#define SYSCALL_READLINKAT  267
#define SYSCALL_FCHMODAT    268
#define SYSCALL_FCHOWNAT    260
#define SYSCALL_GETTIMEOFDAY 169
#define SYSCALL_CLOCK_GETTIME 113
#define SYSCALL_NANOSLEEP   101
#define SYSCALL_GETPID      172
#define SYSCALL_GETUID      174
#define SYSCALL_GETGID      176
#define SYSCALL_SETRLIMIT   163
#define SYSCALL_PRCTL       167
#define SYSCALL_FUTEX       98
#define SYSCALL_SET_TID_ADDRESS 218
#define SYSCALL_RT_SIGRETURN 139
#define SYSCALL_GETDENTS64  61
#define SYSCALL_PIPE2       59
#define SYSCALL_DUP3        24
#define SYSCALL_EPOLL_CREATE1 20
#define SYSCALL_EPOLL_CTL   21
#define SYSCALL_EPOLL_PWAIT 22
#define SYSCALL_PPOLL       73
#define SYSCALL_ACCEPT4     242
#define SYSCALL_GETSOCKNAME 204
#define SYSCALL_GETPEERNAME 205
#define SYSCALL_SHUTDOWN    210
#define SYSCALL_SETSOCKOPT  208
#define SYSCALL_LISTEN      201
#define SYSCALL_SCHED_YIELD 124
#define SYSCALL_GETCPU      168
#define SYSCALL_STATFS      43
#define SYSCALL_FSTATFS     44
#define SYSCALL_UTIMENSAT   88
#define SYSCALL_RENAMEAT    38
#define SYSCALL_RENAMEAT2   276
#define SYSCALL_COPY_FILE_RANGE 285
#define SYSCALL_SYNCFS      84
#define SYSCALL_MADVISE     233
#define SYSCALL_MEMBARRIER  283
#define SYSCALL_RSEQ        293
#define SYSCALL_CLONE3      435
#define SYSCALL_OPENAT2     437
#define SYSCALL_PIDFD_OPEN  434
#define SYSCALL_FACCESSAT2  439
#define SYSCALL_LANDLOCK_CREATE_RULESET 444
#define SYSCALL_LANDLOCK_ADD_RULE 445
#define SYSCALL_LANDLOCK_RESTRICT_SELF 446
#define SYSCALL_MEMFD_SECRET 447
#define SYSCALL_PROCESS_MRELEASE 448
#define SYSCALL_FUTEX_WAITV 449
#define SYSCALL_CACHESTAT   451
#define SYSCALL_FCHMODAT2   452
#define SYSCALL_MAP_SHADOW_STACK 453
#define SYSCALL_STATMOUNT   457
#define SYSCALL_LISTMOUNT   458
#define SYSCALL_LSM_GET_SELF_ATTR 459
#define SYSCALL_LSM_SET_SELF_ATTR 460
#define SYSCALL_LSM_LIST_MODULES 461
#define SYSCALL_MSEAL       462
#endif

// 构建Seccomp BPF过滤器
// 允许白名单中的系统调用,拒绝其他
struct sock_filter build_filter[] = {
    // 加载系统调用号(arch字段)
    BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct seccomp_data, nr)),
    
    // 检查每个允许的系统调用
    // 如果匹配,跳转到允许(ALLOW)
    // 如果不匹配,继续检查下一个
    
    // 文件操作
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_READ, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_WRITE, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_OPENAT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_CLOSE, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_FSTAT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_LSEEK, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_IOCTL, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_FCNTL, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_FSYNC, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_MKDIRAT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_UNLINKAT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_READLINKAT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_FCHMODAT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_FCHOWNAT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_RENAMEAT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_RENAMEAT2, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_STATFS, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_FSTATFS, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_UTIMENSAT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_COPY_FILE_RANGE, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_SYNCFS, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_FACCESSAT2, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_OPENAT2, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    
    // 内存管理
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_MMAP, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_MPROTECT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_MUNMAP, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_BRK, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_MADVISE, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_MREMAP, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_MSEAL, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    
    // 进程管理
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_EXIT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_EXIT_GROUP, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_CLONE, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_CLONE3, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_FORK, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_EXECVE, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_WAIT4, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_KILL, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_GETPID, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_GETUID, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_GETGID, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_SETRLIMIT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_GETRLIMIT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_PRCTL, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_SCHED_YIELD, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_GETCPU, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_SET_TID_ADDRESS, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_FUTEX, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_FUTEX_WAITV, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_RSEQ, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_MEMBARRIER, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_PROCESS_MRELEASE, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_PROCESS_MADVISE, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_PIDFD_OPEN, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_CLONE3, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    
    // 信号处理
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_RT_SIGACTION, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_RT_SIGPROCMASK, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_RT_SIGRETURN, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_TGKILL, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_TKILL, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    
    // 时间
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_GETTIMEOFDAY, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_CLOCK_GETTIME, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_NANOSLEEP, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    
    // 网络(可选,根据应用需求)
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_SOCKET, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_CONNECT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_BIND, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_LISTEN, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_ACCEPT4, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_SENDTO, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_RECVFROM, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_GETSOCKOPT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_SETSOCKOPT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_GETSOCKNAME, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_GETPEERNAME, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_SHUTDOWN, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    
    // IO多路复用
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_PIPE2, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_DUP3, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_EPOLL_CREATE1, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_EPOLL_CTL, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_EPOLL_PWAIT, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_PPOLL, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_PSELECT6, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_EVENTFD2, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_TIMERFD_CREATE, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_TIMERFD_SETTIME, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_TIMERFD_GETTIME, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_SIGNalfd4, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_INOTIFY_INIT1, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_INOTIFY_ADD_WATCH, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, SYSCALL_GETDENTS64, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
    
    // 默认:拒绝并记录
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRAP),
};

// 初始化Seccomp沙箱
int init_seccomp_sandbox() {
    // 先禁止获取新权限
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
        perror("prctl(PR_SET_NO_NEW_PRIVS)");
        return -1;
    }
    struct sock_fprog prog = {
      .len = (unsigned short)(sizeof(build_filter) / sizeof(build_filter[0])),
      .filter = build_filter,
      };
      // 加载Seccomp过滤器
      if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
          perror("prctl(PR_SET_SECCOMP)");
          return -1;
          }
      printf("Seccomp sandbox initialized successfully\n");
      printf("Allowed syscalls: file, memory, process, signal, time, network, io\n");
      printf("Denied syscalls: ptrace, mount, chroot, reboot, kexec, etc.\n");
      return 0;
      }

// 信号处理:捕获Seccomp违规
void sigsys_handler(int sig, siginfo_t *info, void *context) {
  fprintf(stderr, "SECcomp violation: syscall %d blocked\n", info->si_syscall);
  // 记录日志、告警、或优雅退出
  _exit(1);
  }

int main() {
 // 设置SIGSYS处理程序
 struct sigaction sa;
 memset(&sa, 0, sizeof(sa));
 sa.sa_sigaction = sigsys_handler;
 sa.sa_flags = SA_SIGINFO;
 sigaction(SIGSYS, &sa, NULL);
 // 初始化沙箱
 if (init_seccomp_sandbox() != 0) {
   fprintf(stderr, "Failed to initialize sandbox\n");
   return 1;\
   }
 // 沙箱内运行应用代码
 printf("Running in sandbox...\n");
 // 测试:允许的操作
 int fd = open("/tmp/test.txt", O_CREAT | O_WRONLY, 0644);
 if (fd >= 0) {
     write(fd, "Hello from sandbox\n", 18);
     close(fd);
     printf("File operation succeeded\n");
     }
     // 测试:禁止的操作(如果取消注释,将被阻止)
     // ptrace(PTRACE_TRACEME, 0, NULL, NULL);  // 将被Seccomp阻止
     printf("Sandbox test completed\n");
     return 0;
     }
bash 复制代码
# 编译和运行Seccomp沙箱
gcc -o seccomp_sandbox seccomp_sandbox.c
./seccomp_sandbox

# 验证Seccomp状态
cat /proc/self/status | grep Seccomp
# 输出:Seccomp: 2 (FILTER_MODE)

5.3 使用libseccomp简化配置

c 复制代码
// libseccomp_example.c
// 使用libseccomp库简化Seccomp配置

#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int init_sandbox_with_libseccomp() {
    scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_TRAP);  // 默认拒绝并发送SIGSYS
    if (!ctx) {
       fprintf(stderr, "seccomp_init failed\n");
       return -1;
       }
    // 允许基本系统调用
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(lseek), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 0);
    // 允许内存管理
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0);
    // 允许进程管理
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone3), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(wait4), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpid), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getuid), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), 0);
    // 允许信号处理
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0);
    // 允许时间
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(gettimeofday), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clock_gettime), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(nanosleep), 0);
    // 允许网络(条件:检查参数)
    // 只允许连接到特定端口
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(connect), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendto), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(recvfrom), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(bind), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(listen), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept4), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(shutdown), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), 0);
    // 允许IO多路复用
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_create1), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_ctl), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(epoll_pwait), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ppoll), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(pipe2), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(dup3), 0);
    // 加载过滤器
    if (seccomp_load(ctx) < 0) {
      fprintf(stderr, "seccomp_load failed\n");
      seccomp_release(ctx);
      return -1;
      }
     seccomp_release(ctx);
     printf("libseccomp sandbox loaded successfully\n");
     return 0;
     }

int main() {
  if (init_sandbox_with_libseccomp() != 0) {
     return 1;
     }
  printf("Running in libseccomp sandbox\n");
  // 正常操作
  int fd = open("/tmp/test.txt", O_CREAT | O_WRONLY, 0644);
  if (fd >= 0) {
      write(fd, "Hello\n", 6);
      close(fd);
      }
   return 0;
   }
bash 复制代码
# 编译
gcc -o libseccomp_example libseccomp_example.c -lseccomp

六、综合安全加固效果

图5:嵌入式 Linux 安全加固效果

6.1 攻击面缩减量化

加固层次 攻击面 被攻破后影响 安全等级
无加固 100% 100% 不安全
DAC优化 75% 80% 基础
+SELinux 45% 40% 中等
+Capabilities 25% 20% 高
+Seccomp 10% 5% 极高

6.2 完整加固配置脚本

bash 复制代码
#!/bin/bash
# embedded_hardening.sh
# 嵌入式Linux设备完整安全加固脚本

set -e

echo "=== Embedded Linux Security Hardening ==="

# 1. 禁用不必要的服务
echo "[1/8] Disabling unnecessary services..."
systemctl disable bluetooth 2>/dev/null || true
systemctl disable cups 2>/dev/null || true
systemctl disable avahi-daemon 2>/dev/null || true
systemctl disable ModemManager 2>/dev/null || true

# 2. 配置DAC权限
echo "[2/8] Configuring DAC permissions..."
chmod 700 /root
chmod 750 /home/*
chmod 644 /etc/passwd
chmod 600 /etc/shadow
chmod 600 /etc/gshadow

# 3. 启用SELinux
echo "[3/8] Enabling SELinux..."
if [ -f /etc/selinux/config ]; then
    sed -i 's/SELINUX=disabled/SELINUX=enforcing/' /etc/selinux/config
    sed -i 's/SELINUX=permissive/SELINUX=enforcing/' /etc/selinux/config
    setenforce 1 2>/dev/null || true
fi

# 4. 配置Capabilities
echo "[4/8] Configuring Capabilities..."
# 为网络工具分配最小权限
setcap cap_net_raw=ep /bin/ping 2>/dev/null || true
setcap cap_net_admin,cap_net_raw=ep /usr/sbin/tcpdump 2>/dev/null || true

# 5. 配置Seccomp(通过systemd)
echo "[5/8] Configuring Seccomp profiles..."
mkdir -p /etc/seccomp
cat <<'EOF' > /etc/seccomp/default.json
{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": ["SCMP_ARCH_AARCH64", "SCMP_ARCH_X86_64"],
    "syscalls": [
        {"names": ["read", "write", "openat", "close", "fstat", "lseek"], "action": "SCMP_ACT_ALLOW"},
        {"names": ["mmap", "mprotect", "munmap", "brk"], "action": "SCMP_ACT_ALLOW"},
        {"names": ["exit", "exit_group", "clone", "wait4"], "action": "SCMP_ACT_ALLOW"},
        {"names": ["rt_sigaction", "rt_sigprocmask", "rt_sigreturn"], "action": "SCMP_ACT_ALLOW"},
        {"names": ["gettimeofday", "clock_gettime", "nanosleep"], "action": "SCMP_ACT_ALLOW"},
        {"names": ["socket", "connect", "sendto", "recvfrom", "bind", "listen"], "action": "SCMP_ACT_ALLOW"},
        {"names": ["epoll_create1", "epoll_ctl", "epoll_pwait", "ppoll", "pipe2"], "action": "SCMP_ACT_ALLOW"}
    ]
}
EOF

# 6. 内核参数加固
echo "[6/8] Hardening kernel parameters..."
cat <<EOF >> /etc/sysctl.conf
# 禁用IP源路由
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# 禁用ICMP重定向
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0

# 启用SYN cookies
net.ipv4.tcp_syncookies = 1

# 禁用IPv6(如不需要)
net.ipv6.conf.all.disable_ipv6 = 1

# 启用ASLR
kernel.randomize_va_space = 2

# 限制核心转储
fs.suid_dumpable = 0

# 限制进程内存
vm.mmap_rnd_bits = 32

# 启用ptrace限制
kernel.yama.ptrace_scope = 1
EOF
sysctl -p

# 7. 文件系统加固
echo "[7/8] Hardening filesystem..."
# 挂载选项
cat <<EOF >> /etc/fstab
# 安全挂载选项
tmpfs /tmp tmpfs nosuid,nodev,noexec 0 0
tmpfs /var/tmp tmpfs nosuid,nodev,noexec 0 0
EOF

# 8. 审计日志
echo "[8/8] Configuring audit logging..."
if [ -f /etc/audit/auditd.conf ]; then
    systemctl enable auditd 2>/dev/null || true
    auditctl -e 1 2>/dev/null || true
fi

echo "=== Hardening Complete ==="
echo "Please reboot to apply all changes."

七、场景化选型指南

场景 推荐方案 关键配置
工业PLC/网关 SELinux + Capabilities + Seccomp targeted策略,最小权限
医疗设备 SELinux MLS + Seccomp 多级安全,严格沙箱
消费IoT AppArmor + Seccomp 轻量,易维护
车载信息娱乐 Smack + Capabilities Tizen生态兼容
容器/边缘 SELinux + Seccomp + Landlock 容器运行时集成
资源受限MCU Seccomp Strict 最小开销

八、总结与展望

本文系统性地讲解了嵌入式Linux的四层安全防御体系:

安全机制 核心能力 嵌入式价值
SELinux 类型强制,策略驱动访问控制 阻止攻破后的横向移动
Capabilities 拆分root,最小权限 降低特权滥用风险
Seccomp 系统调用白名单沙箱 限制攻击者可操作系统调用
组合使用 纵深防御 攻击面缩减90%以上

未来发展方向:

  • Landlock LSM:Linux 5.13+引入的无特权沙箱,适合应用自限制
  • eBPF LSM:可编程的安全策略,动态响应威胁
  • 机密计算:ARM TrustZone/CCA与Linux安全机制的融合
  • 鸿蒙安全:OpenHarmony的分布式安全模型值得借鉴

安全不是一次性配置,而是持续的过程。建议建立安全基线、定期审计、及时更新,将安全融入嵌入式开发的每个环节。


转载自:https://blog.csdn.net/u014727709/article/details/162661291

欢迎 👍点赞✍评论⭐收藏,欢迎指正

相关推荐
呉師傅16 分钟前
得力P2500、M2500系列打印机硒鼓加粉及清零方法【纯享版】
运维·网络·windows·电脑
Sayai21 分钟前
Elasticsearch 日志检索 DSL 实战:时间范围查询、字段去重、分钟级统计与最新日志获取
大数据·运维·elasticsearch·搜索引擎·日志分析
qetfw28 分钟前
Debian Chrony 时间同步、RAID5 与 LUKS 磁盘加密配置
linux·debian
linux_cfan1 小时前
videojs v10 源代码系列解读:34 · `createComposition`:类型安全的冲突检测
前端·安全
hasty1 小时前
传完再检查为何太晚?LXD 迁移流的文件写入边界
安全·系统安全
每天题库1 小时前
架子工脚手架工题库:安全操作考点与模拟题练习指南
学习·安全·考试·题库·考证
白帽攻防录2 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt
fb_123452 小时前
MySQL运维实战:备份恢复+主从复制+读写分离+MHA高可用(超详细手把手教程)
运维·mysql·oracle
东城居士3 小时前
Linux驱动阻塞与非阻塞访问的理解
linux·嵌入式系统
..Dauntless..3 小时前
【Linux】进程地址空间初步理解
linux·运维·服务器