Skip to content

Case 136: Executable Stack Removed (the fix direction)

Field Value
Verdict ๐ŸŸข COMPATIBLE
Category Quality (Compatible)
Platforms Linux
Flags โ€”
Detected ChangeKinds executable_stack_removed
Source files examples/case136_executable_stack_removed/

Category: Quality | Verdict: ๐ŸŸข COMPATIBLE

Verdict and consumer impact

This is the fix counterpart to case49 (which goes the bad direction). v1 has an executable stack โ€” PT_GNU_STACK with flags RWE (-Wl,-z,execstack). v2 corrects it to RW (-Wl,-z,noexecstack), restoring NX (No-eXecute) protection on the process stack. The exported ABI surface is byte-identical between versions, so every existing binary keeps working unmodified โ€” this change only tightens a security property, it never breaks a caller.

Old/new diff

old/lib.c new/lib.c
linked with -Wl,-z,execstack (PT_GNU_STACK = RWE) linked with -Wl,-z,noexecstack (PT_GNU_STACK = RW)
(library source is identical โ€” see old/lib.c / new/lib.c)

abicheck command

gcc -shared -fPIC -g old/lib.c -o libfoo_v1.so -Wl,-z,execstack
gcc -shared -fPIC -g new/lib.c -o libfoo_v2.so -Wl,-z,noexecstack
abicheck compare libfoo_v1.so libfoo_v2.so

Expected abicheck finding

Verdict: COMPATIBLE (exit 0)

- executable_stack_removed: Executable stack removed: library now uses a
  non-executable stack - NX protection restored (good practice)

Minimum evidence

min_evidence: L0 โ€” PT_GNU_STACK's flags are read directly from the ELF program headers; no debug info or headers are needed to see the change.

Why abicheck catches it

abicheck reads each library's PT_GNU_STACK segment flags from the ELF program header table and diffs the executable bit between versions โ€” a pure L0 ELF fact, tracked as the symmetric complement of the executable-stack regression case49 demonstrates, so a hardening improvement is reported as compatible rather than silently ignored or mis-flagged as a regression.

Runtime failure demonstration

No observable effect on existing binaries โ€” both versions run identically; v2 only restores NX protection on the process stack.

readelf -lW libfoo_v1.so | grep GNU_STACK
# โ†’ GNU_STACK ... RWE 0x10

readelf -lW libfoo_v2.so | grep GNU_STACK
# โ†’ GNU_STACK ... RW  0x10

gcc -shared -fPIC -g old/lib.c -o libfoo.so -Wl,-z,execstack
gcc -g app.c -L. -lfoo -Wl,-rpath,. -o app
./app
# โ†’ compute(7) = 50
# โ†’ transform(3, 4) = 11

gcc -shared -fPIC -g new/lib.c -o libfoo.so -Wl,-z,noexecstack
./app
# โ†’ compute(7) = 50
# โ†’ transform(3, 4) = 11   โ† identical

Safe redesign

This case is the safe redesign โ€” the fix is exactly -Wl,-z,noexecstack (or, in CMake, add_link_options(-Wl,-z,noexecstack)), and ensuring any hand-written assembly inputs carry a .section .note.GNU-stack,"",@progbits marker so the linker never unions in an executable-stack requirement from an unmarked object file.

References


Source files

  • CMakeLists.txt
  • app.c

See also: Examples overview ยท All COMPATIBLE cases ยท Category: Quality (Compatible).