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_RPATHcannot be overridden byLD_LIBRARY_PATH, making it difficult to redirect library loading for security purposes - Flexibility:
DT_RUNPATHis the modern replacement that respectsLD_LIBRARY_PATHordering - Compatibility: Modern linkers default to
DT_RUNPATHwhen-Wl,--enable-new-dtagsis 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¶
Example¶
Fail: Binary uses deprecated DT_RPATH
Pass: Binary uses DT_RUNPATH or no embedded paths
See Also¶
- AD3013: ValidateRunpath - Validates RUNPATH entries
- ld.so(8) man page