提交 97ee0019 编写于 作者: Z Zhihao Cheng 提交者: Jialin Zhang

ubi: Fix UAF wear-leveling entry in eraseblk_count_seq_show()

maillist inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I6D1S7
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit?id=a240bc5c43130c6aa50831d7caaa02a1d84e1bce

--------------------------------

Wear-leveling entry could be freed in error path, which may be accessed
again in eraseblk_count_seq_show(), for example:

__erase_worker                eraseblk_count_seq_show
                                wl = ubi->lookuptbl[*block_number]
				if (wl)
  wl_entry_destroy
    ubi->lookuptbl[e->pnum] = NULL
    kmem_cache_free(ubi_wl_entry_slab, e)
		                   erase_count = wl->ec  // UAF!

Wear-leveling entry updating/accessing in ubi->lookuptbl should be
protected by ubi->wl_lock, fix it by adding ubi->wl_lock to serialize
wl entry accessing between wl_entry_destroy() and
eraseblk_count_seq_show().

Fetch a reproducer in [Link].

Link: https://bugzilla.kernel.org/show_bug.cgi?id=216305
Fixes: 7bccd12d ("ubi: Add debugfs file for tracking PEB state")
Fixes: 801c135c ("UBI: Unsorted Block Images")
Signed-off-by: NZhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: NRichard Weinberger <richard@nod.at>
Reviewed-by: NZhang Yi <yi.zhang@huawei.com>
Signed-off-by: NJialin Zhang <zhangjialin11@huawei.com>
上级 b6558a0c
...@@ -885,8 +885,11 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, ...@@ -885,8 +885,11 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
err = do_sync_erase(ubi, e1, vol_id, lnum, 0); err = do_sync_erase(ubi, e1, vol_id, lnum, 0);
if (err) { if (err) {
if (e2) if (e2) {
spin_lock(&ubi->wl_lock);
wl_entry_destroy(ubi, e2); wl_entry_destroy(ubi, e2);
spin_unlock(&ubi->wl_lock);
}
goto out_ro; goto out_ro;
} }
...@@ -1121,14 +1124,18 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk) ...@@ -1121,14 +1124,18 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)
/* Re-schedule the LEB for erasure */ /* Re-schedule the LEB for erasure */
err1 = schedule_erase(ubi, e, vol_id, lnum, 0, false); err1 = schedule_erase(ubi, e, vol_id, lnum, 0, false);
if (err1) { if (err1) {
spin_lock(&ubi->wl_lock);
wl_entry_destroy(ubi, e); wl_entry_destroy(ubi, e);
spin_unlock(&ubi->wl_lock);
err = err1; err = err1;
goto out_ro; goto out_ro;
} }
return err; return err;
} }
spin_lock(&ubi->wl_lock);
wl_entry_destroy(ubi, e); wl_entry_destroy(ubi, e);
spin_unlock(&ubi->wl_lock);
if (err != -EIO) if (err != -EIO)
/* /*
* If this is not %-EIO, we have no idea what to do. Scheduling * If this is not %-EIO, we have no idea what to do. Scheduling
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册