想象你是一家银行的柜员。一位蒙面客户递进来一个密封包裹,说里面是一笔巨额存款的凭证,请你帮忙验证。你会怎么做?直接拿进金库拆开?万一里面是炸弹呢? AI 大模型就像这位蒙面客户——它才华横溢,能写出可运行的程序,但也可能“使坏”:生成一段看似正常、实则删除文件或窃取数据的代码。在 HumanEval 这场“AI 编程能力考试”中,我们要让模型写代码、做测试题,但绝不能让它写的代码在我们自己的电脑上裸奔。于是,工程师们建了一座特殊的“银行隔离验证室”——代码执行安全沙箱。 沙箱是一座透明的小房间:AI 生成的代码可以在里面肆意运行、接受测试,但房间有防弹玻璃(容器隔离)、有安保门禁(资源限制)、有严格安检(系统调用过滤)。代码产生的任何破坏力都被封在房里,评测结果却能安全传出。这样,我们既看清了 AI 的真实编程水平,又保住了自己的系统。 这篇文章,就来拆解这座“验证室”的每一面墙、每一道门。

岗位关联

一句话价值:理解代码执行安全沙箱,是搭建 AI 评测系统的安全地基,也是你在 AI 基础设施团队站稳脚跟的核心能力。

目录
  1. 可视化演示
  2. 沙箱基本概念
  3. 容器化隔离
  4. 资源限制
  5. 系统调用过滤
  6. 评测执行流程
  7. 安全威胁模型
  8. 结果可靠性
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示进程隔离命名空间隔离系统调用过滤资源配额四层防护链、轻量中量重量三类沙箱的隔离强度与开销权衡、以及HumanEval评测中代码经沙箱安全执行并跑测试判分的流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

四层隔离防护链 进程+命名空间隔离 系统调用过滤防逃逸 seccomp+资源配额 层层递进限制不可信代码副作用

沙箱基本概念

银行收到蒙面客户递来的包裹,不会直接拿进金库,而是送进隔离验证室处理。这是银行业百年来的安全直觉:对来源不明的物品,默认不信任,先隔离再验证。AI 生成的代码正是这样的“蒙面包裹”——它可能完美,也可能包含致命危险。HumanEval 中的沙箱,就是计算机世界里的“隔离验证室”。

代码执行安全沙箱是一个受控的运行环境,专门用来运行不可信代码。在 HumanEval 评测中,模型生成的解题代码就是典型的“不可信输入”,系统会在执行前把它送进沙箱。沙箱的核心思想是信任边界(trust boundary):系统先给每段代码打一个信任度分,低于阈值的代码一律进入隔离环境。

有了信任边界,系统就能明确划分“可信世界”与“不可信世界”:所有跨越边界的数据交互都要经过检查。AI 模型的输出默认不可信,这个“默认”二字,正是沙箱安全性的根基。

就像银行不会因为包裹看起来漂亮就取消隔离流程,HumanEval 的沙箱对每一段 AI 代码一视同仁。信任边界就是验证室的那扇铁门:门后的世界再精彩,也必须在检查之后才能进入。

Isolate(x)={1,trust(x)<θ0,trust(x)≥θ\text{Isolate}(x) = \begin{cases} 1, & \text{trust}(x) < \theta \\ 0, & \text{trust}(x) \geq \theta \end{cases}
这个公式是说:当一段代码 \(x\) 的可信度打分低于阈值 \(\theta\) 时,它就会被送进沙箱;否则可以在常规环境运行。AI 生成的代码信任分普遍很低,所以几乎总是触发隔离。
  1. trust(x) 可信度打分对代码 x 的安全评估值,范围 0 到 1,越接近 1 越可信。
    trust(x)∈[0,1]\text{trust}(x) \in [0, 1]
  2. θ 信任阈值由安全策略预先设定,θ 越高意味着越谨慎,更多代码会被隔离。
    θ=0.5 (默认值)\theta = 0.5 \ (\text{默认值})
  3. Isolate(x)=1 触发隔离当打分低于阈值,代码必须进入沙箱。
    Isolate(x)=1⇒代码进入沙箱\text{Isolate}(x) = 1 \Rightarrow \text{代码进入沙箱}
  4. 判定逻辑宁可错杀一千,不可放过一个——拿不准就隔离。
    当 trust(x)<θ 时,无条件隔离\text{当 trust}(x) < \theta \text{ 时,无条件隔离}

容器化隔离

验证室的第一道屏障是防弹玻璃墙——你能看到房间里发生什么,但手伸不过去。容器化隔离就是这样一堵玻璃墙:AI 代码可以运行,却看不到、摸不到宿主系统的资源。

容器(Container)是一种轻量级虚拟化技术,它不模拟整台电脑,而是用命名空间(namespace)为进程制造一个“独立的世界”。在 HumanEval 平台,每个评测任务通常跑在独立容器里,拥有自己的文件系统视图、进程表和网络栈。文件系统隔离让容器内的“根目录”只是宿主机某个目录的投影;代码即使试着读取 /etc/passwd,打开的也是容器内伪造的空文件。

网络隔离则让容器默认无法访问内网或外部服务,只有评测服务器能通过受控通道与它通信。这样,代码想“翻墙”偷数据时,连“窗户”都找不到。

防弹玻璃的比喻在这里完美落地:代码可以在自己的“独立房间”里横冲直撞,但撞上玻璃墙时只会被弹回,而伤不到墙外的人。

Viewcontainer=Viewhost∖Ssensitive\text{View}_{\text{container}} = \text{View}_{\text{host}} \setminus \mathcal{S}_{\text{sensitive}}
容器里能看到的世界 = 宿主真实世界 − 敏感资源。敏感资源包括密钥文件、内网端口、宿主目录等,被全部隐藏起来。
  1. View_host 宿主视图宿主系统能看到的全部资源集合,包括文件、网络、进程。
    Viewhost={文件}∪{网络}∪{进程}\text{View}_{\text{host}} = \{\text{文件}\} \cup \{\text{网络}\} \cup \{\text{进程}\}
  2. S_sensitive 敏感资源需要重点保护的对象,如用户密钥、内网地址。
    Ssensitive={/home/user, 10.x.x.x, /proc/kcore}\mathcal{S}_{\text{sensitive}} = \{\text{/home/user, 10.x.x.x, /proc/kcore}\}
  3. 集合减法容器视图等于宿主视图去掉敏感资源,构成一个“不完整的世界”。
    Viewcontainer=Viewhost−Ssensitive\text{View}_{\text{container}} = \text{View}_{\text{host}} - \mathcal{S}_{\text{sensitive}}
  4. 隔离效果代码在容器内的一切操作,都被局限在这个“不完整的世界”里。

资源限制

验证室还有一个容易被忽视的设计:供电和空调都有上限。如果包裹里藏着一个“电耗子”——疯狂消耗电力的装置,它就能耗尽整栋楼的电力,让银行瘫痪。AI 代码同样可能“疯狂耗电”:死循环、内存爆炸,拖垮整台评测机。

资源限制从三个维度锁死危险:CPU 配额、内存上限、超时控制。CPU 配额防止死循环占满所有核心;内存上限防止代码申请海量内存导致宿主卡死;超时控制保证每个用例都能在预期时间内跑完。在 HumanEval 中,每个代码进程都会被分配明确的 CPU 时间片和内存额度。

当进程超越限额,系统会亮出强制手段:CPU 超时用 SIGKILL 终止进程,内存超限触发 OOM Killer。这些机制在 Linux 上通过 cgroups 或容器资源参数实现。无论 AI 代码写得多么恶劣,都动摇不了宿主系统的一根汗毛。

资源限制就像验证室里的保险丝:正常电器随便用,一旦短路立刻断电,保护整栋楼。HumanEval 中的每一个死循环、每一段内存炸弹,都被这根保险丝稳稳接住。

Status={OK,trun≤tlimit∧mempeak≤memmax⁡KILLED,otherwise\text{Status} = \begin{cases} \text{OK}, & t_{\text{run}} \leq t_{\text{limit}} \land \text{mem}_{\text{peak}} \leq \text{mem}_{\max} \\ \text{KILLED}, & \text{otherwise} \end{cases}
当运行时间没超过时限、内存峰值没超过上限时,进程状态为 OK;只要有一项超标,进程就会被强制终止。
  1. t_run 已运行时间从代码启动到当前时刻的耗时,由系统计时器测量。
    trun=clockend−clockstartt_{\text{run}} = \text{clock}_{\text{end}} - \text{clock}_{\text{start}}
  2. t_limit 超时上限预设的允许运行时长,HumanEval 中通常为秒级。
    tlimit=2.0 st_{\text{limit}} = 2.0 \ \text{s}
  3. mem_peak 与 mem_max内存峰值和内存上限,单位通常为 MB。
    mempeak≤memmax⁡=64 MB\text{mem}_{\text{peak}} \leq \text{mem}_{\max} = 64 \ \text{MB}
  4. 与逻辑判定两个条件同时满足才放行,任一超标就终止。
    Status=KILLED⇒进程被强制终止\text{Status} = \text{KILLED} \Rightarrow \text{进程被强制终止}

系统调用过滤

验证室里最严格的一关是安检员。每个包裹、每件随身物品都要过安检;安检员手里有一份“批准清单”,清单上没有的东西一律不许带进房间。系统调用过滤,就是操作系统层面的“安检员”。

程序运行时会向操作系统请求服务:打开文件、发送网络包、创建进程——这些请求叫系统调用(system call)。沙箱利用 seccomp 机制在系统调用入口设置检查点:每个系统调用都必须能在白名单里找到自己,才能被放行。

白名单遵循“最小权限原则”:只允许解题必需的 read、write、exit 等无害调用;execve(执行新程序)、socket(创建网络连接)、ptrace(调试附加)等高危调用全部禁止。在 HumanEval 中,一道标准解答只需要计算函数,根本不需要网络和进程创建——所以这些高危调用一律拉黑。

安检员的检查不因包裹漂亮而通融。AI 代码想偷偷建立网络连接上传数据?被拦下。想启动新进程?被拦下。白名单之外,寸步难行。

Allow(s)={1,s∈Wwhitelist0,s∉Wwhitelist\text{Allow}(s) = \begin{cases} 1, & s \in \mathcal{W}_{\text{whitelist}} \\ 0, & s \notin \mathcal{W}_{\text{whitelist}} \end{cases}
系统调用 s 如果属于白名单集合就放行,否则拒绝。这是“非白即黑”的最小权限控制。
  1. s 系统调用程序请求操作系统服务的操作名,比如 open、read、execve。
    s∈{read, write, execve, open, socket, … }s \in \{\text{read, write, execve, open, socket, } \dots\}
  2. W_whitelist 白名单由评测策略预先定义的允许调用集合。
    Wwhitelist={read, write, exit, brk, … }\mathcal{W}_{\text{whitelist}} = \{\text{read, write, exit, brk, } \dots\}
  3. Allow(s)=0 拒绝调用被拦截,进程收到 EPERM 错误。
    Allow(s)=0⇒返回 EPERM 错误\text{Allow}(s) = 0 \Rightarrow \text{返回 EPERM 错误}
  4. 安全性质代码想越狱,连“开锁工具”(高危系统调用)都拿不到。

评测执行流程

验证室有了墙、电力和安检,现在可以正式运转了。HumanEval 的评测流程就像验证室的标准作业程序:接收包裹(代码)、按流程检验(运行测试)、出具报告(结果)。

HumanEval 是 OpenAI 提出的经典编程评测基准,包含 164 道手工编写的编程题。每道题给模型一个函数签名和文档字符串,要求模型补全函数体。评测时,平台把模型生成的代码放进沙箱,注入测试用例,运行并观察输出是否与预期一致。沙箱保证测试能安全执行,同时统计出可比的成绩。

判定标准是测试用例通过率:一个函数通过全部单元测试,才算解题成功。整体指标常用 pass@1、pass@k——前者是单次生成的最优通过率,后者是 k 次生成中至少一次通过的期望比例。这些指标都以沙箱内的真实运行结果为基础,杜绝了“跑都没跑就瞎猜”的可能性。

整个流程环环相扣:沙箱是考场,测试题是考卷,通过率是分数。AI 模型像考生一样在隔离考场完成考试,没有作弊余地,成绩自然可信。

PassRate=1N∑i=1N1[outputi=expectedi]×100%\text{PassRate} = \frac{1}{N}\sum_{i=1}^{N} \mathbb{1}\big[\text{output}_i = \text{expected}_i\big] \times 100\%
通过率 = 输出与预期一致的用例数 ÷ 总用例数 × 100%。全对才是 100%,任何一例不相等都会拉低分数。
  1. N 测试用例总数一道题配备的验证案例数量。
    N=#{测试用例}N = \#\{\text{测试用例}\}
  2. output_i 实际输出第 i 个用例在沙箱中运行得到的输出。
    outputi=sandbox.run(casei)\text{output}_i = \text{sandbox.run}(\text{case}_i)
  3. expected_i 预期输出题目作者预先写好的标准答案。
    expectedi=标准答案i\text{expected}_i = \text{标准答案}_i
  4. 指示函数相等时记 1,不等时记 0。
    1[x]={1,x 成立0,x 不成立\mathbb{1}[x] = \begin{cases} 1, & x \ \text{成立} \\ 0, & x \ \text{不成立} \end{cases}
  5. 通过率计算所有用例的得分求和后除以总数,再换算成百分数。
    PassRate=通过数N×100%\text{PassRate} = \frac{\text{通过数}}{N} \times 100\%

安全威胁模型

验证室要防的“坏家伙”不止一种。银行防抢劫犯,沙箱防恶意代码。威胁模型(Threat Model)就是给“坏家伙”画像:他们是谁、想干什么、会造成多大伤害。

第一类威胁是恶意代码本身:AI 模型可能被诱导生成删除文件、篡改数据的代码。第二类是数据窃取:代码尝试读取环境变量、扫描文件系统,再通过网络把隐私发出去。第三类是资源耗尽(DoS):用死循环或内存炸弹拖垮评测机,影响其他用户。

安全工程用 Risk = P × I 量化威胁:P 是攻击发生概率,I 是成功后的影响。沙箱的目标是同时压低 P 和 I——容器隔离与系统调用过滤让 P 趋近于 0,资源限制让 I 止步于“进程被杀”而不是“宿主机宕机”。

银行不会只装一道门,沙箱也不会只靠一种防御。容器、资源限制、系统调用过滤三道防线,让恶意代码的“威胁之花”无法绽放。

Risk=Pexploit×Impactseverity\text{Risk} = P_{\text{exploit}} \times \text{Impact}_{\text{severity}}
风险 = 攻击成功概率 × 攻击成功后的危害等级。只要其中一个因子为 0,整体风险就是 0。
  1. P_exploit 攻击概率攻击者突破防御的成功率,多层防护下趋近于 0。
    Pexploit≈0(多重防御下)P_{\text{exploit}} \approx 0 \quad (\text{多重防御下})
  2. Impact_severity 危害等级攻击成功造成的损失,从“进程退出”到“宿主被控”不等。
    Impact∈{无害, 泄露, 失控}\text{Impact} \in \{\text{无害, 泄露, 失控}\}
  3. 乘法关系任何一个因子被压到 0,整体风险归零。
    Risk=0⇔P=0 或 Impact=0\text{Risk} = 0 \Leftrightarrow P = 0 \ \text{或} \ \text{Impact} = 0
  4. 纵深防御多层控制同时生效,风险被几何级数压低。

结果可靠性

验证室出具的报告必须经得起复核:同一个包裹,今天验证通过,明天也不能说失败。评测结果的可信度,是沙箱设计的最后一块拼图。

结果可靠性依赖环境一致性:所有代码在完全相同的操作系统、运行库和资源配额下运行,排除环境差异导致的偶然失败。其次是可复现性:同一段代码和同一组测试,多次运行应得到同样结果。HumanEval 平台还会先运行参考实现来校准沙箱——如果参考代码都跑不通过,说明沙箱配置有问题,评测结果就不可信。

误报控制同样是关键:沙箱不应该把正常代码误判为恶意代码。白名单过紧会导致无谓失败,过松又会带来安全风险。工程师通过大量回归测试来调整边界,确保沙箱“既挡得住坏人,也不冤枉好人”。

验证室的复核档案就是这份“一致性台账”。AI 模型的每一次解题成绩,都必须经得起台账检验——否则分数再高,也只是海市蜃楼。

Consistency=NsameNtotal×100%\text{Consistency} = \frac{N_{\text{same}}}{N_{\text{total}}} \times 100\%
一致性 = 重复运行中结果相同的次数 ÷ 总运行次数 × 100%。比值越接近 100%,评测结果越可信。
  1. N_total 总运行次数同一任务重复运行的次数,用于检验稳定性。
    Ntotal=5 (示例)N_{\text{total}} = 5 \ (\text{示例})
  2. N_same 相同结果次数与首次运行结果一致的运行次数。
    Nsame=#{ri=r0}N_{\text{same}} = \#\{r_i = r_0\}
  3. 比值计算相同次数除以总次数,转换为百分比。
    Consistency=NsameNtotal×100%\text{Consistency} = \frac{N_{\text{same}}}{N_{\text{total}}} \times 100\%
  4. 可信标准一致性达到 100%,才说明沙箱没有抖动、评测可信。

AI 应用场景

场景一:AI 编程助手的在线运行测试

阶段:模型部署与工具链集成

解决的问题:GitHub Copilot 这类工具在生成代码后,常提供“运行预览”功能。如果没有沙箱,用户点一下运行按钮,恶意代码就会直接在本地电脑执行,后果不堪设想。沙箱把预览运行隔离在云端容器中,用户只看到输出,绝不接触危险操作。

具体案例:用户在 IDE 中让 AI 写一个“递归删除文件夹”的函数,AI 生成了包含 shutil.rmtree 的代码。预览功能在沙箱中执行它,触发白名单拦截,向用户展示警告而不是真的删掉本地目录。

场景二:CI/CD 流水线自动审查 AI 生成代码

阶段:模型评测与持续集成

解决的问题:研发团队把 AI 生成的代码提交进代码仓库前,需要自动验证“代码能跑、且不使坏”。传统代码审查靠人工,面对海量 AI 提交根本看不过来。沙箱化测试流水线自动执行单元测试,同时用资源限制和系统调用过滤筛掉危险代码。

具体案例:某团队在 Jenkins 流水线中接入沙箱评测节点,每次 AI 提交代码都在隔离容器中跑测试。某次提交中的代码试图读取环境变量中的密钥,被 seccomp 白名单拦截,流水线自动打回提交并生成安全报告。

场景三:AI 编程竞赛平台的判题系统

阶段:模型性能评估与排行榜

解决的问题:竞技类平台允许参赛者提交代码与其它模型对战,代码可能故意攻击评测服务器。判题沙箱保证每份提交都在同等资源限制下运行,成绩公平且系统不被打垮。

具体案例:某 LLM 编程竞赛的判题节点收到一个尝试 fork 炸弹的提交。沙箱的进程数限制和 CPU 配额立刻终止该进程,参赛模型被判超时失败,而评测服务器毫发无损,排行榜继续正常运行。

Python 演示

python98 行
"""HumanEval 代码执行安全沙箱模拟器"""import astimport subprocessimport sysimport tempfile try:    import resourceexcept ImportError:    resource = None  class SandboxError(Exception):    """沙箱拒绝执行时抛出的异常"""    pass  class SandboxEvaluator:    """简化沙箱:AST 过滤 + 子进程资源限制"""     WHITELIST = {        'abs', 'all', 'any', 'bool', 'dict', 'enumerate', 'float',        'format', 'int', 'len', 'list', 'map', 'max', 'min', 'ord',        'print', 'range', 'reversed', 'round', 'set', 'sorted',        'str', 'sum', 'tuple', 'zip'    }     def __init__(self, timeout_sec=2, memory_mb=64, cpu_sec=1):        self.timeout_sec = timeout_sec        self.memory_limit_mb = memory_mb        self.cpu_limit_sec = cpu_sec     def check_source(self, source):        """用 AST 白名单过滤危险写法"""        tree = ast.parse(source)        for node in ast.walk(tree):            if isinstance(node, ast.Import):                raise SandboxError('禁止导入任何模块')            if isinstance(node, ast.Attribute):                raise SandboxError('禁止访问对象属性')            if isinstance(node, ast.Call) and isinstance(node.func, ast.Name):                if node.func.id not in self.WHITELIST:                    raise SandboxError('禁止调用: ' + node.func.id)        return tree     def run_code(self, source):        """在子进程内运行,并施加 CPU/内存限制"""        with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:            f.write(source)            script_path = f.name         def limit():            resource.setrlimit(                resource.RLIMIT_CPU,                (self.cpu_limit_sec, self.cpu_limit_sec)            )            limit_bytes = self.memory_limit_mb * 1024 * 1024            resource.setrlimit(                resource.RLIMIT_AS,                (limit_bytes, limit_bytes)            )         try:            proc = subprocess.run(                [sys.executable, script_path],                capture_output=True, text=True,                timeout=self.timeout_sec,                preexec_fn=limit if (resource and sys.platform != 'win32') else None            )            return {'output': proc.stdout, 'err': proc.stderr,                    'code': proc.returncode, 'timed_out': False}        except subprocess.TimeoutExpired:            return {'output': '', 'err': 'timeout', 'code': -1, 'timed_out': True}     def evaluate(self, source, test_snippet):        """执行一轮 HumanEval 风格评测"""        self.check_source(source)        full_program = source + '\n' + test_snippet        return self.run_code(full_program)  if __name__ == '__main__':    sb = SandboxEvaluator(timeout_sec=3, memory_mb=64)     good_code = 'def add(a, b):\n    return a + b\n'    tests = 'print(add(1, 2))\nprint(add(10, 5))\n'    result = sb.evaluate(good_code, tests)     expected = '3\n15\n'    passed = (result['code'] == 0) and (result['output'] == expected)    print('正常代码评测结果:', '通过' if passed else '失败', result['output'], result['err'])     bad_code = 'import os\nos.system("rm -rf /tmp/x")\n'    try:        sb.evaluate(bad_code, '')        print('恶意代码未被拦截!')    except SandboxError as e:        print('恶意代码被拦截:', e)
目的:用 Python 实现一个简化版 HumanEval 沙箱,先用 AST 白名单拦截危险代码,再用子进程和资源限制约束运行行为。
  1. import ast引入 Python 的抽象语法树模块,用于静态分析代码结构。
  2. class SandboxEvaluator:定义一个沙箱评测器类,封装安全检查与执行逻辑。
  3. def check_source(self, source):在运行前对源码做安全检查,是“安检员”的核心方法。
  4. if isinstance(node, ast.Import):发现 import 节点立即拦截,禁止任何模块导入。
  5. raise SandboxError('禁止导入任何模块')抛出沙箱异常,拒绝执行该代码。
  6. def limit():定义资源限制回调,会在子进程启动前执行。
  7. resource.setrlimit(resource.RLIMIT_CPU, ...)给子进程设置 CPU 时间上限。
  8. resource.setrlimit(resource.RLIMIT_AS, ...)设置进程虚拟内存上限,防止内存炸弹。
  9. subprocess.run(...)在单独的子进程中运行代码,进程崩溃不影响宿主。
  10. preexec_fn=limit if (resource and sys.platform != 'win32') else None在子进程启动前施加上限,兼容非 Unix 环境。
  11. except subprocess.TimeoutExpired:捕获超时异常,返回超时标记而不是让宿主卡死。

常见误区

误区很多初学者以为只要把 AI 代码丢进 Docker 容器,就万事大吉。他们会说“我已经用容器隔离了,怎么还会被攻击?”

正解容器只是沙箱的第一层墙。Docker 默认共享宿主内核,如果没有配合资源限制和 seccomp 过滤,恶意代码依然可以用内核漏洞或资源耗尽攻击跑出容器。就像银行验证室只有玻璃墙,却没有门禁和安检——小偷照样能爬窗进来。真正的沙箱 = 容器隔离 + 资源配额 + 系统调用白名单。

为何常见:因为容器化是最容易感知的隔离方式,文档里处处强调“隔离”,让人误以为隔离等于绝对安全。

误区有人觉得“我只是在本地跑跑测试,AI 代码能有多坏?”于是直接在没有沙箱的环境里执行模型输出。

正解AI 代码的危险性是随机的,不是故意的。即使模型没有恶意,它也可能生成 os.system('rm -rf /') 这种训练数据里的危险模式。本地评测机器一旦中招,丢失的可能是未提交的代码和论文数据。沙箱的成本很低,而裸奔的代价可能极高。

为何常见:因为危险性看不见摸不着,人们倾向于低估低概率高损失事件,本地便利性压过了安全意识。

误区初学者常以为白名单是“功能保障”,多多益善:“反正这些调用都是正常操作,全放进去不就完了?”

正解白名单的哲学是“最小权限”——只放行解题必需的系统调用。每多放一个调用,就多一个被恶意代码利用的窗口。比如放开 socket 后,代码就能外传数据;放开 ptrace 后,代码就可能调试附加到其它进程。功能越少,攻击面越小。

为何常见:因为很多人从“功能优先”的角度思考,忽略了安全是从“减法”里获得的。

误区看到沙箱中跑出的测试用例全部通过,就认为这段 AI 代码是安全的,可以直接上生产。

正解通过率只验证“功能正确”,与“安全无害”是两个维度。一段代码可能完美通过了 add(a, b) 的十个测试,同时偷偷执行了 shutil.rmtree('/home/user')。HumanEval 的沙箱保证代码执行本身无害,但生产环境的代码评审还需要额外的安全审查。

为何常见:因为测试通过给人的直观感受是“没问题”,混淆了正确性评价与安全性评价的边界。

面试题

Q1. 代码执行安全沙箱的核心目的是什么?

单选题 · easy

  • A.加速代码运行性能
  • B.隔离不可信代码保护宿主← 正确答案
  • C.美化代码输出界面
  • D.提升模型准确率

答案:B。沙箱本质是“隔离验证室”:让不可信代码在受控环境中运行,防止它危害宿主系统。A 是性能优化、C 是 UI 问题、D 是模型训练问题,都与沙箱的核心目的无关。

Q2. 以下哪项最符合 HumanEval 评测中沙箱的工作?

单选题 · easy

  • A.压缩代码体积减少存储
  • B.限制代码网络访问并隔离资源← 正确答案
  • C.自动修复代码中的 bug
  • D.评估代码风格是否规范

答案:B。在 HumanEval 评测中,沙箱负责隔离执行环境、限制资源和过滤系统调用,让模型生成的代码安全地跑完测试。压缩体积、修 bug、评风格都不是沙箱的职责。

Q3. 容器化隔离在沙箱中的作用类似于银行验证室的哪样设施?

单选题 · mid

  • A.前台的登记簿
  • B.防弹玻璃墙← 正确答案
  • C.金库的防盗门
  • D.柜台的验钞机

答案:B。容器化隔离提供“看得见但摸不着”的边界,对应验证室的防弹玻璃:能观察内部运行,但资源无法相互触碰。登记簿、防盗门、验钞机分别是日志、访问控制和真伪验证,与容器隔离的功能不同。

Q4. seccomp 机制在沙箱中的主要作用是?

单选题 · mid

  • A.监控网络流量日志
  • B.过滤系统调用← 正确答案
  • C.加密磁盘存储
  • D.自动备份评测数据

答案:B。seccomp 是 Linux 内核提供的系统调用过滤机制,相当于安检员的“批准清单”检查,决定哪些系统调用能执行。网络监控、磁盘加密、数据备份都与 seccomp 无关。

Q5. 如果把系统调用白名单设置得过大,最可能产生的风险是什么?

单选题 · mid

  • A.程序运行速度变慢
  • B.攻击面扩大← 正确答案
  • C.内存占用率升高
  • D.代码文件体积变大

答案:B。白名单每多放一个系统调用,就多一个被恶意代码利用的窗口。比如放开 socket 后代码就能外传数据,攻击面随之扩大。白名单大小与性能、内存、文件体积没有直接关系。

Q6. 某模型对一道题生成了 10 个答案,其中 3 个正确。用 pass@5 指标评估(n=10,c=3,k=5),pass@5 约为多少?

单选题 · hard

  • A.pass@5 为 30%
  • B.pass@5 为 91.7%← 正确答案
  • C.pass@5 为 100%
  • D.无法直接计算

答案:B。pass@k 的无偏估计是 \(1-\binom{n-c}{k}/\binom{n}{k}\)。代入 n=10、c=3、k=5,得 \(1-\binom{7}{5}/\binom{10}{5}=1-21/252\approx 91.7\%\)。30% 是把正确数除以总数(3/10),100% 忽略了采样不全的可能,D 忽略了公式可计算性。

Q7. 资源限制中的“内存上限”主要用于防御哪种攻击?

单选题 · mid

  • A.代码行数过多撑爆磁盘
  • B.内存泄漏或无限申请耗尽宿主← 正确答案
  • C.CPU 风扇转速过快
  • D.网络带宽被下载任务占满

答案:B。内存上限封顶进程可申请的内存量,防止内存炸弹或泄漏拖垮宿主系统。代码长度、风扇转速、网络带宽分别对应存储、硬件和网络维度,都不是内存限制的直接目标。

Q8. 以下哪些属于 HumanEval 沙箱的防御手段?

多选题 · mid

  • A.容器化隔离环境← 正确答案
  • B.CPU 和内存配额控制← 正确答案
  • C.系统调用白名单过滤← 正确答案
  • D.代码格式化与美化

答案:ABC。容器隔离、资源配额、系统调用白名单是沙箱的三道核心防线。代码格式化只是排版工具,不具备任何安全防护能力,因此不应选 D。

Q9. 影响 HumanEval 评测结果可靠性的因素包括?

多选题 · mid

  • A.运行环境的一致性← 正确答案
  • B.评测结果的可复现性← 正确答案
  • C.模型参数量大小
  • D.沙箱对正常代码的误伤← 正确答案

答案:ABD。环境一致性确保不同时间运行结果可比,可复现性确保重复运行结果稳定,沙箱误伤会导致正常代码被误判失败——三者都直接影响可靠性。模型参数量是模型本身的属性,与评测环境的可靠性无关。

Q10. 关于威胁模型公式 Risk = P × Impact,以下说法正确的有?

多选题 · hard

  • A.P 趋近 0 时,即使 Impact 很大整体风险也很低← 正确答案
  • B.纵深防御可以同时压低 P 和 Impact← 正确答案
  • C.沙箱只改变 P 而不影响 Impact
  • D.资源耗尽攻击的后果主要体现在 Impact 维度← 正确答案

答案:ABD。乘法模型中任一因子为 0 则总体风险为 0,A 正确。容器隔离和系统调用过滤主要压低攻击概率 P,资源限制减小危害 Impact,C 说“只改变 P 不影响 Impact”不正确。资源耗尽攻击让服务不可用,属于危害等级 Impact 维度的体现,D 正确。