我有一个小程序,可以编写具有潜在危险的可执行代码(使用PROT_EXEC),调用prctl(PR_SET_SECCOMP, 1)
然后执行此mmap代码。这一切都很好,并允许我通过将mmap'd区域同步到磁盘来“保存”评估状态,并在以后重新加载它(最有可能在另一台机器上进行负载平衡)。但是,这种技术并不总是有效 - 因为此代码可能已对不在mmap'd区域中的程序进行了更改,并且此信息将丢失。
所以我想做的是,在调用代码之前,将所有内容(除了这个mmap'd区域之外)设置为只读。这样我就可以保证可执行代码不能改变mmap'd区域以外的任何其他状态,我可以随意序列化/反序列化。
BTW这是Linux on x86_64
由于
答案 0 :(得分:4)
首先,观察:没有任何内容表明您必须mmap()
将机器指令放入内存或将其保存回文件。 read()
和write()
也可以这样做,只需注意您应该为此目的制作可写和可执行的私有映射。
显然,你不能可靠地禁止写入将要调用你将加载的可执行代码的堆栈区域,如果它要在同一进程中执行,因为这将使堆栈无法使用。您可以通过注释变量或使用汇编来解决此问题。
您的下一个选项是fork()
。您可以将子进程exec
转换为特殊的包装器可执行文件,允许对恶意可执行代码进行最小程度的损坏和内省(仅提供加载/转储),或者您可以通过让子进程将其自身修改为相同的效果来执行相同的操作。这仍然不是100%安全。
-nodefaultlibs
)链接。fork
,ptrace(PTRACE_TRACEME)
后(以便您可以可靠地读取内存内容并进行其他干预),并关闭除管道之外的所有句柄(仅在{{1}中)为简单起见)。 stdin
进入前面提到的包装二进制文件。在包装器二进制文件中:
exec()
具有写入和执行权限的已知位置的私有区域。或者,如果大小固定,您可以静态分配此区域。mmap
。现在唯一有效的系统调用是prctl(PR_SET_SECCOMP, 1)
和_exit
。由于该流程无法sigreturn
,raise
应该没有任何有用的效果。在父母:
sigreturn
或ptrace
,抓住错误或成功完成。wait
或等效于文件的位置读取已知位置的映射区域。