【发布时间】:2016-08-24 04:11:38
【问题描述】:
我正在通过 seccomp 模式为自定义字节码解释器实现 Linux 安全沙箱。为了尽可能减少攻击面,我想在一个完全干净的虚拟地址空间中运行它。我只需要代码和数据段以及可用的堆栈,但我不需要 vsyscall、vdso 或 vvar。
有什么方法可以禁止给给定进程分配此页面?
【问题讨论】:
我正在通过 seccomp 模式为自定义字节码解释器实现 Linux 安全沙箱。为了尽可能减少攻击面,我想在一个完全干净的虚拟地址空间中运行它。我只需要代码和数据段以及可用的堆栈,但我不需要 vsyscall、vdso 或 vvar。
有什么方法可以禁止给给定进程分配此页面?
【问题讨论】:
基本上,不,如果您希望映射本身不可用,则必须全局禁用 vsyscall/vDSO。如果您只希望程序无法调用 vsyscall/vDSO 系统调用,那么 seccomp 将能够做到。不过有一些注意事项:
见https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt
在 x86-64 上,默认启用 vsyscall 仿真。 (vsyscalls 是 vDSO 调用的旧变体。)目前,模拟的 vsyscall 将支持 seccomp,但有一些奇怪之处:
SECCOMP_RET_TRAP 的返回值将设置一个 si_call_addr 指向 给定调用的 vsyscall 条目,而不是之后的地址 “系统调用”指令。任何想要重新开始通话的代码 应该知道 (a) 一个 ret 指令已被模拟并且 (b) 尝试恢复系统调用将再次触发标准 vsyscall 仿真安全检查,主要是恢复系统调用 毫无意义。
SECCOMP_RET_TRACE 的返回值将像往常一样向跟踪器发出信号, 但系统调用可能不会使用 orig_rax 寄存器。它只能更改为 -1 顺序以跳过 当前模拟呼叫。任何其他更改都可能终止该过程。 跟踪器看到的 rip 值将是系统调用入口地址; 这与正常行为不同。跟踪器不得修改 rip或rsp。 (不要依赖终止进程的其他更改。 他们可能会工作。例如,在某些内核上,选择系统调用 仅存在于未来内核中的将被正确模拟(通过 返回 -ENOSYS)。
要检测这种古怪的行为,请检查 addr & ~0x0C00 == 0xFFFFFFFFFF600000。 (对于 SECCOMP_RET_TRACE,使用 rip。对于 SECCOMP_RET_TRAP,使用 siginfo->si_call_addr。)不要检查任何其他 条件:未来的内核可能会改进 vsyscall 仿真和当前 vsyscall=native 模式下的内核会表现不同,但 0xF...F600{0,4,8,C}00 处的指令将不是这些系统调用 案例。
请注意,现代系统根本不可能使用 vsyscall——它们 是一个遗留功能,它们比标准慢得多 系统调用。新代码将使用 vDSO 和 vDSO 发出的系统调用 与正常的系统调用没有区别。
所以模拟的 vsyscall 可以被 seccomp 限制,而 vDSO 也同样被 seccomp 限制。如果禁用gettimeofday(),受限程序将无法通过模拟的 vsyscall、vDSO 或常规系统调用调用该系统调用。如果您使用 seccomp 以这种方式限制它们,则不必担心它们创建的攻击面。
如果您担心攻击者会利用 vDSO 映射本身(这不需要调用系统调用),那么我认为没有办法在每个进程的基础上可靠地禁用它。您可以阻止它被链接,但很难阻止受损的字节码解释器分配内存并将其放回原处。您可以使用vdso=0 内核参数启动,这将在全局范围内禁用它,因此链接它不会有任何作用。
【讨论】: