CVE Candidate: KDB Format String Vulnerability via PROMPT Environment Variable
File
kernel/debug/kdb/kdb_main.c, line 1271
Severity
Critical — Kernel arbitrary memory write (format string attack with %n)
Vulnerability
// kdb_local(), line 1271
snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"),
raw_smp_processor_id());
The value of the PROMPT environment variable is passed directly as the format string argument to snprintf. An attacker with KDB console access can write a malicious format string into PROMPT via the set command, which is then evaluated as a format string every time the prompt is displayed.
Root Cause
kdbgetenv("PROMPT") returns a user-controlled string. Using it as the second argument to snprintf — the format string position — turns any %-specifiers embedded in PROMPT into active format directives, not literal text.
The only argument passed after the format string is raw_smp_processor_id() (an integer). The snprintf call therefore has a fixed, narrow argument list while the format string is fully attacker-controlled.
Attack Scenario
- Attacker reaches the KDB prompt (physical console, crash, or breakpoint).
- Issues:
set PROMPT %65535d%18$n%65535dconsumes the one integer argument and pads output to 65535 characters.%18$nwrites the character count (an attacker-chosen value) to the address held in the 18th argument slot on the kernel stack, which the attacker can tune by adjusting the format string.
- On the very next prompt redraw,
snprintfexecutes the format string with kernel privileges, writing an arbitrary 4-byte value to an arbitrary kernel address. - This can overwrite a function pointer, security hook, or
modprobe_pathto achieve arbitrary code execution at ring 0.
%s and %p specifiers can additionally leak kernel stack/heap addresses, defeating KASLR before the write step.
Impact
| Property | Detail |
|---|---|
| Primitives | Arbitrary kernel memory read (%s/%p) and write (%n) |
| Privilege required | KDB console access (physical or via kgdb) |
| Effect | Full kernel compromise / privilege escalation to ring 0 |
| KASLR bypass | Yes — stack address leak via %p |
Proof-of-Concept (Outline)
# Step 1 — leak a kernel stack address
set PROMPT %p%p%p%p%p%p%p%p
# (read address from next prompt display)
# Step 2 — compute target offset (e.g., modprobe_path or security hook)
# Step 3 — write lower 16 bits of target with %<val>d%<offset>$hn
set PROMPT %<lo_val>d%<offset>$hn
# Step 4 — write upper 16 bits similarly (two-write technique)
Recommended Fix
Never use user-controlled data as a format string. Pass the PROMPT value as a %s argument:
// SAFE: PROMPT value treated as data, not as a format string
snprintf(kdb_prompt_str, CMD_BUFLEN, "%s",
kdbgetenv("PROMPT") ?: "kdb> ");
If CPU-number substitution is still required, implement it with an explicit parser that only recognises the %d specifier for the CPU number, rejecting all other percent sequences.
References
- CWE-134: Use of Externally-Controlled Format String
- The comment on line 1270 (
/* PROMPT can only be set if we have MEM_READ permission. */) acknowledges the sensitivity of this path but does not prevent format string injection.