dm-pcache: reject a kset that overruns its segment

cache_replay(), the writeback worker and the GC worker read a kset of
get_kset_onmedia_size() bytes and advance the position by it. A forged
key_num makes that size exceed the segment's remaining space, so the
advance walks past the segment and trips the cache_pos_advance() BUG_ON.

Reject a kset whose on-media size exceeds cache_seg_remain() before use.

Fixes: 1d57628ff9 ("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>
This commit is contained in:
Bryam Vargas 2026-07-17 06:26:58 -05:00 committed by Mikulas Patocka
parent d189857609
commit 7ac1f10f98
3 changed files with 15 additions and 0 deletions

View File

@ -146,6 +146,11 @@ void pcache_cache_gc_fn(struct work_struct *work)
continue;
}
if (get_kset_onmedia_size(kset_onmedia) > cache_seg_remain(&key_tail)) {
atomic_inc(&cache->gc_errors);
return;
}
for (i = 0; i < kset_onmedia->key_num; i++) {
struct pcache_cache_key key_tmp = { 0 };

View File

@ -818,6 +818,11 @@ int cache_replay(struct pcache_cache *cache)
}
/* Replay the kset and check for errors. */
if (get_kset_onmedia_size(kset_onmedia) > cache_seg_remain(pos)) {
ret = -EIO;
goto out;
}
ret = kset_replay(cache, kset_onmedia);
if (ret)
goto out;

View File

@ -261,6 +261,11 @@ void cache_writeback_fn(struct work_struct *work)
goto queue_work;
}
if (get_kset_onmedia_size(kset_onmedia) > cache_seg_remain(&dirty_tail)) {
atomic_inc(&cache->writeback_errors);
goto unlock;
}
ret = cache_kset_insert_tree(cache, kset_onmedia);
if (ret) {
atomic_inc(&cache->writeback_errors);