AD3001: EnablePositionIndependentExecutable¶
Summary¶
| Property | Value |
|---|---|
| ID | AD3001 |
| Name | EnablePositionIndependentExecutable |
| Category | Security |
| Severity | Error |
| Applies to | ELF (Linux/Unix) |
Description¶
A Position Independent Executable (PIE) relocates all of its sections at load time, including the code section, if ASLR is enabled in the Linux kernel (instead of just the stack/heap). This makes ROP-style attacks more difficult.
How It Works¶
The rule checks the ELF header for:
ET_DYNtype (shared object) - PIE executables are technically shared objects- Presence of
PT_INTERPprogram header - distinguishes PIE from regular .so files - Presence of
PHDRsegment - indicates a proper PIE executable
Why This Matters¶
Position Independent Executables (PIE) are the foundation of effective ASLR on Linux. Without PIE, code sections load at predictable addresses, giving attackers a stable target for exploitation.
ASLR Without PIE¶
Without PIE, ASLR only randomizes the stack and heap:
Non-PIE (Partial ASLR):
0x400000: .text (code) - FIXED! Attacker knows this
0x600000: .data - FIXED!
0x7fff????: Stack - Randomized
0x????: Heap - Randomized
PIE (Full ASLR):
0x????: .text (code) - Randomized!
0x????: .data - Randomized!
0x????: Stack - Randomized
0x????: Heap - Randomized
Entropy Comparison¶
| Configuration | Code Entropy | Stack Entropy | Total Protection |
|---|---|---|---|
| No ASLR | 0 bits | 0 bits | None |
| ASLR, no PIE | 0 bits | ~19 bits | Weak |
| ASLR + PIE | ~28 bits | ~19 bits | Strong |
ROP Attack Difficulty¶
Return-Oriented Programming relies on finding "gadgets" in code:
Without PIE:
Gadget at 0x4011f3 always at 0x4011f3
Attacker pre-computes gadget chain
With PIE:
Gadget at 0x????11f3 (base unknown)
Attacker must first leak an address
Adds extra exploitation step
Real-World Attack Impact¶
| Attack Type | Non-PIE | PIE |
|---|---|---|
| Classic ROP | Direct exploitation | Needs info leak first |
| GOT overwrite | Fixed target | Random target |
| Return-to-libc | Known addresses | Must find addresses |
| JIT spray | Easier | Still possible but harder |
Modern Distribution Defaults¶
| Distribution | PIE Default |
|---|---|
| Ubuntu 17.04+ | Yes |
| Debian 9+ | Yes |
| Fedora 23+ | Yes |
| RHEL 8+ | Yes |
| Android 5.0+ | Yes |
Performance Considerations¶
PIE has minimal overhead on modern x86_64:
| Architecture | Overhead | Reason |
|---|---|---|
| x86_64 | <1% | RIP-relative addressing native |
| x86 (32-bit) | 5-10% | Uses register for GOT |
| ARM64 | <1% | PC-relative addressing |
| ARM32 | 1-5% | Minor register pressure |
On 64-bit systems, PIE is essentially free.
- Full ASLR: Code section is also randomized, not just stack/heap
- ROP mitigation: Attackers can't rely on fixed code addresses
- Gadget randomization: ROP gadgets move with each execution
- Modern standard: Expected on all modern Linux distributions
Resolution¶
GCC/Clang¶
Compile with PIE flags:
# Compile
gcc -fPIE -c source.c -o source.o
# Link
gcc -pie source.o -o binary
# Combined
gcc -fPIE -pie source.c -o binary
CMake¶
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# For executables specifically
add_executable(myapp main.c)
set_property(TARGET myapp PROPERTY POSITION_INDEPENDENT_CODE ON)
Makefile¶
Autotools¶
When to Suppress¶
This rule may be suppressed for:
- Static binaries: Statically linked executables without relocation support
- Boot loaders: Pre-ASLR boot code
- Kernel modules: Kernel code has different requirements
- Embedded systems: Systems without ASLR
Caveats¶
- PIE has minor performance overhead (~1-5%)
- May increase binary size slightly
- Some very old kernels don't support PIE
- Static PIE requires special handling
Distribution Defaults¶
| Distribution | PIE Default |
|---|---|
| Ubuntu 17.10+ | ✅ Enabled |
| Fedora 23+ | ✅ Enabled |
| Debian 9+ | ✅ Enabled |
| Arch Linux | ✅ Enabled |
| Alpine | ✅ Enabled |