On this page
ASLR and Security Hardening
Coverage: ASLR (stack/mmap/exec) → PIE → RELRO → stack canary → NX → CET (IBT/SHSTK) → CFI → sanitizers as defense Applicable to: Linux user space, GCC/Clang + glibc + kernel
Overview
ASLR is the first line of defense in Linux user-space security—by randomizing the address space layout, it prevents attackers from predicting the locations of code, data, and the stack. However, ASLR alone is not enough—PIE, RELRO, stack canaries, and NX each address specific attack surfaces, and used in combination, they form a defense-in-depth strategy.
ASLR Three Levels
# /proc/sys/kernel/randomize_va_space
# 0: Disabled
# 1: Randomize mmap base + stack + vDSO (partial)
# 2: Full randomization + brk (full, default)
# What gets randomized:
# - stack: Random offset on every exec (up to ~8MB random range)
# - mmap base: Starting address for shared libraries (.so) and anonymous mmap
# - executable: Only for PIE (Position-Independent Executable)
# - brk (heap): Randomized in full mode
# Not affected by ASLR:
# - Non-PIE executables: Fixed address (0x400000)
# - vsyscall: Fixed address (0xffffffffff600000)
PIE: Position-Independent Executable
# Non-PIE (traditional, GCC default -no-pie, deprecated):
# .text loaded at fixed address 0x400000
# → Attackers know all gadget addresses → ROP is easy
# PIE (modern default, GCC -pie):
# The entire binary can be loaded randomly like a .so → ASLR takes effect
# Load base address is randomized on every exec
# View load base address:
|
# Performance cost of PIE: ~2-3% (extra indirection for GOT)
# Can be partially eliminated with -fno-plt (direct GOT access, skipping PLT)
RELRO: Relocation Read-Only
# Linker options:
# -Wl,-z,norelro: No protection
# -Wl,-z,relro: Partial protection (default)
# -Wl,-z,now: Full protection (BIND_NOW + RELRO)
# Effects:
# Partial RELRO:
# .got and .dynamic become read-only after startup
# .got.plt remains writable (required for lazy binding)
#
# Full RELRO (BIND_NOW):
# All GOT entries become read-only after startup
# Cost: All symbols resolved immediately at startup → slightly slower startup
# Benefit: GOT is unwritable → cannot overwrite GOT pointers → prevents GOT overwrite attacks
# Check:
readelf -l /bin/ls | grep GNU_RELRO # Present → RELRO enabled
readelf -d /bin/ls | grep BIND_NOW # Present → Full RELRO
Stack Canary
// GCC -fstack-protector (automatically enabled)
// Places an 8-byte canary (random value) at the bottom of the stack frame for each function
// Checks the canary before function return → if modified → stack overflow detected → abort
// Canary source:
// /proc/sys/kernel/randomize_va_space → AT_RANDOM (16 bytes)
// Or: __stack_chk_guard (glibc TLS, initialized from AT_RANDOM at startup)
// Check:
// __stack_chk_fail() → __fortify_fail() → abort + logging
// Compiler levels:
// -fstack-protector: Protects functions with char buf[8+]
// -fstack-protector-strong: Protects functions with arrays/address-taking operations (recommended)
// -fstack-protector-all: Protects all functions (performance cost ~5%)
NX (No-Execute)
Hardware (x86: XD bit / NX bit, ARM: XN):
ELF segment PF_X → mapped as executable
Stack and heap: No PF_X → non-executable
→ Attackers cannot inject shellcode into heap/stack and jump to execute it
→ However, ROP remains effective (reusing existing .text snippets)
Check:
cat /proc/cpuinfo | grep nx # x86: 'nx' in flags
readelf -l /bin/ls | grep STACK # PT_GNU_STACK: RW (no X)
CET: Control-flow Enforcement (Intel 11th gen+)
IBT (Indirect Branch Tracking):
Hardware: Indirect jumps (jmp/call [reg]) can only target endbr32/endbr64 instructions
→ ROP/JOP jumping to middle of a gadget → CPU detects → #CP fault
SHSTK (Shadow Stack):
Hardware: Maintains an independent shadow stack (cannot be modified via regular stores)
call: Hardware pushes return address to shadow stack
ret: Hardware checks shadow stack vs. normal stack → mismatch → #CP fault
→ ROP modifying stack → detected on ret → rejected
Compiler: GCC 8+ / Clang 7+ -fcf-protection=full
Kernel: CET support (5.18+)
Combined Defenses
Attack Vector Mitigation
────────────────────────────────────
Stack overflow → canary + NX + SHSTK
Heap overflow → FORTIFY_SOURCE, ASAN (debug)
GOT overwrite → Full RELRO
ROP/JOP → ASLR + PIE + IBT
Information leak → kptr_restrict, dmesg_restrict
UAF → ASAN (debug), SLAB_FREELIST_RANDOM
Inspection Tools
# Check binary security hardening
# Or: hardening-check /bin/ls (Debian/Ubuntu devscripts)
# Output:
# Position Independent Executable: yes
# Stack protected: yes
# Fortify Source functions: yes
# Read-only relocations: yes
# Immediate binding: yes
References
- Kernel Documentation:
Documentation/admin-guide/sysctl/kernel.rst(randomize_va_space) - LWN: "CET on x86", "Full RELRO and BIND_NOW"
- Tools:
checksec,hardening-check,pwntools
Keywords: ASLR, PIE, RELRO, stack canary, NX, CET, IBT, SHSTK, FORTIFY_SOURCE, BIND_NOW