为啥堆栈段可以在 Raspberry Pi 上执行?
Posted
技术标签:
【中文标题】为啥堆栈段可以在 Raspberry Pi 上执行?【英文标题】:Why is the stack segment executable on Raspberry Pi?为什么堆栈段可以在 Raspberry Pi 上执行? 【发布时间】:2017-07-22 10:58:58 【问题描述】:我有一个带有 Raspbian GNU/Linux 8 (Jessie) 操作系统的 Raspberry Pi 3。
我写了这个简单的程序。我用gcc -o hello hello.c
编译它。
#include <stdio.h>
void main()
printf("hello!\n");
从 readelf 输出看来一切正常:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
EXIDX 0x0004cc 0x000104cc 0x000104cc 0x00008 0x00008 R 0x4
PHDR 0x000034 0x00010034 0x00010034 0x00120 0x00120 R E 0x4
INTERP 0x000154 0x00010154 0x00010154 0x00019 0x00019 R 0x1
[Requesting program interpreter: /lib/ld-linux-armhf.so.3]
LOAD 0x000000 0x00010000 0x00010000 0x004d8 0x004d8 R E 0x10000
LOAD 0x000f0c 0x00020f0c 0x00020f0c 0x0011c 0x00120 RW 0x10000
DYNAMIC 0x000f18 0x00020f18 0x00020f18 0x000e8 0x000e8 RW 0x4
NOTE 0x000170 0x00010170 0x00010170 0x00044 0x00044 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
GNU_RELRO 0x000f0c 0x00020f0c 0x00020f0c 0x000f4 0x000f4 R 0x1
但是当我运行程序时,堆栈是可执行的:
0x7efdf000 0x7f000000 0x00000000 rwx [stack]
我也尝试使用选项-z noexecstack
进行编译,但没有任何改变。
我也尝试下载具有此代码的libarmmem.so
版本:
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
但没有任何改变。
为什么堆栈段可以在 Raspberry Pi 上执行?
编辑我添加了 LD_DEBUG=files ./hello 命令的输出
23110:
23110: file=/usr/lib/arm-linux-gnueabihf/libarmmem.so [0]; needed by ./hello [0]
23110: file=/usr/lib/arm-linux-gnueabihf/libarmmem.so [0]; generating link map
23110: dynamic: 0x76f273fc base: 0x76f13000 size: 0x00014524
23110: entry: 0x76f13568 phdr: 0x76f13034 phnum: 6
23110:
23110:
23110: file=libc.so.6 [0]; needed by ./hello [0]
23110: file=libc.so.6 [0]; generating link map
23110: dynamic: 0x76f0ef20 base: 0x76dd4000 size: 0x0013e550
23110: entry: 0x76dea840 phdr: 0x76dd4034 phnum: 10
23110:
23110:
23110: calling init: /lib/arm-linux-gnueabihf/libc.so.6
23110:
23110:
23110: calling init: /usr/lib/arm-linux-gnueabihf/libarmmem.so
23110:
23110:
23110: initialize program: ./hello
23110:
23110:
23110: transferring control: ./hello
23110:
hello!
23110:
23110: calling fini: ./hello [0]
23110:
23110:
23110: calling fini: /usr/lib/arm-linux-gnueabihf/libarmmem.so [0]
23110:
添加更多信息: 我编辑文件 architecture.S,在我收到 make 之后:
gcc -std=gnu99 -O2 -c -o trampoline.o trampoline.c
gcc -shared -o libarmmem.so architecture.o memcmp.o memcpymove.o memcpymove-a7.o memset.o trampoline.o
`architecture' referenced in section `.text' of trampoline.o: defined in discarded section `.note.GNU-stack' of architecture.o
`architecture' referenced in section `.text' of trampoline.o: defined in discarded section `.note.GNU-stack' of architecture.o
`architecture' referenced in section `.text' of trampoline.o: defined in discarded section `.note.GNU-stack' of architecture.o
`architecture' referenced in section `.text' of trampoline.o: defined in discarded section `.note.GNU-stack' of architecture.o
collect2: error: ld returned 1 exit status
Makefile:13: recipe for target 'libarmmem.so' failed
make: *** [libarmmem.so] Error 1
【问题讨论】:
请原谅我的无知...你是如何得到这个结果的:0x7efdf000 0x7f000000 0x00000000 rwx [stack]
。那是trace
的一部分吗?
@jww 不只是 /proc/pidof hello
/maps
请以LD_DEBUG=files ./hello
运行程序并将输出添加到您的帖子中。有报道称LD_PRELOAD
库会导致此问题。
@FlorianWeimer 也看看这个`$cat /etc/ld.so.preload /usr/lib/arm-linux-gnueabihf/libarmmem.so`
【参考方案1】:
这很可能是/usr/lib/arm-linux-gnueabihf/libarmmem.so
造成的。我找到了这个源文件:
它缺少不可执行的堆栈注解,因此 glibc 在预加载 DSO 时保守地使堆栈可执行。其他源文件有这样的:
/* Prevent the stack from becoming executable */
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
因此,您只需将其复制到architecture.S
(在文件末尾)并重新构建。
您可以通过eu-readelf -l /usr/lib/arm-linux-gnueabihf/libarmmem.so
验证此 DSO 是否确实是罪魁祸首。它应该根本不显示GNU_STACK
程序头,或者在倒数第二列中标记为RWE
的GNU_STACK
程序头。
【讨论】:
@Livio,抱歉,看起来有点乱码。评论框不是发布编译器输出消息的好地方。请修改帖子,说明您做了什么以及结果如何。 哦,抱歉,我错过了architecture.S
在开头附近没有节指令。您需要将我发布的片段放在文件末尾,或者如果您将其留在开头,请在其后添加.data
指令。
添加ASFLAGS += -Wa,--noexecstack
应该不够吧。编译器驱动程序将做正确的事情并使用正确的标志调用汇编程序。
哦等等...trampoline.c
会导致 GCC 编译器下的 NX 堆栈丢失(如果它是真正的蹦床的话)。 libarmmem.so
可能无法拥有它们。
@jww,我不这么认为。这些不是堆叠蹦床。以上是关于为啥堆栈段可以在 Raspberry Pi 上执行?的主要内容,如果未能解决你的问题,请参考以下文章
树莓派(Raspberry Pi)4B无界面安装 Raspberry Pi 系统篇
创建一个bat文件以在Windows上运行raspberry pi命令
从 Apache Laravel PHP 控制器在 Raspberry PI 上执行 python 脚本