Skip to content

AD3012: DoNotUseRpath

Summary

Property Value
ID AD3012
Name DoNotUseRpath
Category Security
Severity Warning
Applies to ELF (Linux/Unix)

Description

This rule checks that ELF binaries do not use the deprecated DT_RPATH dynamic tag for library search paths. DT_RPATH has been superseded by DT_RUNPATH and poses security risks because it takes precedence over LD_LIBRARY_PATH, making it harder for users and administrators to override library paths.

Why This Matters

The deprecated DT_RPATH tag creates a rigid library search order that cannot be overridden, potentially enabling library injection attacks and making security updates harder to deploy.

RPATH vs RUNPATH Search Order

The difference is critical for security:

With DT_RPATH:
  1. DT_RPATH entries (hardcoded, cannot override)
  2. LD_LIBRARY_PATH
  3. DT_RUNPATH entries
  4. System paths (/lib, /usr/lib)

With DT_RUNPATH:
  1. LD_LIBRARY_PATH (administrator can override!)
  2. DT_RUNPATH entries
  3. System paths

Why Override Capability Matters

Scenario With RPATH With RUNPATH
Security patch Must rebuild binary Set LD_LIBRARY_PATH
Testing new library Must rebuild binary Set LD_LIBRARY_PATH
Container isolation Harder Easy path override
Debug with instrumentation Harder Easy interposition

Library Injection Risk

If RPATH points to a location the attacker can write:

Binary with RPATH=/opt/app/lib

If attacker can write to /opt/app/lib:
  1. Place malicious libfoo.so in /opt/app/lib
  2. Binary loads attacker's library
  3. Attacker code runs with binary's privileges

With RUNPATH, admin could use:
  LD_LIBRARY_PATH=/safe/path ./binary

SUID/SGID Implications

Note: LD_LIBRARY_PATH is ignored for SUID binaries, so:

Binary Type RPATH Risk
Normal binary Moderate (LD_LIBRARY_PATH workaround)
SUID binary High (no workaround possible)

Historical Context

1990s: DT_RPATH introduced
2000s: Security issues recognized
2011: DT_RUNPATH recommended (glibc 2.11+)
Today: DT_RPATH deprecated, --enable-new-dtags default

Linker Behavior

Flag Result
-Wl,-rpath,/path (old default) Creates DT_RPATH
-Wl,-rpath,/path -Wl,--enable-new-dtags Creates DT_RUNPATH
Most modern linkers default DT_RUNPATH
  • Security: DT_RPATH cannot be overridden by LD_LIBRARY_PATH, making it difficult to redirect library loading for security purposes
  • Flexibility: DT_RUNPATH is the modern replacement that respects LD_LIBRARY_PATH ordering
  • Compatibility: Modern linkers default to DT_RUNPATH when -Wl,--enable-new-dtags is used

Performance Considerations

Switching from RPATH to RUNPATH has no performance impact:

Aspect Impact
Library loading time Identical
Runtime overhead None
Binary size Identical

Why there's no overhead: - Both RPATH and RUNPATH are resolved at dynamic link time - The only difference is search order priority - No runtime checks or additional processing

This is a pure security improvement with zero cost.

Resolution

Use RUNPATH instead of RPATH

# Modern linkers: use --enable-new-dtags to use DT_RUNPATH
gcc -o myapp myapp.c -Wl,-rpath,/opt/mylibs -Wl,--enable-new-dtags

# Or avoid embedding paths entirely and use LD_LIBRARY_PATH at runtime
gcc -o myapp myapp.c

Verify the fix

readelf -d myapp | grep -E "RPATH|RUNPATH"

Example

Fail: Binary uses deprecated DT_RPATH

0x000000000000000f (RPATH)     Library rpath: [/opt/mylibs]

Pass: Binary uses DT_RUNPATH or no embedded paths

0x000000000000001d (RUNPATH)   Library runpath: [/opt/mylibs]

See Also