操作系统安全与端侧 AI 推理部署:常见反模式与安全防护架构

把大模型或小参数量语言模型(SLM)放到嵌入式设备上,通常要同时处理性能、设备权限和运维约束。

在算力受限的边缘板卡上,为了优化推理延迟或提升吞吐帧率,部分系统设计在操作系统层面采用了削弱隔离粒度的做法。然而,工程实践表明,在 Demo 演示阶段看似高效的优化方式,置于真实生产环境后往往会演变为系统安全与稳定隐患。端侧 AI 部署在追求执行效率的同时,更需保障系统稳健性。若过度放宽 Linux 操作系统的安全边界,将带来潜在的安全风险。

常见端侧 AI 部署反模式拆解

综合常见端侧推理项目的架构设计,存在三个典型且需关注的反模式:

1. 为追求调度效率直接授予 CAP_SYS_ADMIN 或 Root 特权

在嵌入式 Linux 系统中,推理任务常需要进行 CPU 核心绑定(sched_setaffinity)或设置实时调度优先级(SCHED_FIFO)。部分部署配置直接在 systemd 服务文件中指定 User=root

这种配置意味着,若推理引擎在解析模型输入时发生缓冲区溢出,越权行为将直接获取设备的最高控制权,从而构成对内网其他节点的安全威胁。

2. 基于未隔离共享内存进行零拷贝

为省去用户态、内核态与 NPU 驱动之间的多级内存复制,部分实现自定义字符设备驱动,通过 remap_pfn_range 将连续物理内存直接映射给应用层。

然而,若该段内存缺乏访问控制列表(ACL)及地址空间隔离保护,同一设备上的其他普通权限进程便可能通过 mmap 读取模型推理过程中的敏感中间张量,甚至导出模型权重。

3. 在应用层内存中解密模型文件

部分方案将加密的模型权重保存在 Flash 中,系统启动时由推理进程读取至内存并完成解密。

在未启用 Linux 内核 ptrace 限制的情况下,通过挂载调试工具即可提取解密后的完整权重,造成资产泄露风险。

建立安全的无特权端侧推理架构

这些风险不等于只能以性能换安全。Linux 提供了可组合的隔离机制,但具体代价取决于驱动、硬件和推理运行时:

  1. 进程降级与资源硬隔离:利用 cgroups v2cpuset 子系统,在系统启动阶段为推理进程划定固定的 CPU 核心池,无需在运行时动态申请高特权调度接口。
  2. seccomp-bpf 系统调用过滤:先通过实际运行跟踪得到运行时需要的调用集合,再按架构和版本编写策略。它可以缩小攻击面,但不能替代内存安全、输入校验和设备访问控制。
  3. 利用 DMA-BUF 传递缓冲区:DMA-BUF 通过文件描述符共享缓冲区并管理生命周期。是否允许导出、映射和同步仍取决于具体驱动与权限模型,不能把它视为自动的保密机制。

基于 C 语言的 seccomp-bpf 沙箱实施代码

以下代码只演示过滤器的结构,不是一份可直接用于推理运行时的白名单。真实部署必须用 strace、审计日志或运行时文档确认调用集,并在目标板卡上回归测试。

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

// 检查架构并限制为 x86_64 或 ARM64
#if defined(__x86_64__)
  #define ARCH_NR AUDIT_ARCH_X86_64
#elif defined(__aarch64__)
  #define ARCH_NR AUDIT_ARCH_AARCH64
#else
  #error "Unsupported Architecture"
#endif

static int apply_inference_seccomp_sandbox(void) {
    // 允许推理运行时所需的极少数安全 syscall
    struct sock_filter filter[] = {
        // 1. 检查架构是否匹配
        BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch))),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ARCH_NR, 1, 0),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),

        // 2. 读取 syscall 编号
        BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))),

        // 3. 显式拦截并拒绝 ptrace (防止内存 dump)
#ifdef __NR_ptrace
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ptrace, 0, 1),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | (EPERM & SECCOMP_RET_DATA)),
#endif

        // 4. 白名单允许:futex, read, write, ioctl, exit_group
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_read, 4, 0),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 3, 0),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 2, 0),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_exit_group, 1, 0),
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_futex, 0, 1),
        
        // 匹配成功返回 ALLOW,不匹配则拒绝并中断
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS)
    };

    struct sock_fprog prog = {
        .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
        .filter = filter,
    };

    // 启用 NO_NEW_PRIVS,阻止后续 exec 获得额外权限
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
        perror("PR_SET_NO_NEW_PRIVS 失败");
        return -1;
    }

    // 装载 seccomp 过滤器
    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
        perror("PR_SET_SECCOMP 载入失败");
        return -1;
    }

    printf("端侧推理 seccomp 低开销沙箱装载成功。\n");
    return 0;
}

int main(void) {
    printf("完成模型初始化与硬件 Device 句柄绑定...\n");

    // 加载沙箱
    if (apply_inference_seccomp_sandbox() != 0) {
        exit(EXIT_FAILURE);
    }

    // 沙箱激活后的推理循环逻辑
    printf("沙箱保护中:执行安全推理逻辑...\n");
    
    return 0;
}

部署前应记录的评估项

不同 SoC、模型、驱动版本和策略复杂度下,延迟与内存变化会不同。部署前可按下列维度记录基线和隔离后的结果:

部署模式与配置 运行特权 系统调用白名单 P99 推理延迟 (ms) 内存额外开销 内存 Dump 攻击防御
特权模式 进程身份与 capability 实际调用集 记录 P50/P99 记录 RSS/缓冲区 检查越权路径是否仍可用
共享缓冲区方案 缓冲区导出权限 映射与同步调用 记录 P50/P99 记录共享缓冲区占用 尝试跨进程访问与 fd 泄漏
受限模式 无特权用户、最小 capability 经回归验证的白名单 与基线对比 与基线对比 验证拒绝行为和正常推理

端侧 AI 的工程推进既需要考虑算法剪枝与帧率表现,也需兼顾生产环境下的系统稳定性与安全防线。

端侧部署的目标不是套一份固定策略,而是在目标硬件上验证:推理流程仍可用,越权路径被限制,性能开销处于团队可接受范围。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐