使用GNU ld及仅含.text段的链接脚本生成的最小静态ELF可执行文件为何被Linux加载器拒绝?
为什么Linux加载器拒绝运行这个精简ELF可执行文件?
我来帮你拆解这个问题——你遇到的EPERM错误,根源在于你的ELF文件把核心LOAD段映射到了虚拟地址0x0,而Linux内核出于安全防护的考虑,直接拒绝加载这样的可执行文件。
先看看你得到的错误输出:
$ strace ./experiment execve("./experiment", ["./experiment"], 0x7ffee000bd20 /* 69 vars */) = -1 EPERM (Operation not permitted)
再看readelf输出里的程序头,重点看LOAD段的信息:
$ readelf -hl ./experiment ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x120 Start of program headers: 64 (bytes into file) Start of section headers: 512 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 4 Size of section headers: 64 (bytes) Number of section headers: 6 Section header string table index: 5 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000190 0x0000000000000190 R E 0x1000 NOTE 0x0000000000000160 0x0000000000000160 0x0000000000000160 0x0000000000000030 0x0000000000000030 R 0x8 GNU_PROPERTY 0x0000000000000160 0x0000000000000160 0x0000000000000030 R 0x8 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10 Section to Segment mapping: Segment Sections... 00 .text .note.gnu.property 01 .note.gnu.property 02 .note.gnu.property 03
核心问题分析
你的链接脚本里写了这一行:
. = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
这强制把程序的text段(以及包含它的LOAD段)的虚拟起始地址设为0x0。但Linux内核有个安全机制:通过vm.mmap_min_addr这个sysctl参数限制用户空间程序能映射的最低虚拟地址(默认通常是0x10000,也就是65536)。这么做是为了防止NULL指针解引用意外访问到有效内存,避免潜在的安全漏洞。你的LOAD段起始地址0x0远低于这个最小值,所以内核在execve时直接拒绝加载,返回EPERM。
解决方法
修改链接脚本,把text-segment的起始地址改成x86_64 Linux默认的用户空间起始地址0x400000即可:
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") OUTPUT_ARCH(i386:x86-64) ENTRY(_start) SECTIONS { . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; .text : { *(.text) } }
重新执行编译链接步骤,生成的可执行文件就能被正常加载运行了。
补充说明
虽然ELF标准本身并没有禁止LOAD段使用0x0地址,但Linux的安全策略会阻止这种映射。另外,你程序里的其他段(NOTE、GNU_PROPERTY)本身没有问题,只是LOAD段的地址违反了内核的规则。
可复现的代码与步骤
汇编代码(experiment.S)
#include <sys/syscall.h> .text .global _start .type _start, @function _start: mov %rsp, %rdi and $(~4095), %rdi mov $4096, %rsi mov $SYS_munmap, %rax syscall test %rax, %rax jne .Lfail .Lloop: mov $SYS_pause, %rax syscall jmp .Lloop .Lfail: mov %rax, %rdi neg %rdi mov $SYS_exit, %rax syscall .size _start, .-_start .section .note.GNU-stack,"",@progbits
链接脚本(experiment.ld)
(修改前的版本,也就是导致问题的版本)
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") OUTPUT_ARCH(i386:x86-64) ENTRY(_start) SECTIONS { . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS; .text : { *(.text) } }
编译链接命令
cc -P -E experiment.S | as -o experiment.o - ld -o experiment -static -e _start -T experiment.ld experiment.o
Base64编码的问题程序
f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAIAEAAAAAAABAAAAAAAAAAAACAAAAAAAAAAAAAEAAOAAE AEAABgAFAAEAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAEAAAAAAACQAQAAAAAAAAAQ AAAAAAAAABAAAAAQAAABgAQAAAAAAAGABAAAAAAAAYAEAAAAAAAAwAAAAAAAAADAAAAAAAAAACAAA AAAAAABT5XRkBAAAAGABAAAAAAAAYAEAAAAAAABgAQAAAAAAADAAAAAAAAAAMAAAAAAAAAAIAAAA AAAAAFHldGQGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA AAAAASInnSIHnAPD//0jHxgAQAABIx8ALAAAADwVIhcB1C0jHwCIAAAAPBev1SInHSPffSMfAPAAA AA8FAAAAAAAAAAQAAAAgAAAABQAAAEdOVQABAAHABAAAAAEAAAAAAAAAAgABwAQAAAABAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAASAAEAIAEAAAAAAAA5AAAAAAAAAABfc3RhcnQA AC5zeW10YWIALnN0cnRhYgAuc2hzdHJ0YWIALnRleHQALm5vdGUuZ251LnByb3BlcnR5AAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAGwAAAAEAAAAGAAAAAAAAACABAAAAAAAAIAEAAAAAAAA5AAAAAAAAAAAAAAAAAAAAAQAA AAAAAAAAAAAAAAAACEAAAAHAAAAAgAAAAAAAABgAQAAAAAAAGABAAAAAAAAMAAAAAAAAAAAAAAA AAAAAgAAAAAAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAACQAQAAAAAAADAAAAAA AAAABAAAAAEAAAAIAAAAAAAAABgAAAAAAAAACQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAwAEAAAAA AAAIAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAABEAAAADAAAAAAAAAAAAAAAAAAAAAAAA AMgBAAAAAAAANAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAA=
内容的提问来源于stack exchange,提问作者zwol
相关产品推荐
相关产品推荐

