mprotect整个程序,运行危险代码

Hep*_*tic 5 c linux posix sandbox mprotect

我有一个小程序,可以映射具有潜在危险的可执行代码(使用PROT_EXEC),prctl(PR_SET_SECCOMP, 1)然后调用并执行此mmap编码。这一切都很好,并允许我通过将mmap'd区域同步到磁盘来“保存”评估状态,然后稍后将其重新加载(很可能在另一台计算机上进行负载平衡)。但是,这种技术并不总是有效的-因为此代码可能已对不在mmap'd区域中的程序进行了更改,因此这些信息将丢失。

因此,我想做的是在调用代码之前使所有内容(除了此mmap'd区域之外)绝对都是只读的。这样,我保证可执行代码除了可以随意进行序列化/反序列化的mmap'd区域之外,不会更改任何状态。

顺便说一句,这是x86_64上的Linux

谢谢

Mat*_*ner 4

首先,观察一下:没有任何内容表明您必须mmap()将机器指令放入内存或将它们保存回文件中。read()write()可以这样做,只是请注意,您应该为此目的创建一个可写且可执行的私有映射。

显然,如果要在同一进程中执行,则无法可靠地禁用对将调用要加载的可执行代码的堆栈区域的写入,因为这将使堆栈无法使用。您可以通过注释变量或使用程序集来解决此问题。

您的下一个选择是fork()。您可以exec将子项放入一个特殊的包装可执行文件中,该可执行文件允许恶意可执行代码造成的损坏和内省最小化(提供简单的加载/转储),或者您可以通过让子项修改自身以达到相同的效果来执行相同的操作。这仍然不是 100% 安全。

提案0

  • 创建一个与最小库 ( ) 链接的独立二进制文件-nodefaultlibs
  • fork在子级中的,之后ptrace(PTRACE_TRACEME)(以便您可以可靠地读取内存内容并进行其他干预),并关闭除管道之外的所有句柄(只是为了stdin简单起见)。exec()进入前面提到的包装二进制文件。

在包装二进制文件中:

  • mmap位于已知位置的具有写入和执行权限的私有区域。或者,如果大小固定,您可以静态分配该区域。
  • 将管道的内容读入该区域。
  • 关闭管道。现在该进程没有打开的句柄。
  • prctl(PR_SET_SECCOMP, 1)。现在唯一有效的系统调用是_exitsigreturn。既然这个过程不能raisesigreturn应该没有任何有用的效果。
  • 从主堆栈(应该是唯一的堆栈)中删除写入权限。由于您无意返回,并且会立即跳转,因此您不需要再次触摸堆栈。
  • 跳转到区域内的起始位置。使用程序集执行此操作,或创建一个函数指针并调用它(如果您可以使其在不压入堆栈的情况下工作)。现在您应该执行一个唯一可用的可写区域的内存区域。主堆栈受到保护,并且由于缺乏库支持而不应使用堆。

在父级中:

  • 使用ptracewait捕获错误或成功完成。
  • /proc/<pid>/mem通过文件或等效文件读取已知位置处的映射区域。