summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJianyun Gao <jianyungao89@gmail.com>2026-07-20 11:36:32 +0800
committerMikulas Patocka <mpatocka@redhat.com>2026-07-20 15:37:46 +0200
commitc2e894eac398b258f12fdec73ed6ba081047f7b3 (patch)
tree3c80a696828d15aa659dd16ca96909b79957850f
parentfb9e17287a4ea1cbbcedc77e6866978ecc2a7b55 (diff)
dm-pcache: fix use-after-free and invalid seg operations in kset_replay()
In kset_replay, when key->seg_gen is stale (key->seg_gen < key->cache_pos.cache_seg->gen), cache_key_put(key) is called but then key->cache_pos.cache_seg is accessed as the argument to cache_seg_get(). This is a use-after-free on the freed key memory. Although mempool recycled memory is not immediately reclaimed or overwritten in practice, this is still a potential UAF bug. Additionally, for expired invalid keys, setting the cache->seg_map bit and calling cache_seg_get() is unreasonable since the corresponding segment data is no longer valid. Fix both issues by moving cache_seg_get() and __set_bit() after the gen check, so they only execute for valid keys, and using continue to skip invalid keys. Cc: stable@vger.kernel.org Fixes: 1d57628ff95b ("dm-pcache: add persistent cache target in device-mapper") Signed-off-by: Jianyun Gao <jianyungao89@gmail.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
-rw-r--r--drivers/md/dm-pcache/cache_key.c13
1 files changed, 6 insertions, 7 deletions
diff --git a/drivers/md/dm-pcache/cache_key.c b/drivers/md/dm-pcache/cache_key.c
index 1caea11a61a3..9e1808eeee85 100644
--- a/drivers/md/dm-pcache/cache_key.c
+++ b/drivers/md/dm-pcache/cache_key.c
@@ -751,18 +751,17 @@ static int kset_replay(struct pcache_cache *cache, struct pcache_cache_kset_onme
goto err;
}
- __set_bit(key->cache_pos.cache_seg->cache_seg_id, cache->seg_map);
-
/* Check if the segment generation is valid for insertion. */
if (key->seg_gen < key->cache_pos.cache_seg->gen) {
cache_key_put(key);
- } else {
- cache_subtree = get_subtree(&cache->req_key_tree, key->off);
- spin_lock(&cache_subtree->tree_lock);
- cache_key_insert(&cache->req_key_tree, key, true);
- spin_unlock(&cache_subtree->tree_lock);
+ continue;
}
+ __set_bit(key->cache_pos.cache_seg->cache_seg_id, cache->seg_map);
+ cache_subtree = get_subtree(&cache->req_key_tree, key->off);
+ spin_lock(&cache_subtree->tree_lock);
+ cache_key_insert(&cache->req_key_tree, key, true);
+ spin_unlock(&cache_subtree->tree_lock);
cache_seg_get(key->cache_pos.cache_seg);
}