https://bugs.kde.org/show_bug.cgi?id=523068
Bug ID: 523068
Summary: Valgrind PDB File Search Command Injection via Crafted
PE Path
Classification: Developer tools
Product: valgrind
Version First unspecified
Reported In:
Platform: Other
OS: All
Status: REPORTED
Severity: normal
Priority: NOR
Component: general
Assignee: [email protected]
Reporter: [email protected]
Target Milestone: ---
Created attachment 194307
--> https://bugs.kde.org/attachment.cgi?id=194307&action=edit
poc
# Valgrind PDB File Search Command Injection via Crafted PE Path
**Product:** Valgrind
**Version:** 3.27.1 (latest release)
**File:** `coregrind/m_debuginfo/readpdb.c`
**Function:** `ML_(find_name_of_pdb_file)` (line 2529-2534)
**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 PE executable under Valgrind + Wine)
**Validation: Lab verified**
**Environment:** Valgrind 3.27.1 source (valgrind-3.27.1.tar.bz2), Linux with
Wine, default build configuration
**Commit:** HEAD at sourceware.org/git/valgrind.git (verified 2026-07-01)
## Summary
When Valgrind processes a Windows PE executable (via Wine on Linux), it invokes
`strings` and `grep` via `VG_(system)` (which calls `/bin/sh -c <cmd>`) to
locate the associated PDB debug file. The PE filename is placed in single
quotes inside a double-quoted shell command, but in POSIX shell, single quotes
inside double quotes are literal characters and provide no quoting protection.
`$()` command substitution and backtick expansion remain active.
## Vulnerable Code
`coregrind/m_debuginfo/readpdb.c`, lines 2520-2534:
```c
const HChar* sh = "/bin/sh";
const HChar* strings = "strings";
const HChar* egrep = "grep -E";
/* (sh) -c "(strings) (pename) | (egrep) 'pdb' > (tmpname) */
Int cmdlen = VG_(strlen)(strings) + VG_(strlen)(pename)
+ VG_(strlen)(egrep) + VG_(strlen)(tmpname)
+ 100/*misc*/;
HChar* cmd = ML_(dinfo_zalloc)("di.readpe.fnopf.cmd", cmdlen);
VG_(sprintf)(cmd, "%s -c \"%s '%s' | %s '\\.pdb$|\\.PDB$' >> %s\"",
sh, strings, pename, egrep, tmpname);
// ^^^ unsanitized PE filename
vg_assert(cmd[cmdlen-1] == 0);
r = VG_(system)( cmd ); // <-- executes via /bin/sh -c
```
The resulting shell command is:
```
/bin/sh -c "strings '<PE_FILENAME>' | grep -E '\.pdb$|\.PDB$' >>
/tmp/vg_pdb_xxx"
```
In POSIX shell, single quotes inside double quotes are literal characters. The
`pename` is effectively unquoted within the double-quoted `-c` argument, so
`$()` and backtick substitution are expanded.
## Data Flow
1. User runs `valgrind wine ./program.exe` on Linux
2. Wine loads the PE executable; Valgrind intercepts and processes its debug
information
3. `ML_(find_name_of_pdb_file)` is called with the PE filename as `pename`
4. Line 2529: `VG_(sprintf)` constructs a shell command embedding `pename` in
single quotes inside double quotes
5. Line 2534: `VG_(system)(cmd)` invokes `/bin/sh -c "<command>"`
6. Shell expands any `$()` or backtick sequences in the PE filename
## Attack Model
An attacker provides a PE executable at a path containing shell metacharacters:
```
/tmp/prog$(touch${IFS}/tmp/pwned).exe
```
When run under Valgrind + Wine:
1. Valgrind processes the PE file's debug information
2. `ML_(find_name_of_pdb_file)` constructs:
`/bin/sh -c "strings '/tmp/prog$(touch${IFS}/tmp/pwned).exe' | grep -E
'\.pdb$|\.PDB$' >> /tmp/vg_pdb_xxx"`
3. The single quotes provide no protection inside the `"..."` argument to
`/bin/sh -c`
4. Shell expands `$(touch${IFS}/tmp/pwned)` -- arbitrary command execution
**Vectors:**
- CTF challenges or untrusted Windows binaries analyzed with Valgrind + Wine
- Malware analysis workflows where PE samples are examined under Valgrind for
memory error detection
- Shared analysis directories where filenames are attacker-controlled
--
You are receiving this mail because:
You are watching all bug changes.