Repository navigation
Sandbox Security
dxx114514-stack edited this page Oct 1, 2026
·
2 revisions
CliJudge 采用纵深防御:选手代码在多层隔离中执行,可信组件单独归类,导入外部内容时显式告警。
| 执行者 | 模式 | 隔离 |
|---|---|---|
| 选手提交代码 | 受限(untrusted) | 完整沙箱:全部隔离层生效 |
| 编译器(g++/javac/自定义 compile) | 可信 | 保留时间限制(compile_time_limit_ms),跳过隔离层 |
| SPJ / 交互器 / 生成器 / grader | 可信(放宽隔离) | 保留时间/内存/进程限制,但跳过受限令牌、命名空间与 seccomp 等隔离层,可写工作目录 |
导入告警:problem import / contest import 检测到题目包携带 SPJ / 交互器 / 生成器 / grader 组件时,输出:
Warning: this package contains special judge/interactor/generator/grader code,
which is executed in a trusted (reduced-isolation) mode during judging.
Only import packages from sources you trust.
→ 只导入可信来源的题目包与 CDF。
contest import(CDF)的告警文案首句为Warning: this CDF contains …、末句为Only import contests from sources you trust.;其检测条件只看spj/interactor/grader/graderFilesPath字段——CDF 结构本就没有 generator 字段,文案里的 "generator" 属通用模板串。
-
进程树隔离 —
CREATE_SUSPENDED+ Job Object 绑定后才恢复执行,杜绝竞态逃逸 -
强制回收 —
KILL_ON_JOB_CLOSE:主进程结束则整棵进程树被系统强制秒杀 -
禁止脱离 — 禁用
BREAKAWAY,子进程无法脱离沙箱 - 权限降级 — 受限令牌剥离 SeDebug / SeImpersonate 等高危特权,Low Integrity Level 运行
- 资源限制 — 内存上限、CPU 时间限制双重保障
- 数据隔离 — 每次判题独立临时目录,结束后暴力删除
可用编译期宏关闭部分安全特性(有明确风险时才使用):
CLIJUDGE_NO_LOWIL(关闭 Low Integrity Level)、CLIJUDGE_NO_RELABEL(关闭完整性重标记)。
-
命名空间阶梯 — 依次尝试
user+mnt+pid+net+ipc+uts→user+mnt→ 普通 fork(全失败逐级降级);自写 uid/gid 映射 -
文件系统 — make-rprivate
/→ 绑定可写 workDir 与/tmp→ 全新/proc→ 卸载/sys→ 只读重挂载根文件系统(保持 workDir 可写) -
网络 — 新 net namespace(空网卡)+ seccomp 拒绝
socket双重兜底 -
seccomp — 架构检查 + syscall 黑名单:
mount/ptrace/提权/网络配置等敌意调用 → SIGSYS;clone3/io_uring/bpf等探测型 → ENOSYS;untrusted && maxProcesses==1时拒绝进程创建(fork/vfork/非线程 clone → EPERM),线程不受限,其余场景父进程 10ms 轮询进程组超限击杀 -
环境变量白名单 — 最小 env 注入(PATH 等),附加变量见
judge.env -
RLIMIT —
RLIMIT_CPU/RLIMIT_AS(内存)/RLIMIT_STACK/RLIMIT_FSIZE(写文件上限)
加固环境(如 Ubuntu 24.04+ 默认 kernel.apparmor_restrict_unprivileged_userns=1)会拒绝 uid_map 自写(EPERM)。沙箱每次进程首跑前执行 probeSandboxCaps() 预检:
- uid_map 不可写 → 命名空间阶梯直接从 level0(普通 fork)起步,靠 seccomp + RLIMIT 兜底
- seccomp 不可安装 → 不安装过滤器,靠 RLIMIT 兜底
- 预检通过的环境(如普通发行版 / WSL)行为不变,仍用完整命名空间隔离
诊断:设置环境变量 CLIJUDGE_SANDBOX_DEBUG=<文件路径> 可记录每次沙箱启动的 level / caps / 失败点 / AppArmor profile(冒烟测试默认开启)。
-
原子写 — 题目/比赛/文章/提交索引与
config.json均采用「临时文件 + rename 原子替换」,崩溃不会留下半截 JSON;例外:.cjl语言包与首装内置包用普通writeFile写入(非原子,崩溃可能留半截语言包,可重新displaylang pull修复) -
跨进程锁 —
data/.clijudge.lock(WindowsLockFileEx/ Linuxflock)对修改类命令排他,读命令依赖原子快照无需加锁;例外:problem testdata子命令(含list)按粗粒度归入修改类同样加锁;进程崩溃后 OS 自动释放锁
- 以普通用户运行即可;Windows 下如遇沙箱执行失败,尝试管理员身份运行
- Linux 评测 C/C++ 需要 PATH 上有
g++;Python 需要python3 - 不要在不可信机器上以高权限运行 CliJudge 本体