| From: Peng Zhang <zhangpeng.00@bytedance.com> |
| Subject: maple_tree: fix a potential concurrency bug in RCU mode |
| Date: Tue, 14 Mar 2023 20:42:03 +0800 |
| |
| There is a concurrency bug that may cause the wrong value to be loaded |
| when a CPU is modifying the maple tree. |
| |
| CPU1: |
| mtree_insert_range() |
| mas_insert() |
| mas_store_root() |
| ... |
| mas_root_expand() |
| ... |
| rcu_assign_pointer(mas->tree->ma_root, mte_mk_root(mas->node)); |
| ma_set_meta(node, maple_leaf_64, 0, slot); <---IP |
| |
| CPU2: |
| mtree_load() |
| mtree_lookup_walk() |
| ma_data_end(); |
| |
| When CPU1 is about to execute the instruction pointed to by IP, the |
| ma_data_end() executed by CPU2 may return the wrong end position, which |
| will cause the value loaded by mtree_load() to be wrong. |
| |
| An example of triggering the bug: |
| |
| Add mdelay(100) between rcu_assign_pointer() and ma_set_meta() in |
| mas_root_expand(). |
| |
| static DEFINE_MTREE(tree); |
| int work(void *p) { |
| unsigned long val; |
| for (int i = 0 ; i< 30; ++i) { |
| val = (unsigned long)mtree_load(&tree, 8); |
| mdelay(5); |
| pr_info("%lu",val); |
| } |
| return 0; |
| } |
| |
| mt_init_flags(&tree, MT_FLAGS_USE_RCU); |
| mtree_insert(&tree, 0, (void*)12345, GFP_KERNEL); |
| run_thread(work) |
| mtree_insert(&tree, 1, (void*)56789, GFP_KERNEL); |
| |
| In RCU mode, mtree_load() should always return the value before or after |
| the data structure is modified, and in this example mtree_load(&tree, 8) |
| may return 56789 which is not expected, it should always return NULL. Fix |
| it by put ma_set_meta() before rcu_assign_pointer(). |
| |
| Link: https://lkml.kernel.org/r/20230314124203.91572-4-zhangpeng.00@bytedance.com |
| Fixes: 54a611b60590 ("Maple Tree: add new data structure") |
| Signed-off-by: Peng Zhang <zhangpeng.00@bytedance.com> |
| Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com> |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| lib/maple_tree.c | 3 +-- |
| 1 file changed, 1 insertion(+), 2 deletions(-) |
| |
| --- a/lib/maple_tree.c~maple_tree-fix-a-potential-concurrency-bug-in-rcu-mode |
| +++ a/lib/maple_tree.c |
| @@ -3725,10 +3725,9 @@ static inline int mas_root_expand(struct |
| slot++; |
| mas->depth = 1; |
| mas_set_height(mas); |
| - |
| + ma_set_meta(node, maple_leaf_64, 0, slot); |
| /* swap the new root into the tree */ |
| rcu_assign_pointer(mas->tree->ma_root, mte_mk_root(mas->node)); |
| - ma_set_meta(node, maple_leaf_64, 0, slot); |
| return slot; |
| } |
| |
| _ |