我有一个小程序,它可能带有潜在危险的可执行代码(使用prctl(PR_SET_SECCOMP, 1)
),调用prctl(PR_SET_SECCOMP, 1)
,然后执行这个mmap代码。 这一切都很好,并允许我通过将mmap'd区域同步到磁盘来“保存”评估状态,并稍后重新加载(最有可能在另一台机器上进行负载平衡)。 但是,这种技术并不总是有效的,因为这个代码可能会改变不在mmap的区域中的程序,这些信息将会丢失。
所以我想要做的是,在调用代码之前,绝对只做(除了这个mmap的区域)。 这样我就可以保证可执行代码不能改变任何可以随意序列化/反序列化的mmap'd区域以外的状态。
顺便说一句,这是x86_64上的Linux
谢谢
首先,一个观察:没有什么说你必须mmap()
获取机器指令到内存或将其保存回文件。 read()
和write()
也可以这样做,只要注意你应该为此写一个可写和可执行的私有映射。
显然,如果要在同一个进程中执行,则不能可靠地禁止写入将要调用的可执行代码的堆栈区域,因为这会导致堆栈不可用。 你可以通过注释你的变量或使用程序集来解决这个问题。
你的下一个选择是fork()
。 你可以在孩子身上执行一个特殊的包装可执行文件,允许通过恶意的可执行代码(提供简单的加载/转储)来最小的破坏和反省,或者你也可以通过让孩子修改自己来达到同样的效果。 这仍然不是100%安全。
-nodefaultlibs
)。 fork
, ptrace(PTRACE_TRACEME)
放在子ptrace(PTRACE_TRACEME)
中(这样可以可靠地读取内存内容并执行其他干预),并关闭除管道之外的所有句柄(为了简单起见,只是在stdin
中)。 exec()
到上述的包装二进制文件中。 在包装二进制文件中:
mmap
私有区域。 或者,如果大小是固定的,你可以静态分配这个区域。 prctl(PR_SET_SECCOMP, 1)
。 现在唯一有效的系统调用是_exit
和sigreturn
。 由于这个过程不能raise
, sigreturn
应该没有什么用处。 在父母:
ptrace
或wait
,错误或成功完成。 /proc/<pid>/mem
或等同于文件的方式读取已知位置的映射区域。