Case 49: Executable Stack (GNU_STACK RWX)¶
| Field | Value |
|---|---|
| Verdict | ๐ข COMPATIBLE |
| Category | Quality (Compatible) |
| Platforms | Linux |
| Flags | Bad practice |
Detected ChangeKinds |
executable_stack_removed |
| Source files | examples/case49_executable_stack/ |
Category: ELF / Security | Verdict: ๐ข COMPATIBLE (bad practice)
Verdict and consumer impact¶
Both libraries export identical symbols with identical signatures and
identical DWARF type layouts โ the functional ABI is unchanged. The
difference is in the PT_GNU_STACK program header: v1 (linked with
-Wl,-z,execstack) has flags RWE (read-write-execute), while v2 (linked
with -Wl,-z,noexecstack) has RW. An executable stack disables NX
(No-eXecute) protection for the entire process that loads the library,
making stack-based buffer overflows in that process trivially exploitable
โ a security regression, not an ABI break. No recompilation is required
either way; the concern is deployment security posture, not compatibility.
Old/new diff¶
old/lib.c (linked -Wl,-z,execstack) |
new/lib.c (linked -Wl,-z,noexecstack) |
|---|---|
identical compute()/transform() source |
identical compute()/transform() source |
GNU_STACK segment: RWE |
GNU_STACK segment: RW |
abicheck command¶
gcc -shared -fPIC -g old/lib.c -o libstack_v1.so -Wl,-z,execstack
gcc -shared -fPIC -g new/lib.c -o libstack_v2.so -Wl,-z,noexecstack
abicheck compare libstack_v1.so libstack_v2.so
Expected abicheck finding¶
Verdict: COMPATIBLE (exit 0)
Quality Issues:
- executable_stack_removed: Executable stack removed: library now uses a
non-executable stack โ NX protection restored (good practice)
Minimum evidence¶
min_evidence: L0 โ the PT_GNU_STACK program header's flags are read
directly from the ELF program header table; no debug info or headers
needed.
Why abicheck catches it¶
abicheck reads each binary's PT_GNU_STACK segment flags from the ELF
program headers and compares the executable bit between old and new; a
library that drops the executable-stack flag (or gains one) is reported
as a quality finding โ executable_stack_removed/executable_stack_added
โ rather than a break, since the exported symbols and their types are
unaffected.
Runtime failure demonstration¶
No observable effect on this app โ compute()/transform() return
identical results in both versions, since neither function relies on
stack execution. The risk PT_GNU_STACK RWE exposes is latent: it widens
the blast radius of any other stack-corrupting bug in the process, it
doesn't itself cause one.
# Build old library (executable stack) + app
gcc -shared -fPIC -g old/lib.c -o libstack.so -Wl,-z,execstack
gcc -g app.c -L. -lstack -Wl,-rpath,. -o app
./app
# โ compute(7) = 50
# โ transform(3, 4) = 11
# Swap in new library (non-executable stack, no recompile)
gcc -shared -fPIC -g new/lib.c -o libstack.so -Wl,-z,noexecstack
./app
# โ compute(7) = 50
# โ transform(3, 4) = 11 (identical)
# The difference is visible only in the ELF program headers:
readelf -l libstack_v1.so | grep -A1 GNU_STACK
# โ GNU_STACK ... RWE
readelf -l libstack_v2.so | grep -A1 GNU_STACK
# โ GNU_STACK ... RW
Safe redesign¶
Ensure every object linked into the library โ especially hand-written or
generated assembly โ carries a .note.GNU-stack section requesting a
non-executable stack, since the linker takes the union of all input
objects' stack permissions:
or force it at link time regardless of inputs:
Real-world example: Fedora and Debian both enforce
-Wl,-z,noexecstack via lintian/rpmlint packaging checks, rejecting
packages that ship an executable stack.
Cross-tool comparison¶
abidw/abidiff operate on symbol and type ABI and have no dedicated
notion of PT_GNU_STACK security metadata, so there is no equivalent
finding to compare here โ this is an abicheck-specific ELF hardening
check.
References¶
Source files¶
CMakeLists.txtapp.c
See also: Examples overview ยท All COMPATIBLE cases ยท Category: Quality (Compatible).