Skip to content

Commit e7a7f46

Browse files
authored
Validate that ELF objects request a non-executable stack (#1070)
Closes #1069.
1 parent 3d273cd commit e7a7f46

1 file changed

Lines changed: 36 additions & 3 deletions

File tree

src/validation.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ use {
1010
object::{
1111
Architecture, Endianness, FileKind, Object, SectionIndex, SymbolScope,
1212
elf::{
13-
ET_DYN, ET_EXEC, FileHeader32, FileHeader64, SHN_UNDEF, STB_GLOBAL, STB_WEAK,
14-
STV_DEFAULT, STV_HIDDEN,
13+
ET_DYN, ET_EXEC, FileHeader32, FileHeader64, PF_X, PT_GNU_STACK, SHN_UNDEF, STB_GLOBAL,
14+
STB_WEAK, STV_DEFAULT, STV_HIDDEN,
1515
},
1616
macho::{LC_CODE_SIGNATURE, MH_OBJECT, MH_TWOLEVEL, MachHeader32, MachHeader64},
1717
read::{
18-
elf::{Dyn, FileHeader, SectionHeader, Sym},
18+
elf::{Dyn, FileHeader, ProgramHeader, SectionHeader, Sym},
1919
macho::{LoadCommandVariant, MachHeader, Nlist, Section, Segment},
2020
pe::{ImageNtHeaders, PeFile, PeFile32, PeFile64},
2121
},
@@ -1161,6 +1161,39 @@ fn validate_elf<Elf: FileHeader<Endian = Endianness>>(
11611161
}
11621162
}
11631163

1164+
// Verify that objects are not requesting an executable stack. For backwards compatibility,
1165+
// Linux (the kernel when loading an executable, and glibc when loading a shared library)
1166+
// assumes you need an executable stack unless you request otherwise. In linked outputs
1167+
// (executables and shared libraries) this is in the program header: the flags of a
1168+
// PT_GNU_STACK entry specify stack permissions, and the default if unspecified is RWX. In
1169+
// intermediate objects (.o files) this is conveyed via the presence of an empty-length
1170+
// .note.GNU-stack, which is marked as an executable section (SHF_EXECINSTR) if the object
1171+
// needs an executable stack.
1172+
//
1173+
// For now we only check binaries because of an LLVM bug that causes .o files to be missing a
1174+
// .note.GNU-stack section, which we are overriding with -Wl,-z,noexecstack.
1175+
1176+
if matches!(elf.e_type(endian), ET_EXEC | ET_DYN) {
1177+
let mut found_pt_gnu_stack = false;
1178+
for phdr in elf.program_headers(endian, data)? {
1179+
if phdr.p_type(endian) != PT_GNU_STACK {
1180+
continue;
1181+
}
1182+
found_pt_gnu_stack = true;
1183+
if (phdr.p_flags(endian) & PF_X) != 0 {
1184+
context
1185+
.errors
1186+
.push(format!("{} requests executable stack", path.display()));
1187+
}
1188+
}
1189+
if !found_pt_gnu_stack {
1190+
context.errors.push(format!(
1191+
"{} missing PT_GNU_STACK header (defaults to executable stack)",
1192+
path.display(),
1193+
));
1194+
}
1195+
}
1196+
11641197
Ok(())
11651198
}
11661199

0 commit comments

Comments
 (0)