提交 13a09ade 编写于 作者: Z Zhiqiang Liu 提交者: Yang Yingliang

bcache: fix potential deadlock problem in btree_gc_coalesce

hulk inclusion
category: bugfix
bugzilla: 13690
CVE: CVE-2020-12771

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

coccicheck reports:
  drivers/md//bcache/btree.c:1538:1-7: preceding lock on line 1417

btree_gc_coalesce func is designed to coalesce two adjacent nodes in
new_nodes[GC_MERGE_NODES] and finally release one node. All nodes`write_lock,
new_nodes[i]->write_lock, are holded before coalescing adjacent nodes,
and them will be released after coalescing successfully.

However, if the coalescing process fails, such as no enough space of new_nodes[1]
to fit all of the remaining keys in new_nodes[0] and realloc keylist failed, we
will goto to out_nocoalesce tag directly without releasing new_nodes[i]->write_lock.
Then, a deadlock will occur after calling btree_node_free to free new_nodes[i],
which also try to acquire new_nodes[i]->write_lock.

Here, we add a new tag 'out_unlock_nocoalesce' before out_nocoalesce tag to release
new_nodes[i]->write_lock when coalescing process fails.

Fixes: 2a285686 ("bcache: btree locking rework")
Signed-off-by: NZhiqiang Liu <liuzhiqiang26@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Reviewed-by: NJason Yan <yanaijie@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 97fd0dd5
...@@ -1432,7 +1432,7 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op, ...@@ -1432,7 +1432,7 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
if (__set_blocks(n1, n1->keys + n2->keys, if (__set_blocks(n1, n1->keys + n2->keys,
block_bytes(b->c)) > block_bytes(b->c)) >
btree_blocks(new_nodes[i])) btree_blocks(new_nodes[i]))
goto out_nocoalesce; goto out_unlock_nocoalesce;
keys = n2->keys; keys = n2->keys;
/* Take the key of the node we're getting rid of */ /* Take the key of the node we're getting rid of */
...@@ -1461,7 +1461,7 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op, ...@@ -1461,7 +1461,7 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
if (__bch_keylist_realloc(&keylist, if (__bch_keylist_realloc(&keylist,
bkey_u64s(&new_nodes[i]->key))) bkey_u64s(&new_nodes[i]->key)))
goto out_nocoalesce; goto out_unlock_nocoalesce;
bch_btree_node_write(new_nodes[i], &cl); bch_btree_node_write(new_nodes[i], &cl);
bch_keylist_add(&keylist, &new_nodes[i]->key); bch_keylist_add(&keylist, &new_nodes[i]->key);
...@@ -1507,6 +1507,10 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op, ...@@ -1507,6 +1507,10 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
/* Invalidated our iterator */ /* Invalidated our iterator */
return -EINTR; return -EINTR;
out_unlock_nocoalesce:
for (i = 0; i < nodes; i++)
mutex_unlock(&new_nodes[i]->write_lock);
out_nocoalesce: out_nocoalesce:
closure_sync(&cl); closure_sync(&cl);
bch_keylist_free(&keylist); bch_keylist_free(&keylist);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册