我正在通过seccomp模式为自定义字节码解释器实现一个linux安全沙盒。为了尽可能减少攻击面,我想在一个完全干净的虚拟地址空间中运行它。我只需要代码和数据段加上可用的堆栈,但我不需要vsyscall、vdso或vvar。
是否有任何方法可以为给定进程禁用此页的分配?
最佳答案
基本上,不需要,如果希望映射本身不可用,则必须全局禁用vsyscall/vdso。如果您只希望程序无法调用vsyscall/vdso syscalls,那么seccomp将能够执行此操作。但也有一些注意事项:
见https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt
在x86-64上,默认情况下启用vsyscall仿真。(vsyscalls是
vdso调用上的传统变体。)目前,模拟的vsyscalls将向seccomp致敬,但有一些奇怪之处:
seccomp_ret_trap的返回值将设置一个指向
给定调用的vsyscall条目,而不是
“syscall”指令。任何希望重新启动调用的代码
应注意(a)已模拟RET指令,以及(b)
尝试恢复系统调用将再次触发标准vsyscall
模拟安全检查,主要是恢复系统调用
毫无意义。
seccomp_ret_trace的返回值将一如既往地向跟踪器发送信号,
但不能使用
原始寄存器。只能将其更改为-1顺序以跳过
当前模拟的调用。任何其他更改都可能终止进程。
跟踪器看到的RIP值将是系统调用条目地址;
这与正常行为不同。跟踪器不能修改
RIP或RSP。(不要依赖于终止进程的其他更改。
它们可能有用。例如,在某些内核上,选择系统调用
只存在于未来内核中的将被正确仿真(通过
返回-埃诺斯)。
要检测这种奇怪的行为,请检查addr&~0x0c00==
0xffffffffff600000。(对于seccomp_ret_trace,使用rip。为了
seccomp_ret_trap,使用siginfo->si_call_addr.)不要检查任何其他
条件:未来的内核可能会改进vsyscall仿真和当前的
vsyscall=native模式下的内核将有不同的行为,但是
在0xf…f600{0,4,8,c}00处的指令在这些
案例。
注意,现代系统根本不可能使用vsyscalls——它们
是一个遗留的特性,它们比标准的要慢得多
系统调用。新代码将使用vdso,并且vdso发出系统调用
无法与正常系统调用区分。
因此,模拟的vsyscall可以被seccomp限制,而vdso也同样被seccomp限制。如果禁用gettimeofday()
,受限程序将无法通过模拟vsyscall、vdso或常规syscall调用该syscall。如果你用seccomp把它们限制在这个范围内,你就不必担心它们造成的攻击面。
如果您担心攻击者利用vdso映射本身(这不需要调用syscall),那么我认为没有一种方法可以可靠地在每个进程上禁用它。您可以防止它被链接进来,但是很难防止受到损害的字节码解释器分配内存并将其放回去。不过,您可以使用vdso=0
内核参数启动,该参数将全局禁用它,因此将其链接到中不会有任何作用。
关于linux - 禁用Linux vsyscall vdso vvar,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39114292/