Memory Safety: NULL pointer dereference in kernel device-mapper pcache option parser
Description
The patch fixes a memory-safety vulnerability in the device-mapper pcache target option parser. Previously, when parsing an option table that advertises an optional argument but provides only the option name (e.g., cache_mode) and no corresponding value, parse_cache_opts would consume the option name, decrement argc, and then call dm_shift_arg() to fetch the value. If no value existed, dm_shift_arg() could return NULL, and a subsequent strcmp() would dereference that NULL pointer, causing a NULL dereference. This could crash the kernel or potentially be leveraged for a DoS. The fix adds explicit checks to ensure an option has a value before consuming it, returning a proper error when a value is missing and avoiding the NULL dereference while preserving correct behavior for well-formed tables.
Proof of Concept
PoC (local DoS via crafted dm-pcache option table):
Prerequisites: Privileged access to manipulate device-mapper tables (e.g., root on a test system) and a test kernel with the vulnerable dm-pcache code loaded.
1) Prepare a malformed device-mapper table that includes an option name with no value. The vulnerable path triggers when an option is present (e.g., cache_mode) but its value is missing. Example table token sequence to feed to dmsetup:
"0 256 pcache cache_mode"
Note: This includes the option name cache_mode but no value after it.
2) Apply the table to create a dm-pcache target (using dmsetup):
dmsetup create test_pcache --table '0 256 pcache cache_mode'
3) Expected outcome on pre-fix kernels: the parser would dereference a NULL pointer when handling the missing value, leading to a kernel crash (NULL pointer dereference) or a hung DM target during table construction.
4) Observations: If the kernel is vulnerable, you should observe a kernel oops/crash or a failure to construct the target with an error instead of a crash depending on the exact code path and kernel version. In a safe test environment, monitor dmesg for a NULL dereference or oops originating from dm-pcache parsing.
Remediation: The fixed code checks for the presence of a value before consuming an option and returns a clear error (e.g., -EINVAL) when a value is missing, preventing the NULL dereference while keeping well-formed option-value pairs functioning as intended.
Commit Details
Author: Samuel Moelius
Date: 2026-06-29 15:47 UTC
Message:
dm-pcache: reject option groups without values
The pcache target parses optional arguments as name/value pairs. A
table that advertises one optional argument and supplies only a
recognized option name, for example "cache_mode", reaches
parse_cache_opts() with argc == 1. The parser consumes the name,
decrements argc to zero, then calls dm_shift_arg() again for the value.
dm_shift_arg() returns NULL when no arguments remain, and the following
strcmp() dereferences that NULL pointer.
Check that each recognized option has a value before consuming it. This
keeps valid "cache_mode writeback" and "data_crc true/false" tables
unchanged while making malformed tables fail during target construction
with a precise missing-value error.
Assisted-by: Codex:gpt-5.5-cyber-preview
Signed-off-by: Samuel Moelius <sam.moelius@trailofbits.com>
Reviewed-by: Zheng Gu <cengku@gmail.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper")
Cc: stable@vger.kernel.org
Triage Assessment
Vulnerability Type: Memory Safety
Confidence: HIGH
Reasoning:
The patch adds checks to ensure that option values exist before consuming them in the dm-pcache option parser, preventing a NULL pointer dereference when parsing malformed tables. This addresses a memory-safety bug that could be triggered by crafted input, reducing potential security impact from crashes or exploitation.
Verification Assessment
Vulnerability Type: Memory Safety: NULL pointer dereference in kernel device-mapper pcache option parser
Confidence: HIGH
Affected Versions: < v7.0-rc6 (pre-fix kernels containing the dm-pcache option parser)
Code Diff
diff --git a/drivers/md/dm-pcache/dm_pcache.c b/drivers/md/dm-pcache/dm_pcache.c
index 81c795c0400e93..d5cfd162c06335 100644
--- a/drivers/md/dm-pcache/dm_pcache.c
+++ b/drivers/md/dm-pcache/dm_pcache.c
@@ -168,6 +168,10 @@ static int parse_cache_opts(struct dm_pcache *pcache, struct dm_arg_set *as,
argc--;
if (!strcmp(arg, "cache_mode")) {
+ if (!argc) {
+ *error = "Missing value for cache_mode";
+ return -EINVAL;
+ }
arg = dm_shift_arg(as);
if (!strcmp(arg, "writeback")) {
opts->cache_mode = PCACHE_CACHE_MODE_WRITEBACK;
@@ -177,6 +181,10 @@ static int parse_cache_opts(struct dm_pcache *pcache, struct dm_arg_set *as,
}
argc--;
} else if (!strcmp(arg, "data_crc")) {
+ if (!argc) {
+ *error = "Missing value for data_crc";
+ return -EINVAL;
+ }
arg = dm_shift_arg(as);
if (!strcmp(arg, "true")) {
opts->data_crc = true;