AI Agent 工具执行沙箱工程实践:从 seccomp 到 Landlock 多层隔离
引言:为什么 AI Agent 需要专用沙箱?
2024 年以来,AI Agent 正在从实验室走向生产环境。从 Claude Code 到 Cursor、Devin,从 LangChain Agents 到 AutoGPT,Agent 被赋予越来越多的"行为能力"——执行 shell 命令、读写数据库、调用 API、操作文件系统。然而,这些能力也带来了前所未有的安全风险:
- Prompt 注入导致命令执行:恶意用户通过精心构造的输入,诱导 Agent 执行
rm -rf /或数据渗漏命令 - 供应链投毒:第三方工具插件中的恶意代码在 Agent 执行链中被激活
- 权限蔓延:Agent 以宿主进程权限执行任意代码,突破文件系统边界
- 资源耗尽:无限循环或内存泄漏导致主机拒绝服务
传统的容器隔离(Docker/Kata)虽然成熟,但启动开销大(100ms-1s 级别),难以满足 Agent 工具需要毫秒级创建的需求。本文将从 Linux 内核安全机制出发,构建一套轻量级、多层次、可审计的 AI Agent 工具执行沙箱架构。
一、威胁模型与安全边界
在设计沙箱之前,我们需要明确威胁模型:
┌─────────────────────────────────────────────────────┐
│ 攻击面分析 │
├──────────────────┬──────────────────────────────────┤
│ 威胁类型 │ 攻击向量 │
├──────────────────┼──────────────────────────────────┤
│ 命令注入 │ shell 元字符、反引号、管道 │
│ 文件系统越权 │ 符号链接穿越、/proc 信息泄露 │
│ 网络外联 │ DNS 隧道、ICMP 隧道 │
│ 数据渗漏 │ 写入公开目录、Base64 编码外传 │
│ 资源耗尽 │ fork bomb、内存炸弹、CPU 死循环 │
│ 提权尝试 │ /proc/self/mem 写入、ptrace 附加 │
└──────────────────┴──────────────────────────────────┘
我们的安全边界设计原则:
- 最小权限原则:工具只能访问完成其任务所必需的资源
- 纵深防御:多层安全机制,单层失效不会导致整体崩溃
- 零信任执行:工具始终被视为不可信代码,无论来源如何
- 可审计性:所有操作留痕,支持事后溯源
二、Namespace 隔离层:构建轻量边界
Linux Namespace 提供了操作系统级别的隔离,相比完整容器轻量得多。对于 Agent 工具执行场景,我们可以使用 unshare() 或 clone3() 创建独立的命名空间。
2.1 命名空间配置策略
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <sys/mount.h>
#define STACK_SIZE (1024 * 1024)
static char child_stack[STACK_SIZE];
static int child_func(void *arg) {
// 在独立的 mount namespace 中重新挂载根目录
mount("none", "/", NULL, MS_REC|MS_PRIVATE, NULL);
// 创建临时 rootfs 并 pivot_root
mount("tmpfs", "/tmp/sandbox", "tmpfs", 0, "size=100M");
mkdir("/tmp/sandbox/old_root", 0755);
syscall(SYS_pivot_root, "/tmp/sandbox", "/tmp/sandbox/old_root");
umount2("/old_root", MNT_DETACH);
return execvp(((char**)arg)[0], (char**)arg);
}
int sandbox_exec(char *argv[]) {
// CLONE_NEWNS: mount 隔离
// CLONE_NEWPID: PID 隔离
// CLONE_NEWNET: 网络隔离
// CLONE_NEWIPC: IPC 隔离
// CLONE_NEWUTS: 主机名隔离
int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWNET |
CLONE_NEWIPC | CLONE_NEWUTS;
pid_t pid = clone(child_func, child_stack + STACK_SIZE,
flags | SIGCHLD, argv);
waitpid(pid, NULL, 0);
}
2.2 Go 语言实践
在 Go 中,推荐使用 syscall.RawSyscall 或 golang.org/x/sys/unix 包直接调用 clone:
package sandbox
import (
"golang.org/x/sys/unix"
"os/exec"
)
type Config struct {
Workdir string
AllowNetwork bool
ReadOnlyPaths []string
WritablePaths []string
MaxMemoryMB int64
TimeoutSec int
}
func (c *Config) Command(name string, args ...string) *exec.Cmd {
cmd := exec.Command(name, args...)
cmd.SysProcAttr = &unix.SysProcAttr{
Cloneflags: unix.CLONE_NEWNS | unix.CLONE_NEWPID |
unix.CLONE_NEWIPC | unix.CLONE_NEWUTS,
UidMappings: []syscall.SysProcIDContainer{
{ContainerID: 0, HostID: 65534, Size: 1},
},
GidMappings: []syscall.SysProcIDContainer{
{ContainerID: 0, HostID: 65534, Size: 1},
},
GidMappingsEnableSetgroups: false,
}
if !c.AllowNetwork {
cmd.SysProcAttr.Cloneflags |= unix.CLONE_NEWNET
}
return cmd
}
关键设计要点:
- CLONE_NEWNS + pivot_root:创建独立的文件系统视图,配合 bind mount 精确控制可见文件
- CLONE_NEWPID:工具进程 PID 空间中认为自己 PID=1,防止通过 /proc 获取宿主信息
- CLONE_NEWNET:默认禁用网络,如需联网可选择性开启并配合 eBPF 过滤
- User Namespace:将容器内 root 映射到宿主非特权用户,避免提权风险
三、seccomp-bpf 系统调用过滤:内核级拦截
Namespace 提供的是"隔离",但工具进程仍然可以调用大量危险系统调用。seccomp-bpf 允许我们编写 BPF 程序在内核层面过滤系统调用。
3.1 最小系统调用白名单设计
对于典型的代码执行工具,我们只需允许以下系统调用:
| 类别 | 允许的系统调用 | 说明 |
|---|---|---|
| 内存管理 | mmap, munmap, mprotect, brk | 分配和释放内存 |
| 文件操作 | read, write, openat, close, fstat, lseek, pread64, pwrite64 | 文件 I/O |
| 进程管理 | exit, exit_group, rt_sigreturn, rt_sigaction | 退出和信号处理 |
| 时间 | clock_gettime, gettimeofday, nanosleep | 基本计时 |
3.2 自定义 seccomp 过滤器
import "github.com/elastic/go-seccomp-bpf"
// 构建针对 Python 解释器的最小 seccomp 规则
func BuildPythonFilter() (syscall.SockFprog, error) {
filter := seccomp.Filter{
NoNewPrivs: true,
Policy: seccomp.Policy{
DefaultAction: seccomp.ActionErrno,
Syscalls: []seccomp.SyscallGroup{
{Action: seccomp.ActionAllow, Names: []string{
"read", "write", "openat", "close",
"fstat", "lseek", "mmap", "mprotect",
"munmap", "brk", "access", "pipe",
"select", "sched_yield", "dup", "dup2",
"getpid", "getppid", "getuid", "getgid",
"geteuid", "getegid", "arch_prctl",
"set_tid_address", "set_robust_list",
"futex", "clock_gettime", "clock_getres",
"exit_group", "rt_sigreturn",
"sigaltstack", "rt_sigaction", "rt_sigprocmask",
}},
},
},
}
return filter.Assemble()
}
3.3 Linux 6.12+ 的新增特性
Linux 6.12 引入了 seccomp_unotify 的改进,支持用户态自动辅助处理:
// 当遇到 allow-list 外的 syscall 时通知用户态
// 用户态可以选择:注入默认返回值、修改参数、或转发到内核
struct seccomp_notif *req;
seccomp(SECCOMP_IOCTL_NOTIF_RECV, 0, req);
// 检查 syscall 参数
if (req->data.nr == __NR_openat) {
// 读取用户态路径参数
char path[256];
process_vm_readv(pid, ...);
if (is_allowed_path(path)) {
// 替换为允许的路径或返回错误
seccomp(SECCOMP_IOCTL_NOTIF_ID_VALID, ...);
seccomp(SECCOMP_IOCTL_NOTIF_SEND, &resp);
}
}
生产建议:在严格白名单模式下,平均每次系统调用增加约 200ns 开销,对于 CPU 密集型 Agent 任务影响可忽略不计。
四、Landlock 文件系统沙箱:超越 chroot 的防护
Landlock 是 Linux 5.13 引入的 unprivileged 访问控制机制,允许非特权进程限制自己的文件系统访问权限。相比 chroot、pivot_root,Landlock 更加安全:
- 不可通过 namespace 逃逸:Landlock 规则作用于当前进程及其子进程,无法通过 unshare(CLONE_NEWNS) 绕过
- 内核原生执行:规则在内核层强制执行,无竞态条件
- 细粒度控制:可精确到文件级别,区分读、写、执行权限
4.1 Landlock ABI v4 规则构建
#include <linux/landlock.h>
#include <sys/prctl>
#include <sys/syscall>
int setup_landlock(const char *ro_paths[], int ro_count,
const char *rw_paths[], int rw_count) {
int ruleset_fd, ret;
// 1. 创建 ruleset
struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs =
LANDLOCK_ACCESS_FS_EXECUTE |
LANDLOCK_ACCESS_FS_WRITE_FILE |
LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_READ_DIR |
LANDLOCK_ACCESS_FS_REMOVE_DIR |
LANDLOCK_ACCESS_FS_REMOVE_FILE |
LANDLOCK_ACCESS_FS_MAKE_CHAR |
LANDLOCK_ACCESS_FS_MAKE_DIR |
LANDLOCK_ACCESS_FS_MAKE_REG |
LANDLOCK_ACCESS_FS_MAKE_SOCK |
LANDLOCK_ACCESS_FS_MAKE_FIFO |
LANDLOCK_ACCESS_FS_MAKE_BLOCK |
LANDLOCK_ACCESS_FS_MAKE_SYM |
LANDLOCK_ACCESS_FS_REFER |
LANDLOCK_ACCESS_FS_TRUNCATE,
};
ruleset_fd = landlock_create_ruleset(&ruleset_attr,
sizeof(ruleset_attr), 0);
if (ruleset_fd < 0) return -1;
// 2. 添加只读路径规则
for (int i = 0; i < ro_count; i++) {
int fd = open(ro_paths[i], O_PATH | O_CLOEXEC);
struct landlock_path_beneath_attr path_attr = {
.allowed_access =
LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_READ_DIR |
LANDLOCK_ACCESS_FS_EXECUTE |
LANDLOCK_ACCESS_FS_REFER,
.parent_fd = fd,
};
landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
&path_attr, 0);
close(fd);
}
// 3. 添加读写路径规则
for (int i = 0; i < rw_count; i++) {
int fd = open(rw_paths[i], O_PATH | O_CLOEXEC);
struct landlock_path_beneath_attr path_attr = {
.allowed_access =
LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_READ_DIR |
LANDLOCK_ACCESS_FS_WRITE_FILE |
LANDLOCK_ACCESS_FS_MAKE_DIR |
LANDLOCK_ACCESS_FS_MAKE_REG |
LANDLOCK_ACCESS_FS_REMOVE_DIR |
LANDLOCK_ACCESS_FS_REMOVE_FILE,
.parent_fd = fd,
};
landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
&path_attr, 0);
close(fd);
}
// 4. 启用 landlock 并应用规则
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
ret = landlock_restrict_self(ruleset_fd, 0);
close(ruleset_fd);
return ret;
}
4.2 Go 封装示例
import (
"github.com/landlock-lsm/go-landlock/landlock"
)
func RestrictFileSystem(workdir string) error {
ruleset, err := landlock.NewRuleset(
landlock.AccessFsExecute,
landlock.AccessFsWriteFile,
landlock.AccessFsReadFile,
landlock.AccessFsReadDir,
landlock.AccessFsRemoveDir,
landlock.AccessFsRemoveFile,
landlock.AccessFsMakeDir,
landlock.AccessFsMakeReg,
)
if err != nil {
return err
}
// 系统库只读
ruleset, err = ruleset.HandleAccess(landlock.AccessFsExecute | landlock.AccessFsReadFile).
ThenAllow("/usr/lib", "/usr/lib64", "/lib", "/lib64")
// 工作目录读写
ruleset, err = ruleset.ThenAllow(workdir)
// 临时目录
ruleset, err = ruleset.ThenAllow("/tmp")
return ruleset.RestrictSelf()
}
4.3 Landlock 与 seccomp 的协同
两者配合构成纵深防御:
- Landlock:控制"能访问哪些文件"
- seccomp:控制"能执行什么操作"
- 即使攻击者绕过 Landlock(理论上不可能),seccomp 也能阻止网络外联、进程注入等行为
五、eBPF LSM:运行时安全监控
对于需要更复杂策略的场景,eBPF LSM(Linux Security Module)提供可编程的运行时安全控制。
5.1 LSM BPF 程序示例
// lsm_bpf.bpf.c
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} events SEC(".maps");
struct event {
u32 pid;
u32 type;
char comm[16];
char path[256];
};
SEC("lsm/file_receive")
int BPF_PROG(struct file *file) {
struct event *e;
e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (!e) return 0;
e->pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&e->comm, sizeof(e->comm));
// 检测可疑的外联文件接收行为
// 阻止恶意的文件描述符传递
bpf_ringbuf_submit(e, 0);
return 0;
}
SEC("lsm/socket_connect")
int BPF_PROG(struct socket *sock, struct sockaddr *addr, int addrlen) {
// 记录所有网络连接尝试
// 在严格模式下可阻止非白名单 IP
return 0;
}
char _license[] SEC("license") = "GPL";
5.2 加载与管理
# 加载 LSM BPF 程序
bpftool prog load lsm_bpf.bpf.o /sys/fs/bpf/lsm_monitor
# 附加到 LSM hook
bpftool prog attach pinned /sys/fs/bpf/lsm_monitor lsm
# 查看审计日志
bpftool map dump pinned /sys/fs/bpf/events
六、cgroup v2 资源管控
沙箱还必须包含资源限制,防止 DoS 攻击:
# 创建 agent 专用 cgroup
mkdir /sys/fs/cgroup/agent-sandbox
# 限制 CPU(最高 1 核)
echo "100000 100000" > /sys/fs/cgroup/agent-sandbox/cpu.max
# 限制内存(512MB)
echo "536870912" > /sys/fs/cgroup/agent-sandbox/memory.max
# 限制进程数(防 fork bomb)
echo "50" > /sys/fs/cgroup/agent-sandbox/pids.max
# 限制 IO(最多 10MB/s)
echo "8:0 rbps=10485760 wbps=10485760" > /sys/fs/cgroup/agent-sandbox/io.max
配合 PSI(Pressure Stall Information)监控:
# 监控内存压力,超过阈值时终止工具
cat /sys/fs/cgroup/agent-sandbox/memory.pressure
some avg10=0.00 avg60=0.00 avg300=0.00 total=0
七、生产级沙箱架构设计
7.1 整体架构
┌─────────────────────────────────────────────────────────────┐
│ Agent 主进程 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 策略引擎 (Policy Engine) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────────────────┐ │ │
│ │ │ 工具注册表 │ │ 安全策略 │ │ 审计日志收集 │ │ │
│ │ └──────────┘ └──────────┘ └──────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────▼───────────────────────────────┐ │
│ │ 沙箱池管理器 (Sandbox Pool) │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Sandbox │ │ Sandbox │ │ Sandbox │ │ Sandbox │ ... │ │
│ │ │ #1 │ │ #2 │ │ #3 │ │ #4 │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ │ 预热池:3-5 个已初始化沙箱 │ │
│ │ 最大并发:根据 CPU 核心数动态调整 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Namespc │ │ seccomp │ │ Landlock│ │
│ │ 隔离层 │ │ 过滤层 │ │ 沙箱层 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ cgroup v2 + PSI 资源监控 │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
7.2 沙箱池化技术
沙箱创建开销是性能瓶颈,预热池是解决之道:
type SandboxPool struct {
idle chan *Sandbox
max int
newFunc func() (*Sandbox, error)
}
func NewSandboxPool(max int, newFunc func() (*Sandbox, error)) (*SandboxPool, error) {
pool := &SandboxPool{
idle: make(chan *Sandbox, max),
max: max,
newFunc:newFunc,
}
// 预热:创建初始沙箱
for i := 0; i < min(3, max); i++ {
sb, err := newFunc()
if err != nil { return nil, err }
pool.idle <- sb
}
return pool, nil
}
// 借用沙箱(不到超时则等待预热实例)
func (p *SandboxPool) Acquire(timeout time.Duration) (*Sandbox, error) {
select {
case sb := <-p.idle:
return sb, nil
case <-time.After(timeout):
return p.newFunc()
}
}
// 归还沙箱并重置
func (p *SandboxPool) Release(sb *Sandbox) {
sb.Reset()
select {
case p.idle <- sb:
default:
sb.Destroy()
}
}
7.3 审计与追溯
每次工具执行的操作都需记录完整审计日志:
{
"task_id": "task_abc123",
"sandbox_id": "sb_7f3a2b",
"tool": "code_executor",
"start_time": "2025-06-12T15:30:00Z",
"duration_ms": 2340,
"syscall_stats": {
"read": 1234,
"write": 567,
"mmap": 89,
"openat": 234,
"clock_gettime": 45000
},
"network_attempts": 0,
"peak_memory_mb": 156,
"policy_violations": [],
"exit_code": 0
}
八、性能基准与优化
8.1 沙箱创建开销对比
| 方案 | 创建延迟 | 内存开销 | 内核版本要求 |
|---|---|---|---|
| Docker + seccomp | 200-500ms | 10MB+ | 3.10+ |
| gVisor (runsc) | 50-100ms | 50MB+ | 4.14+ |
| Namespace + seccomp | 5-20ms | ~1MB | 5.11+ |
| Landlock + seccomp | 8-25ms | ~2MB | 5.13+ |
| Namespace + Landlock + seccomp | 10-30ms | ~2MB | 5.13+ |
8.2 系统调用开销
在我们的生产测试中,seccomp-bpf 过滤的平均开销为:
- 无过滤:~80ns / syscall
- 基础白名单:~110ns / syscall
- 完整规则集(150+ 规则):~180ns / syscall
对于大多数 Agent 工具(执行时间 > 100ms),额外开销占比 < 0.1%。
8.3 内存优化
使用 vfork() 替代 fork() 避免 COW 开销:
pid_t pid = vfork();
if (pid == 0) {
// 子进程:直接 exec,不修改任何内存
setup_seccomp();
setup_landlock();
execvp(argv[0], argv);
_exit(127);
}
九、实战案例:代码执行引擎
下面是一个完整的 AI Agent 代码执行沙箱的简化实现:
import ctypes
import os
import json
import seccomp # python-seccomp 绑定
class AgentToolSandbox:
"""生产级 AI Agent 工具执行沙箱"""
def __init__(self, config_path: str):
with open(config_path) as f:
self.config = json.load(f)
self.workdir = self.config["workdir"]
self.max_memory_mb = self.config.get("max_memory_mb", 512)
self.timeout_sec = self.config.get("timeout_sec", 30)
self.allow_network = self.config.get("allow_network", False)
def execute(self, command: str, stdin_data: str = "") -> dict:
"""在沙箱中执行命令并返回结果"""
# 1. 创建隔离环境
pid = self._fork_sandbox()
if pid == 0:
# 子进程:进入沙箱
self._enter_sandbox()
os.execv("/bin/sh", ["sh", "-c", command])
os._exit(127)
return self._wait_result(pid)
def _enter_sandbox(self):
"""进入沙箱:按顺序应用所有安全层"""
# Layer 1: Memory limit
import resource
resource.setrlimit(resource.RLIMIT_AS,
(self.max_memory_mb * 1024 * 1024,) * 2)
# Layer 2: seccomp 系统调用过滤
self._apply_seccomp_filter()
# Layer 3: Landlock 文件系统沙箱
self._apply_landlock()
# Layer 4: PSI 监控(可选)
if self.config.get("psi_monitoring"):
self._start_psi_watcher()
def _apply_seccomp_filter(self):
"""应用最小系统调用白名单"""
filter = seccomp.SyscallFilter(seccomp.ALLOW)
filter.set_attr(seccomp.ATTR_DEFAULT_KILL, None)
allowed_syscalls = [
"read", "write", "open", "openat", "close",
"stat", "fstat", "lstat", "lseek",
"mmap", "mprotect", "munmap", "brk",
"access", "pipe", "select", "sched_yield",
"dup", "dup2", "getpid", "getppid",
"getuid", "getgid", "geteuid", "getegid",
"arch_prctl", "set_tid_address",
"futex", "clock_gettime", "clock_getres",
"exit_group", "rt_sigreturn",
"sigaltstack", "rt_sigaction", "rt_sigprocmask",
]
for name in allowed_syscalls:
filter.add_rule(seccomp.ALLOW, name)
filter.load()
def _apply_landlock(self):
"""应用 Landlock 文件访问规则"""
# 使用 Python ctypes 封装 Landlock syscall
LANDLOCK_ACCESS = (
0x0001 | # EXECUTE
0x0002 | # WRITE_FILE
0x0008 | # READ_FILE
0x0010 | # READ_DIR
0x0020 | # REMOVE_DIR
0x0040 | # REMOVE_FILE
0x0080 | # MAKE_CHAR
0x0100 | # MAKE_DIR
0x0200 # MAKE_REG
)
# landlock_create_ruleset
# landlock_add_rule (LANDLOCK_RULE_PATH_BENEATH)
# landlock_restrict_self
pass
def _fork_sandbox(self) -> int:
"""创建并隔离子进程"""
import ctypes
libc = ctypes.CDLL("libc.so.6", use_errno=True)
CLONE_FLAGS = (0x20000000 | # CLONE_NEWNS
0x10000000 | # CLONE_NEWPID
0x04000000 | # CLONE_NEWIPC
0x08000000 | # CLONE_NEWUTS
0x00000100 | # CLONE_NEWUSER
0x00020000) # CLONE_NEWCGROUP
# 如果禁用网络,添加 NET 隔离
if not self.allow_network:
CLONE_FLAGS |= 0x40000000 # CLONE_NEWNET
pid = libc.clone(
ctypes.c_void_p(0), # 使用 vfork 语义
None,
CLONE_FLAGS,
ctypes.c_void_p(0)
)
return pid
十、总结与展望
本文构建了一套完整的 AI Agent 工具执行沙箱体系:
安全层次 防护目标 内核版本
─────────────────────────────────────────────────────────────
Namespace 隔离 → 进程/网络/文件系统视图隔离 3.8+
cgroup v2 → CPU/内存/IO/进程数资源限制 4.15+
seccomp-bpf → 系统调用白名单过滤 3.5+
Landlock v4 → 文件系统细粒度访问控制 5.13+
eBPF LSM → 运行时安全策略执行 5.7+
PR_SET_NO_NEW_PRIVS → 防止特权提升 3.5+
对于不同安全等级的场景,我们可以组合不同的安全层:
- Level 1(低风险工具):Namespace 隔离 + cgroup 限制
- Level 2(标准工具):Level 1 + seccomp-bpf 白名单
- Level 3(高风险工具):Level 2 + Landlock 文件沙箱
- Level 4(不信任代码):Level 3 + eBPF LSM + PSI 监控
随着 Linux 内核持续演进,未来我们可以期待更多沙箱相关的特性:
- mount API 演进:open_tree/clone_make 为更精细的挂载控制提供基础
- PIDFD 隔离:通过 pidfd_getfd 限制跨进程操作
- io_uring 安全:新增的 seccomp 过滤器规则覆盖 io_uring 系统调用
- 透明内存加密:AMD SEV-SNP / Intel TDX 在 Agent 场景的应用
AI Agent 的安全沙箱仍在快速演进中。作为系统工程师,我们需要深入理解内核安全机制,才能在 Agent 时代构建真正可靠的安全边界。
关键原则铭记:沙箱不是银弹,但它能让攻击代价呈指数级增长。纵深防御的核心在于——任何一层都不完美,但多层组合后的安全边界足以抵御绝大多数现实攻击。

发表评论 取消回复