diff options
| author | Bryam Vargas <hexlabsecurity@proton.me> | 2026-07-17 06:26:55 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-09-07 17:22:57 +0200 |
| commit | ab5dcde6fa96bc115b85f3621c60e39c66229a90 (patch) | |
| tree | 693c63689209bf1ea5c3bf6f55b7d5a378e26726 | |
| parent | 296efdc110b10665c4f2e48e2540f3507267acf3 (diff) | |
| download | linux-stable-ab5dcde6fa96bc115b85f3621c60e39c66229a90.tar.gz linux-stable-ab5dcde6fa96bc115b85f3621c60e39c66229a90.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.c | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/md/dm-pcache/cache.c b/drivers/md/dm-pcache/cache.c index 534bf07b794f..7a8b48cdcb36 100644 --- a/drivers/md/dm-pcache/cache.c +++ b/drivers/md/dm-pcache/cache.c @@ -246,6 +246,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: @@ -261,6 +268,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) |
