Case 49: Executable Stack (GNU_STACK RWX)¶
| Field | Value |
|---|---|
| Verdict | ๐ข COMPATIBLE |
| Category | Quality (Compatible) |
| Platforms | Linux |
| Flags | Bad practice |
Detected ChangeKinds |
โ |
| Source files | examples/case49_executable_stack/ |
Category: ELF / Security | Verdict: BAD PRACTICE
What this case is about¶
Both libraries export identical symbols with identical signatures. The
difference is in the PT_GNU_STACK program header: v1 has flags RWE
(read-write-execute), while v2 has RW (read-write, non-executable).
An executable stack is a security bad practice: it disables NX (No-eXecute) protection for the entire process, making stack-based buffer overflow exploits trivially exploitable.
How executable stacks sneak in¶
The most common cause is linking a single .o file compiled from assembly
that has .section .note.GNU-stack,"x",@progbits. The GNU linker takes the
union of all stack permissions โ if any input object requests an executable
stack, the entire shared library (and any process loading it) gets one.
This happens frequently with:
- Hand-written assembly without the proper .note.GNU-stack annotation
- Old assembly files generated by compilers that defaulted to executable stacks
- Third-party object files or static archives
What abicheck detects¶
EXECUTABLE_STACK: The library hasPT_GNU_STACKwith execute permission. This is classified as a security metadata issue. Because the actual symbols and types are identical, the functional ABI is compatible.
Overall verdict: COMPATIBLE (same ABI surface; executable stack is security concern).
How to reproduce¶
# Build bad version (with executable stack via linker flag)
gcc -shared -fPIC -g bad.c -o libbad.so -Wl,-z,execstack
# Build good version (non-executable stack)
gcc -shared -fPIC -g good.c -o libgood.so -Wl,-z,noexecstack
# Verify GNU_STACK flags
readelf -l libbad.so | grep -A1 GNU_STACK
# โ GNU_STACK 0x000000 ... RWE โ executable!
readelf -l libgood.so | grep -A1 GNU_STACK
# โ GNU_STACK 0x000000 ... RW โ correct
# Run abicheck
python3 -m abicheck.cli dump libbad.so -o /tmp/v1.json
python3 -m abicheck.cli dump libgood.so -o /tmp/v2.json
python3 -m abicheck.cli compare /tmp/v1.json /tmp/v2.json
# โ COMPATIBLE + EXECUTABLE_STACK warning
How to fix¶
Ensure all assembly files include a non-executable stack annotation:
Or use the linker flag to force a non-executable stack:
In CMake:
Real-world example¶
The Linux kernel, glibc, and all major distributions flag executable stack
as a security defect. Fedora and Debian both have policies requiring
-Wl,-z,noexecstack and lintian/rpmlint checks that reject packages with
executable stacks.
References¶
Real Failure Demo¶
Severity: SECURITY / BAD PRACTICE
The program still runs, but the v1 artifact requests an executable process stack. Hardened loaders and distro policy can reject this even when symbol ABI looks otherwise compatible.
cmake -S examples -B /tmp/abicheck-examples-build -DCMAKE_BUILD_TYPE=Debug
cmake --build /tmp/abicheck-examples-build --target case50_executable_stack_v1 case50_executable_stack_v2
readelf -W -l /tmp/abicheck-examples-build/case50_executable_stack/libv1.so | grep GNU_STACK
# GNU_STACK ... RWE
readelf -W -l /tmp/abicheck-examples-build/case50_executable_stack/libv2.so | grep GNU_STACK
# GNU_STACK ... RW
Source files¶
CMakeLists.txtapp.cbad.cgood.c
See also: Examples overview ยท All COMPATIBLE cases ยท Category: Quality (Compatible).