如何使用 Landlock?
解读
在国内 Rust 后端、云原生与容器安全方向的面试中,“如何使用 Landlock” 并不是让你背诵系统调用,而是考察三点:
- 是否知道 Linux 5.13+ 才内置 Landlock,而 Rust 侧必须通过 landlock crate 做安全封装;
- 能否用 Rust 所有权语义 把“规则构建 → 规则合并 → 进程自我沙箱化”三步翻译成类型安全的代码;
- 是否理解 “编译期即权限声明” 的 Rust 哲学:规则一旦插入,后续线程即使被攻击也无法扩大权限,这与容器 Seccomp、AppArmor 形成互补。
面试官常追问:“如果规则写错导致业务日志写不进去,线上如何灰度?” 因此答案必须给出 可回滚、可观测 的落地姿势。
知识点
- landlock-rs 三件套:Ruleset、PathBeneath、AccessFile 结构体;
- ABI 版本协商:landlock::ABI::new() 自动降级,保证镜像在 5.10 与 5.15 内核都可启停;
- Rust 所有权转移:Ruleset::add_rule() 会消费 self,强制“一次性构建”模型,避免运行时追加规则带来的 TOCTOU;
- 兼容容器场景:与 prctl(NO_NEW_PRIVS) 配合使用,防止通过 setuid 逃逸;
- 国内镜像源:crates.io 索引走 rsproxy.cn,landlock 0.3+ 已加入“中科大红帽”镜像缓存,CI 无需翻墙。
答案
-
依赖与特征开关
[dependencies] landlock = { version = "0.3", features = ["compat"] }compat 特征 保证旧内核不会编译失败。
-
构建最小可用沙箱(只读 /etc,禁止其余写)
use landlock::{ AccessFile, PathBeneath, Ruleset, RulesetAttr, RulesetCreated, ABI, }; use std::fs::File; use std::os::unix::io::AsRawFd; fn lock_myself() -> Result<(), anyhow::Error> { let abi = ABI::new().unwrap_or(ABI::V1); // 自动协商 let ruleset = Ruleset::new() .handle_access(AccessFile::from_all(abi))? .create()?; // 消费 self,拿到 RulesetCreated let etc = PathBeneath::new("/etc") .allow_access(AccessFile::ReadFile)?; let ruleset = ruleset.add_rule(etc)?; // 继续消费,返回新的 RulesetCreated ruleset.restrict_self()?; // 立即生效,当前线程及其子线程 Ok(()) }关键点:restrict_self() 一旦返回 Ok,当前进程永远无法再打开 /tmp/write.log 进行写操作,除非重启。
-
线上灰度与回滚
- 把
lock_myself()封装成 “沙箱层”,在 tokio Runtime 启动前调用; - 通过 配置中心 下发
landlock.enable开关,若规则过严导致写日志失败,直接重启 Pod 即可回滚,因为规则只对运行中的进程生效; - 利用 prometheus 指标 记录
landlock_restrict_self_result,0 表示成功,1 表示降级,方便 SRE 告警。
- 把
-
与容器生态协同
- 在 Kubernetes 1.29+ 中,可把 Landlock 规则写入 OCI seccomp 注解,但 Rust 侧仍建议 自包含,避免不同容器运行时对 Landlock 支持度不一;
- 与 runc 1.2 的 rootless 容器一起使用时,需先
prctl(NO_NEW_PRIVS),否则restrict_self()返回EPERM。
拓展思考
-
“编译期权限”能否再往前一步?
借助 const fn 与 serde const 解析,把 JSON 规则在编译期转成PathBeneath数组,实现 “镜像构建即沙箱定型”,杜绝运维人员在线改规则带来的合规风险。 -
与 io_uring 共存时的死锁陷阱
io_uring 的 kernel worker 可能在你调用restrict_self()之后代表进程打开新文件,若规则未预声明,会返回EPERM并触发 uring 回退到 sync 接口,性能陡降 30%。解决:在规则里 预允许 /dev/io_uring 的读写权限,并通过AccessFile::Execute禁止任意新二进制执行。 -
国内等保 2.0 场景
等保三级要求“最小权限”,但传统 AppArmor 配置难审计。可把 Landlock 规则导出成 JSON 模板,由 Rust 二进制在启动时打印到 stdout,审计人员直接比对 “代码即策略”,满足 “策略不可变” 条款,且无需宿主机安装额外内核模块。