https://bugs.kde.org/show_bug.cgi?id=523067
Bug ID: 523067
Summary: Valgrind dsymutil Command Injection via Crafted
Library Path
Classification: Developer tools
Product: valgrind
Version First unspecified
Reported In:
Platform: Other
OS: All
Status: REPORTED
Severity: major
Priority: NOR
Component: general
Assignee: [email protected]
Reporter: [email protected]
Target Milestone: ---
Created attachment 194306
--> https://bugs.kde.org/attachment.cgi?id=194306&action=edit
poc
# Valgrind dsymutil Command Injection via Crafted Library Path
**Product:** Valgrind
**Version:** 3.27.1 (latest release)
**File:** `coregrind/m_debuginfo/readmacho.c`
**Function:** `ML_(read_macho_debug_info)` (line 1338-1346)
**CWE:** CWE-78 (Improper Neutralization of Special Elements used in an OS
Command)
**CVSS 3.1:** 7.8 (AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)
**Auth Required:** None (user runs program under Valgrind)
**Validation: Lab verified**
**Environment:** Valgrind 3.27.1 source (valgrind-3.27.1.tar.bz2), macOS,
default build configuration
**Commit:** HEAD at sourceware.org/git/valgrind.git (verified 2026-07-01)
## Summary
When Valgrind processes a Mach-O binary on macOS that has no matching dSYM
debug symbols, it invokes `/usr/bin/dsymutil` via `VG_(system)` (which calls
`/bin/sh -c <cmd>`). The library filename is embedded in double quotes, which
do not prevent shell command substitution (`$()` or backticks). An attacker who
controls a library path can achieve arbitrary command execution when a user
runs any program that loads that library under Valgrind.
The `--dsymutil` flag defaults to `yes`, making this reachable in all default
macOS Valgrind configurations.
## Vulnerable Code
`coregrind/m_debuginfo/readmacho.c`, lines 1332-1346:
```c
/* Run dsymutil */
{ Int r;
const HChar* dsymutil = "/usr/bin/dsymutil ";
HChar* cmd = ML_(dinfo_zalloc)( "di.readmacho.tmp1",
VG_(strlen)(dsymutil)
+ VG_(strlen)(di->fsm.filename)
+ 32 /* misc */ );
VG_(strcpy)(cmd, dsymutil);
if (0) VG_(strcat)(cmd, "--verbose ");
VG_(strcat)(cmd, "\"");
VG_(strcat)(cmd, di->fsm.filename); // <-- unsanitized filename
VG_(strcat)(cmd, "\"");
if (VG_(clo_verbosity) > 0) {
VG_(message)(Vg_DebugMsg, "run: %s\n", cmd);
}
r = VG_(system)( cmd ); // <-- executes via /bin/sh -c
```
`VG_(system)` implementation at `coregrind/m_libcproc.c:549`:
```c
const HChar *argv[4] = { "/bin/sh", "-c", cmd, 0 };
pid = VG_(spawn)(argv[0], argv);
```
## Data Flow
1. User runs `valgrind ./program` on macOS
2. `./program` loads a shared library (dylib) from a path controlled by the
attacker
3. Valgrind's debug info reader processes the library via
`ML_(read_macho_debug_info)`
4. If no matching dSYM directory is found and the path is not a "system" path
(not under `/usr/`, `/bin/`, `/System/`, `/Library/`, `/Applications/`,
`/opt/`, `/sw/`, `/sbin/`), Valgrind proceeds to run dsymutil
5. Line 1318: `if (!VG_(clo_dsymutil))` -- defaults to `True` (enabled), so
this block is skipped
6. Lines 1338-1342: The library filename is concatenated into a shell command
with only double-quote protection
7. Line 1346: `VG_(system)(cmd)` invokes `/bin/sh -c "/usr/bin/dsymutil
\"<filename>\""`
8. In POSIX shell, double quotes do NOT prevent `$()` command substitution or
backtick expansion
## Attack Model
An attacker creates a shared library at a path containing shell metacharacters:
```
/tmp/lib$(touch${IFS}/tmp/pwned).dylib
```
Or using backticks:
```
/tmp/lib`touch /tmp/pwned`.dylib
```
When a program linked against this library (or one that `dlopen()`s it) is run
under Valgrind:
1. Valgrind detects the Mach-O shared library
2. No dSYM file exists at the expected path
3. Path is not in the system library exclusion list (not under `/usr/`,
`/System/`, etc.)
4. Valgrind constructs: `/usr/bin/dsymutil
"/tmp/lib$(touch${IFS}/tmp/pwned).dylib"`
5. `/bin/sh -c` expands `$(touch${IFS}/tmp/pwned)` before dsymutil runs
6. Arbitrary command execution in the context of the Valgrind process
**Vectors for placing the malicious library:**
- DYLD_LIBRARY_PATH or DYLD_INSERT_LIBRARIES manipulation
- Shared library in a user-writable project directory (e.g., `./lib/`)
- Crafted application bundle with embedded dylibs
- CTF challenges or untrusted binaries with embedded library references
**Default exposure:** All macOS Valgrind users. The `--dsymutil=yes` default
means no special flags are needed.
--
You are receiving this mail because:
You are watching all bug changes.