【问题标题】:SECCOMP: How to emulate malloc, realloc and free?SECCOMP:如何模拟 malloc、realloc 和 free?
【发布时间】:2012-07-13 17:50:36
【问题描述】:

我想在我的服务器上执行任意(潜在危险)二进制文件。因此,我使用objcopy 将“main”符号重命名为“other_main”,以便我可以链接到我自己的小主函数,该函数为RLIMIT_CPU 设置适当的值并在调用other_main 之前切换SECCOMP 标志。到目前为止,我对这个解决方案非常满意。

现在的问题是,第 3 方程序代码可能包含一些对 malloc 的调用,这些调用可能会立即终止程序(不允许使用 sbrk)。因此,我想在设置 SECCOMP 之前预先分配一些合理大小的数组(例如 20MB),这些数组应该由 malloc / realloc / calloc / free 使用。不幸的是,我不知道如何归档最后一步。我必须自己实现所有这 4 个功能吗?如何将自己的函数注入到 stdlib(例如,当 printf 在内部调用 malloc 时会发生什么?)。

【问题讨论】:

  • 重命名符号真的有效吗?我真的很想知道操作系统如何处理剥离的二进制文件。
  • 重命名符号在这里可以正常工作。 objcopy 似乎真的很强大。显然不允许您剥离二进制文件,但这对我来说不是问题,因为我自己编译二进制文件。只是C代码不可信。
  • 您能否为您的用户提供与您的操作系统库不同的 C 库(例如 Newlib)?如果是这样,编写自己的sbrk(无法脱离沙箱)将非常容易,然后 malloc/realloc/calloc/free 和朋友都可以工作。
  • 对不起。我想念您重新链接并创建新程序。
  • 请注意,仅仅重命名main 可能不够——二进制文件可能包含在main 之前运行的初始化程序。

标签: c linux gcc malloc seccomp


【解决方案1】:

对于 malloc 和 free,您的程序只需要定义自己的版本。我见过的大多数 libc 实现(包括 glibc、klibc 和 Dietlibc)都会很乐意使用您的内存分配器例程。因此,在进入 seccomp 模式之前,使用 mmap 或 sbrk 分配一大块内存,然后从该块中分配 malloc/free。 memmgr 是一个简单的堆分配器,可以轻松适应固定缓冲区的分配。

seccomp 的真正问题是它允许的一组系统调用(读取、写入、退出和 sigreturn)根本不足以运行与或多或少的 any libc 链接的程序.例如:

  • 在 glibc 中,exit 和 _exit 调用 exit_group
  • 在glibc中,printf可以调用mmap
  • 在dietlibc中,scanf可以调用ioctl
  • 等等等等

通常有充分的理由说明为什么需要这些调用。例如,dietlibc 使用 ioctl 在从标准输入读取输入时检查标准输入是否为 tty,以便刷新标准输出。如果输出是行缓冲的,这是确保在读取交互式输入之前提示可见的标准行为。

所以,我得出结论,原来的seccomp模式或多或少没用。然而,模式 2(又名“过滤模式”)更有用,因为它允许您将特定的系统调用列入白名单。我的 github 页面上有一个proof of concept,它以 seccomp 模式 2 运行程序,但允许它们使用 printf 和 scanf,以及使用 malloc/free 分配内存。

【讨论】:

    【解决方案2】:

    seccompsandbox:

    • 在一个线程中启用 seccomp,该线程执行 RPC(通过 read/write 在预分配的 socketpair 上)到同一进程中的另一个(非 seccomp)线程,该线程能够执行特权操作,例如如mmap
    • 修补函数,例如 malloc(在内存中,在运行时)以重定向到它们的 seccomp-safe 包装器

    Chromium's seccomp Sandbox 提供了有关其工作原理的更多详细信息。

    【讨论】:

      【解决方案3】:

      并非所有 malloc 实现都基于 sbrk(),例如 GNU mmalloc。如果需要自定义实现,This doc 也可能很有用。

      +两个简单的malloc实现here

      【讨论】:

      • 唯一允许的系统调用是 read、write、sigreturn 和 exit。所以我也不能使用 mmap,除非我在程序开始时预先分配了足够的内存(一个合理大小的静态数组似乎适合我的用例)。然而,该链接看起来很有用,假设我真的必须实现自己的 malloc。但是我仍然不知道如何替换 stdlib 中 printf 和其他地方使用的内部 malloc 调用。
      • 我已经更正了答案:dlmalloc 实际上确实使用了 sbrk()。然而,在那里我发现了基于 mmap() 的 GNU mmaloc。在您的情况下,您可能会考虑在其基础上使用静态池 [] 代替堆 + 简单处理功能。例如,您也可以在静态数组中保留 N 个引用。那当然是伪动态内存。
      猜你喜欢
      • 1970-01-01
      • 2012-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-19
      • 2012-06-10
      相关资源
      最近更新 更多