2010-07-29 136 views
1

我的系统(Linux内核2.6.32-24)正在实现一个名为地址空间布局随机化(ASLR)的功能。 ASLR似乎改变了堆栈大小:可变堆栈大小

void f(int n) 
{ 
    printf(" %d ", n); 
    f(n + 1); 
} 

int main(...) 
{ 
    f(0); 
} 

很明显,如果你执行程序,你会得到一个堆栈溢出。问题是分段错误在每次执行时发生在不同的“n”值上。这很明显是由ASLR引起的(如果你禁用它,程序始终以相同的值“n”退出)。

我有两个问题:

  1. 岂不是ASLR使堆栈大小略有变化?
  2. 如果是这样,您是否看到这个事实存在问题?可能是内核错误?
+1

令人惊讶的是,编译器并没有将该函数优化为简单的无限循环。 – caf 2010-07-29 13:46:51

回答

1

这可能意味着在一个实例中堆栈恰好流入其他分配的块,而在另一个实例中,它会在未分配的地址空间上跳转。

+0

我一开始也这么想过,但我一直在试图看看/ proc//maps文件。堆栈段永远不会接近另一个映射,并且它的大小在它的段错误发生之前比堆栈的rlimit(rlim_cur)大得多(超过一页)。 – jdizzle 2010-07-29 10:35:47

+0

你的意思是说,如果默认堆栈大小为8192k,那么在超过此限制之后,分段故障会发生很多? 您能否发布说明以检查此行为? – agori 2010-07-29 10:44:31

+0

我只是有一个循环捕获/ proc//maps文件,并查看proc崩溃之前打印的最后一件事情。分配给堆栈的内存范围在崩溃时间一直大于rlimit的金额(在开始无限递归之前,我得到/打印rlimit值) – jdizzle 2010-07-29 11:47:05

1

ASLR代表“地址空间布局随机化”。它所做的是在每次运行时更改不同的段/段起始地址,是的,这包括堆栈。

这不是一个bug;这是设计。它的目的部分是让溢出缓冲区难以获得访问权限,因为为了执行任意代码,您需要诱使CPU“返回”到堆栈中某个点或运行时库中。合法的代码会知道要返回的位置,但是某些罐头式利用不会 - 每次都可能是不同的地址。至于为什么表观堆栈大小发生变化,堆栈空间是以页面分配的,而不是以字节分配的。调整堆栈指针,特别是如果它不是页面大小的倍数,则会改变您看到的可用空间量。

+0

您确定ASLR可以更改段/段大小吗?你有这方面的参考吗? – agori 2010-07-29 09:58:14

+0

除了这是它的整个生活目的(因此名称),请参阅http://en.wikipedia.org/wiki/Address_space_layout_randomization或http://netsecurity.about.com/od/quicktips/qt/whatisaslr.htm一些更多的信息。 – cHao 2010-07-29 10:02:56

+0

ASLR肯定会更改地址,但我看不到任何有关更改堆栈大小的文档。 – agori 2010-07-29 10:05:47