mprotect整个程序,运行危险的代码
作者:互联网
我有一个小程序,可以编写具有潜在危险的可执行代码(使用PROT_EXEC),调用prctl(PR_SET_SECCOMP,1),然后执行这个mmap代码.这一切都很好,并允许我通过将mmap’d区域同步到磁盘来“保存”评估状态,并在以后重新加载它(最有可能在另一台机器上进行负载平衡).但是,此技术并不总是有效 – 因为此代码可能已对不在mmap’d区域中的程序进行了更改,并且此信息将丢失.
所以我想做的是,在调用代码之前,将所有内容(除了这个mmap’d区域之外)设置为只读.这样我就可以保证可执行代码不能改变mmap’d区域以外的任何其他状态,我可以随意序列化/反序列化.
顺便说一句,这是x86_64上的Linux
谢谢
解决方法:
首先,观察:没有任何东西表明你必须使用mmap()将机器指令送入内存或将它们保存回文件. read()和write()也可以这样做,只需注意你应该为此目的制作一个可写和可执行的私有映射.
显然,你不能可靠地禁止写入将要调用你将加载的可执行代码的堆栈区域,如果它要在同一进程中执行,因为这将使堆栈无法使用.您可以通过注释变量或使用程序集来解决此问题.
你的下一个选择是fork().你可以在子进程中执行一个特殊的包装器可执行文件,它允许最小的损坏和恶意可执行代码的内省(提供简单的加载/转储),或者你也可以通过让孩子修改自己到同样的效果来做同样的事情.这仍然不是100%安全.
Proposal0
>创建一个独立的二进制文件,链接到最小的库(-nodefaultlibs).
>在子句中使用ptrace(PTRACE_TRACEME)之后(以便您可以可靠地读取内存内容并执行其他干预),并关闭除管道之外的所有句柄(为简单起见,仅在stdin中). exec()进入前面提到的包装二进制文件.
在包装器二进制文件中:
>使用写入和执行权限在已知位置mmap一个私有区域.或者,如果大小固定,您可以静态分配此区域.
>将管道内容读入该区域.
>关闭管道.现在该进程没有打开句柄.
> prctl(PR_SET_SECCOMP,1).现在唯一有效的系统调用是_exit和sigreturn.由于这个过程不能提高,sigreturn应该没有任何有用的效果.
>从主堆栈中删除写入权限(应该是唯一的堆栈).由于您无意返回,并且会在之后立即跳转,因此您不需要再次触摸堆栈.
>跳转到区域内的起始位置.使用程序集执行此操作,或创建一个函数指针并调用它(如果您可以在不推送到堆栈的情况下使其工作).现在您应该执行一个可用的唯一可写区域的内存区域.主堆栈受到保护,由于缺少库支持,堆不应该使用.
在父母:
>使用ptrace或wait,捕获错误或成功完成.
>通过/ proc /< pid> / mem或等效于文件读取已知位置的映射区域.
标签:posix,c-3,linux,sandbox,mprotect 来源: https://codeday.me/bug/20190626/1293399.html