要防止不受信任的代码通过堆栈溢出来窃取对我的应用程序的控制权?

时间:2018-11-21 07:49:37

标签: stack-overflow sandbox jit

我正在考虑编写一个JIT库,该库将在Windows,Mac和Linux上编译和执行不受信任的代码。不受信任的代码所用的语言是“安全的”,在某种意义上是:对数组进行绑定检查,不可能有指向不可访问的内存的指针,也没有办法进行系统调用。此外,不可信代码的每个函数使用的堆栈空间在编译期间是固定的(即,没有alloca()或C样式的可变长度数组)。

但是,这种语言可以进行递归函数调用,这意味着可能会发生堆栈溢出。

通常,堆栈溢出将导致分段错误,因为操作系统将在堆栈末尾添加一个无法访问的保护页(至少,我关心的所有三个操作系统都将执行此操作)。假设我不处理SIGSEGV或尝试捕获分段错误,这将导致崩溃,并降低我的JIT运行时以及应用程序的其余部分。很好-不受信任的代码无法控制应用程序或从中访问数据。

但是显然,如果函数分配了大量的堆栈内存(例如,通过在堆栈上声明一个大数组),则有可能“跳过”保护页面。因此,可以使精心设计的代码溢出堆栈而不会引起分段错误。这意味着可以设计不受信任的代码来分配足够的堆栈内存,以便我的JIT库将其编译为跳转保护页面的机器代码。这样的恶意代码将能够做坏事,例如:覆盖应用程序其余部分的数据,以便当JITted代码返回到应用程序时,应用程序将读取修改后的数据,并执行原本不希望的操作。做。这意味着恶意代码已有效地获得了对整个应用程序的控制(并且将能够执行应用程序许可的任何操作)。

检测堆栈溢出(使整个程序崩溃或将控制权交还给JIT运行时以便我处理)的正确方法是什么?

我可以想到两种可能的方式:

  • 从OS中查询剩余的堆栈空间,并在每个功能的序言中进行检查。如果没有足够的堆栈空间,可以调用abort()。可以像this answer这样在Linux上查询它,其他操作系统也有一种方法。
  • 在每个函数的序言中探究所需的堆栈空间。如果没有足够的堆栈空间,这将访问保护页面。 WAVM就是这种情况。

0 个答案:

没有答案