Skip to content

AD3025: EnableExceptionHandling

Summary

Property Value
ID AD3025
Name EnableExceptionHandling
Category Security
Severity Note
Applies to ELF (Linux/Unix)

Description

The -fexceptions compiler option generates frame unwind information for all functions. This allows glibc's implementation of POSIX thread cancellation to use proper stack unwinding instead of setjmp/longjmp, improving security for multi-threaded C code.

How It Works

The rule checks for the presence of exception handling sections:

  • .eh_frame - Exception handling frame information
  • .eh_frame_hdr - Header for .eh_frame lookup
  • .gcc_except_table - GCC exception table

At least one of these sections should be present for proper exception handling.

Why This Matters

Without proper exception handling support, pthreads cancellation in C code leaves unprotected function pointers on the stack. This creates additional exploitation targets that make buffer overflow attacks easier to execute.

The Thread Cancellation Problem

glibc's thread cancellation mechanism differs based on exception handling:

With -fexceptions:
  pthread_cancel() → Uses C++ unwind mechanism
  Stack frames properly unwound
  No extra pointers on stack

Without -fexceptions:
  pthread_cancel() → Uses setjmp/longjmp style
  glibc places function pointers on stack
  These pointers are NOT protected by canaries

Stack Layout Comparison

Without -fexceptions (vulnerable):
  ┌─────────────────┐
  │ Return Address  │  ← Protected by canary
  ├─────────────────┤
  │ Canary          │
  ├─────────────────┤
  │ Cancel Handler  │  ← UNPROTECTED function pointer!
  ├─────────────────┤
  │ Local Buffer    │  ← Overflow starts here
  └─────────────────┘

Overflow can reach Cancel Handler WITHOUT touching canary!

With -fexceptions (safe):
  ┌─────────────────┐
  │ Return Address  │  ← Protected by canary
  ├─────────────────┤
  │ Canary          │
  ├─────────────────┤
  │ Local Buffer    │  ← No unprotected pointers
  └─────────────────┘

Unwind info in .eh_frame, not on stack.

Exploitation Scenario

1. Multi-threaded C program without -fexceptions
2. Buffer overflow in one thread
3. Overflow overwrites cancel handler pointer
4. Another thread calls pthread_cancel()
5. glibc invokes the (corrupted) handler
6. Attacker gains code execution
7. Stack canary never detected corruption!

Who Is Affected

Code Type Risk
Multi-threaded C Yes, if no -fexceptions
C++ code No, exceptions enabled by default
Single-threaded C Lower (no pthread_cancel)
C with no buffer ops Lower

Performance Overhead

Aspect Impact
Code size ~2-5% larger (unwind tables)
Runtime Zero for happy path
Stack unwind Only on exceptions/cancel

.eh_frame Section

With -fexceptions:
  .eh_frame      ← Contains unwind instructions
  .eh_frame_hdr  ← Lookup table for fast access

These sections enable proper stack unwinding
without storing pointers on the runtime stack.
  • Thread cancellation safety: Enables proper POSIX thread cancellation handling
  • Stack pointer protection: Without exception handling, glibc may spill unprotected function pointers onto the stack
  • Exploit mitigation: Reduces attack surface for stack-based buffer overflows
  • OpenSSF recommended: Part of the OpenSSF Compiler Hardening Guide

Vulnerability Background

When -fexceptions is not enabled for C code using pthreads:

  1. glibc's thread cancellation uses setjmp/longjmp-style unwinding
  2. This may place an unprotected function pointer on the stack
  3. Stack buffer overflows can more easily hijack control flow
  4. The function pointer becomes an exploitation target

Resolution

GCC/Clang

Enable exception handling for C code:

# Compile with -fexceptions
gcc -fexceptions source.c -o binary

# Especially important for multi-threaded code
gcc -fexceptions -pthread source.c -o binary

CMake

add_compile_options(-fexceptions)

# Or for specific targets
target_compile_options(myapp PRIVATE -fexceptions)

Makefile

CFLAGS += -fexceptions

When to Suppress

This rule may be suppressed for:

  • Single-threaded code: Programs that don't use pthreads
  • No thread cancellation: Code that doesn't use pthread_cancel
  • Size-constrained: Embedded systems where binary size is critical
  • Statically linked: With musl or other libcs that handle this differently

Caveats

  • Exception handling increases binary size due to unwind tables
  • The actual security benefit depends on how thread cancellation is used
  • This is marked as Note level - informational, not a hard requirement
  • C++ code typically has this enabled by default

Binary Size Impact

Without -fexceptions: Smaller binary, no .eh_frame
With -fexceptions:    ~5-10% larger due to unwind tables

Checking Exception Handling

# Check for .eh_frame section
readelf -S binary | grep eh_frame

# Check section sizes
size --format=sysv binary | grep -E "eh_frame|gcc_except"

# Using objdump
objdump -h binary | grep eh_frame

References