Skip to content

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:

  1. ET_DYN type (shared object) - PIE executables are technically shared objects
  2. Presence of PT_INTERP program header - distinguishes PIE from regular .so files
  3. Presence of PHDR segment - 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

CFLAGS += -fPIE
LDFLAGS += -pie

binary: source.o
    $(CC) $(LDFLAGS) -o $@ $^

Autotools

./configure CFLAGS="-fPIE" LDFLAGS="-pie"

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

References