From fb30958afb9fd9c3e44047332080d0c713e73160 Mon Sep 17 00:00:00 2001 From: Chengke Wang Date: Sun, 27 Nov 2022 20:40:50 +0800 Subject: [PATCH] mm: fix hyperhold zlist bug ohos inclusion category: bugfix issue: #I63M0I CVE: NA -------------------------------- Fix hyperhold zlist double free bug. In concurrent state insert and delete obj maybe result in multiple free eid. Signed-off-by: Ke Liu --- .../block/zram/zram_group/group_writeback.c | 6 +++ drivers/block/zram/zram_group/zlist.c | 14 ++++-- drivers/block/zram/zram_group/zlist.h | 11 ++-- drivers/block/zram/zram_group/zram_group.c | 50 ++++++++++++++++++- drivers/block/zram/zram_group/zram_group.h | 2 + 5 files changed, 73 insertions(+), 10 deletions(-) diff --git a/drivers/block/zram/zram_group/group_writeback.c b/drivers/block/zram/zram_group/group_writeback.c index ceeb5cf4321d..34f7ca616587 100644 --- a/drivers/block/zram/zram_group/group_writeback.c +++ b/drivers/block/zram/zram_group/group_writeback.c @@ -280,12 +280,18 @@ static u64 write_one_extent(struct zram *zram, u16 gid) if (!hpio) goto free_extent; + zgrp_get_ext(zram->zgrp, eid); size = collect_objs(zram, gid, hpio, hyperhold_extent_size(eid)); if (size == 0) { pr_err("group %u has no data in zram.\n", gid); + zgrp_put_ext(zram->zgrp, eid); goto put_hpio; } zgrp_ext_insert(zram->zgrp, eid, gid); + if (zgrp_put_ext(zram->zgrp, eid)) { + zgrp_ext_delete(zram->zgrp, eid, gid); + hyperhold_should_free_extent(eid); + } ret = hyperhold_write_async(hpio, write_endio, priv); if (ret) diff --git a/drivers/block/zram/zram_group/zlist.c b/drivers/block/zram/zram_group/zlist.c index d1fe60875949..fd8295ecadaa 100644 --- a/drivers/block/zram/zram_group/zlist.c +++ b/drivers/block/zram/zram_group/zlist.c @@ -205,14 +205,22 @@ bool zlist_set_priv(u32 idx, struct zlist_table *tab) return ret; } -bool zlist_clr_priv(u32 idx, struct zlist_table *tab) +bool zlist_clr_priv_nolock(u32 idx, struct zlist_table *tab) { struct zlist_node *node = idx2node(idx, tab); bool ret = false; - zlist_node_lock(node); ret = !test_and_clear_bit(ZLIST_PRIV_BIT, (unsigned long *)node); - zlist_node_unlock(node); + + return ret; +} + +bool zlist_test_priv_nolock(u32 idx, struct zlist_table *tab) +{ + struct zlist_node *node = idx2node(idx, tab); + bool ret = false; + + ret = test_bit(ZLIST_PRIV_BIT, (unsigned long *)node); return ret; } diff --git a/drivers/block/zram/zram_group/zlist.h b/drivers/block/zram/zram_group/zlist.h index 9509e3b674ca..a7cbf37509e9 100644 --- a/drivers/block/zram/zram_group/zlist.h +++ b/drivers/block/zram/zram_group/zlist.h @@ -15,10 +15,10 @@ #define ZLIST_IDX_MAX (1 << ZLIST_IDX_SHIFT) struct zlist_node { - u32 prev : ZLIST_IDX_SHIFT; - u32 lock : 1; - u32 next : ZLIST_IDX_SHIFT; - u32 priv : 1; + u64 prev : ZLIST_IDX_SHIFT; + u64 lock : 1; + u64 next : ZLIST_IDX_SHIFT; + u64 priv : 1; }; struct zlist_table { @@ -83,7 +83,8 @@ static inline bool zlist_del(u32 hid, u32 idx, struct zlist_table *tab) } bool zlist_set_priv(u32 idx, struct zlist_table *tab); -bool zlist_clr_priv(u32 idx, struct zlist_table *tab); +bool zlist_clr_priv_nolock(u32 idx, struct zlist_table *tab); +bool zlist_test_priv_nolock(u32 idx, struct zlist_table *tab); void zlist_node_init(u32 idx, struct zlist_table *tab); diff --git a/drivers/block/zram/zram_group/zram_group.c b/drivers/block/zram/zram_group/zram_group.c index 85c7f00b4b7e..9a023e77d5cd 100644 --- a/drivers/block/zram/zram_group/zram_group.c +++ b/drivers/block/zram/zram_group/zram_group.c @@ -489,6 +489,45 @@ u32 zgrp_isolate_exts(struct zram_group *zgrp, u16 gid, u32 *eids, u32 nr, bool return cnt; } +void zgrp_get_ext(struct zram_group *zgrp, u32 eid) +{ + u32 hid; + + if (!CHECK(zgrp, "zram group is not enable!\n")) + return; + if (!CHECK(zgrp->wbgrp.enable, "zram group writeback is not enable!\n")) + return; + if (!CHECK_BOUND(eid, 0, zgrp->wbgrp.nr_ext - 1)) + return; + + hid = eid + zgrp->nr_obj + zgrp->nr_grp; + zlist_set_priv(hid, zgrp->obj_tab); + pr_info("get extent %u\n", eid); +} + +bool zgrp_put_ext(struct zram_group *zgrp, u32 eid) +{ + u32 hid; + bool ret = false; + + if (!CHECK(zgrp, "zram group is not enable!\n")) + return false; + if (!CHECK(zgrp->wbgrp.enable, "zram group writeback is not enable!\n")) + return false; + if (!CHECK_BOUND(eid, 0, zgrp->wbgrp.nr_ext - 1)) + return false; + + hid = eid + zgrp->nr_obj + zgrp->nr_grp; + zlist_lock(hid, zgrp->obj_tab); + zlist_clr_priv_nolock(hid, zgrp->obj_tab); + ret = zlist_is_isolated_nolock(hid, zgrp->obj_tab); + zlist_unlock(hid, zgrp->obj_tab); + + pr_info("put extent %u, ret = %d\n", eid, ret); + + return ret; +} + /* * insert obj at @index into extent @eid */ @@ -517,6 +556,7 @@ void wbgrp_obj_insert(struct zram_group *zgrp, u32 index, u32 eid) bool wbgrp_obj_delete(struct zram_group *zgrp, u32 index, u32 eid) { u32 hid; + bool ret = false; if (!zgrp) { pr_debug("zram group is not enable!"); @@ -531,7 +571,12 @@ bool wbgrp_obj_delete(struct zram_group *zgrp, u32 index, u32 eid) pr_debug("delete obj %u from extent %u\n", index, eid); hid = eid + zgrp->nr_obj + zgrp->nr_grp; - return zlist_del(hid, index, zgrp->obj_tab); + zlist_lock(hid, zgrp->obj_tab); + ret = zlist_del_nolock(hid, index, zgrp->obj_tab) + && !zlist_test_priv_nolock(hid, zgrp->obj_tab); + zlist_unlock(hid, zgrp->obj_tab); + + return ret; } /* @@ -567,7 +612,8 @@ u32 wbgrp_isolate_objs(struct zram_group *zgrp, u32 eid, u32 *idxs, u32 nr, bool for (i = 0; i < cnt; i++) zlist_del_nolock(hid, idxs[i], zgrp->obj_tab); if (last) - *last = cnt && zlist_is_isolated_nolock(hid, zgrp->obj_tab); + *last = cnt && zlist_is_isolated_nolock(hid, zgrp->obj_tab) + && !zlist_test_priv_nolock(hid, zgrp->obj_tab); zlist_unlock(hid, zgrp->obj_tab); pr_debug("isolated %u objs from extent %u.\n", cnt, eid); diff --git a/drivers/block/zram/zram_group/zram_group.h b/drivers/block/zram/zram_group/zram_group.h index 7ac16ba87703..9b184b7bda77 100644 --- a/drivers/block/zram/zram_group/zram_group.h +++ b/drivers/block/zram/zram_group/zram_group.h @@ -86,6 +86,8 @@ int zram_group_apply_writeback(struct zram_group *zgrp, u32 nr_ext); void zgrp_ext_insert(struct zram_group *zgrp, u32 eid, u16 gid); bool zgrp_ext_delete(struct zram_group *zgrp, u32 eid, u16 gid); u32 zgrp_isolate_exts(struct zram_group *zgrp, u16 gid, u32 *eids, u32 nr, bool *last); +void zgrp_get_ext(struct zram_group *zgrp, u32 eid); +bool zgrp_put_ext(struct zram_group *zgrp, u32 eid); void wbgrp_obj_insert(struct zram_group *zgrp, u32 index, u32 eid); bool wbgrp_obj_delete(struct zram_group *zgrp, u32 index, u32 eid); u32 wbgrp_isolate_objs(struct zram_group *zgrp, u32 eid, u32 *idxs, u32 nr, bool *last); -- Gitee