为了实现mainstream机器的硬件栈保护(比如amd64平台上的 NX bit),开发者需要在软件包上做正确的栈设置,所有的平台都有栈保护的课题,它的目的是在软件包故障时进行修复,我们重点关注 GNU_STACK ELF 的标志。ELF 是 executable and linking format 的缩写,意思是可执行的连接格式,ELF是一种所有Linux发行版普遍使用的文件格式,一个ELF可以是一个可执行文件或者库文件,而 GNU_STACK 是一个程序头,告诉系统当ELF被载入内存的时候如何来控制栈。GNU栈分为可执行栈与不可执行栈。以可执行栈标识为结尾的ELF文件分下面三种情形:
1. 由GCC生成的使用可执行栈的代码。
2. 由汇编源码生成的目标文件包含了一个向连接器指明需要可执行栈的标识(即为了设置为可执行栈的GNU_STACK记号)。
3. 由汇编源码生成的目标文件没有GNU_STACK记号,这对于某些将在多种平台上使用的代码来说经常会发生这种情况。
由GCC生成栈上执行代码的情况发生在要实现一个trampoline嵌套函数的时候,如果想除去可执行栈的要求则需要重写代码,有的时候这种重写比较容易,有的时候不容易。
如果一个汇编源码包含了一个GNU_STACK记号指明了要可执行栈,这是设计者有意所为,同样,想取消这种要求也需重写代码。
如果一个汇编源码没有包含GNU_STACK记号,系统会默认地认为需要可执行栈,然而,如果无GNU_STACK记号,通常是作者没有添加,而不是代码本身对可执行栈的实际需要。
前两种情况,带有可执行栈的标识是对的,想移除它只能重写代码,然而,如果上游作者没有指明汇编源码的目标文件是否需要可执行栈,那么如果修补它就意味着在源码里添加GNU_STACK记号指明不需要可执行栈。
寻找需要可执行栈的ELF文件,先下载一个PaX工具包:
$ emerge pax-utils
用里面的scanelf对文件进行扫描,看看哪些文件需要可执行栈:
$ scanelf -lpqe
看看哪些文件缺失了GNU_STACK记号:
$ scanelf -qeR .
用binutils里面的readelf可以查看文件的ELF标识:
$ readelf -S plaympeg.o
可以看到有的文件里有 .note.GNU-stack标识,有的没有。
一般情况下,用gcc编译源码,gcc会关照GNU_STACK记号,除非需要,否则最后的目标文件不会带有可执行栈标识,但如果你编译的是汇编源码,那么gcc无法自动添加GNU_STACK记号,所以,属于可执行栈的ELF二进制文件的源码以包含着原始汇编代码的软件包最为常见,注意,这里不是说内联汇编源码,而是以大写的.S为后缀的纯汇编源码。我们可以对每个用汇编写成的文件打上补丁并把这些修改传到上游,或者懒做,强迫软件包编译系统用 GNU as 的 --noexecstack 选项对源码文件进行汇编(此方法不推荐)。
阅读(3024) | 评论(0) | 转发(0) |