summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryam Vargas <hexlabsecurity@proton.me>2026-07-17 06:26:55 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-07 17:37:23 +0200
commit3e19172089ec81132a8a48e802b1034a744209f4 (patch)
treefb4d57a582c031c11d974c3d17138a50eb65c411
parent8c52308f3805bc8f5b664a4f63eacc0027dc86fd (diff)
downloadlinux-3e19172089ec81132a8a48e802b1034a744209f4.tar.gz
linux-3e19172089ec81132a8a48e802b1034a744209f4.zip
dm-pcache: validate geometry fields from on-disk cache_info
commit 32d1809da31094ef76fd98dc1f1a8b55ca1295dd upstream. cache_segs_init() iterates cache_info->n_segs times indexing cache->segments[], which is sized to the cache device geometry, and get_seg_id() takes each segment id from the on-media cache_info and the per-segment next_seg link. Both come from cache device metadata that is only CRC-protected with a fixed public seed, so whoever supplies the cache device on a table load (CAP_SYS_ADMIN) controls them: an oversized n_segs or an out-of-range id drives an out-of-bounds access of cache->segments[] and a wild CACHE_DEV_SEGMENT() pointer into the device mapping -- an out-of-bounds read and write from on-disk data. Reject an n_segs that exceeds the device segment count and a segment id that is out of range before either is used. Valid metadata is unaffected. Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Cc: stable@vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/md/dm-pcache/cache.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/md/dm-pcache/cache.c b/drivers/md/dm-pcache/cache.c
index bb1ada31e483..91cf5491c6f8 100644
--- a/drivers/md/dm-pcache/cache.c
+++ b/drivers/md/dm-pcache/cache.c
@@ -247,6 +247,13 @@ static int get_seg_id(struct pcache_cache *cache,
} else {
*seg_id = cache->cache_info.seg_id;
}
+
+ if (*seg_id >= cache_dev->seg_num) {
+ pcache_dev_err(pcache, "invalid segment id %u from cache device (seg_num %u)\n",
+ *seg_id, cache_dev->seg_num);
+ ret = -EIO;
+ goto err;
+ }
}
return 0;
err:
@@ -262,6 +269,13 @@ static int cache_segs_init(struct pcache_cache *cache)
int ret;
u32 i;
+ if (cache_info->n_segs > cache->cache_dev->seg_num) {
+ pcache_dev_err(CACHE_TO_PCACHE(cache),
+ "cache_info n_segs %u exceeds cache device segments %u\n",
+ cache_info->n_segs, cache->cache_dev->seg_num);
+ return -EIO;
+ }
+
for (i = 0; i < cache_info->n_segs; i++) {
ret = get_seg_id(cache, prev_cache_seg, new_cache, &seg_id);
if (ret)