AD3024: RestrictDlopen¶
Summary¶
| Property | Value |
|---|---|
| ID | AD3024 |
| Name | RestrictDlopen |
| Category | Security |
| Severity | Note |
| Applies to | ELF (Linux/Unix) |
Description¶
The -Wl,-z,nodlopen linker option marks shared objects as not available to dlopen(3) calls. This can help reduce an attacker's ability to load and manipulate shared objects as part of an attack chain.
How It Works¶
The rule checks for the DF_1_NOOPEN flag (0x40) in the DT_FLAGS_1 dynamic section entry:
- Flag present: Shared object cannot be loaded via dlopen()
- Flag absent: Shared object can be dynamically loaded
Why This Matters¶
Dynamic library loading via dlopen() is a powerful capability that attackers can abuse. Restricting dlopen access reduces the attack surface by preventing exploitation techniques that rely on dynamically loading and executing code from shared objects.
Attack Surface from dlopen¶
Attackers can abuse dlopen in various ways:
1. Code Injection:
- Attacker creates malicious .so file
- Tricks program into dlopen()ing it
- Attacker's code runs in process context
2. Library Confusion:
- Attacker controls library search path
- dlopen() loads attacker's library instead
- Code substitution attack
3. ROP to dlopen:
- After gaining code execution
- ROP chain calls dlopen("malicious.so")
- Full attacker code loads into process
Protection Mechanisms¶
| Flag | Effect |
|---|---|
| DF_1_NOOPEN | Library cannot be dlopen'd |
| DF_1_NODUMP | Library cannot be dumped (ptrace) |
| DF_1_NODEFLIB | Don't search default library paths |
When NOOPEN Helps¶
| Scenario | Benefit |
|---|---|
| Sensitive libraries | Can't be loaded into attacker-controlled process |
| Internal libraries | Only available through normal linking |
| Exploit chains | Breaks ROP→dlopen patterns |
| Sandboxed code | Limits loading capabilities |
NOOPEN Limitations¶
NOOPEN prevents:
✓ dlopen("libsensitive.so", RTLD_LAZY)
✓ Dynamic loading attacks
NOOPEN does NOT prevent:
✗ Normal linking (ld.so loads at startup)
✗ Direct mmap of library file
✗ Other exploitation techniques
It's one layer of defense, not a complete solution.
OpenSSF Recommendation¶
The OpenSSF Compiler Hardening Guide recommends nodlopen for:
- Libraries containing sensitive operations
- Libraries that should only be statically linked
- Defense-in-depth for all libraries
Compatibility Considerations¶
| Use Case | NOOPEN Compatible |
|---|---|
| Plugin systems | No (plugins need dlopen) |
| Normal libraries | Yes |
| System libraries | Usually no |
| Application-specific | Yes |
- Attack surface reduction: Prevents attackers from loading the library dynamically
- Defense in depth: Makes exploitation chains more difficult
- Library isolation: Ensures libraries are only loaded through normal linking
- OpenSSF recommended: Part of the OpenSSF Compiler Hardening Guide
Resolution¶
GCC/Clang¶
Add the nodlopen flag when linking shared libraries:
CMake¶
# For shared libraries
add_library(mylib SHARED source.c)
target_link_options(mylib PRIVATE -Wl,-z,nodlopen)
Makefile¶
When to Suppress¶
This rule may be suppressed for:
- Plugin libraries: Libraries designed to be loaded via dlopen()
- Loadable modules: Intentionally dynamic components
- Optional dependencies: Libraries that may or may not be loaded at runtime
- Optimized library loading: Libraries using delayed loading patterns
Caveats¶
- This flag only affects
dlopen()calls, not normal dynamic linking - The flag is enforced by glibc, not the kernel
- Attackers with code execution could bypass this check
- Not all build systems support this flag by default