[PATCH v2 1/4] maple_tree: remove mt_clear_meta() to fix a pointer corruption
From: Dimitris Charisis
Date: Wed Sep 16 2026 - 07:56:31 EST
mt_clear_meta() decides whether the last slot of a maple_range_64 node
holds a child pointer or a struct maple_metadata with the check
if (unlikely((mte_to_node(next) &&
mte_node_type(next))))
return; /* no metadata, could be node */
The check expects the pointer to be encoded. But the only callsite of
mt_clear_meta() is mt_destroy_walk() on the RCU destroy path, and by the
time it runs, mte_dead_leaves() has overwritten every slot on a full
node with a raw pointer, stripping the type information. Thus, the check
above never returns early for a full node as it should. It falls through
and then:
meta->gap = 0;
meta->end = 0;
zeroes two bytes of a valid child pointer. Later, mt_free_walk()
dereferences the corrupted pointer.
Fix this by removing mt_clear_meta() along with its only callsite.
mt_clear_meta() is only called for the root of each sub-tree destroyed
under RCU. Descendant nodes retain their metadata until they are freed.
RCU readers may use the metadata while traversing a node, but do not use
cleared metadata to detect that a node has been removed. They detect a
dead node via ma_dead_node().
Fixes: 2e5b4921f8ef ("maple_tree: fix freeing of nodes in rcu mode")
Signed-off-by: Dimitris Charisis <dchar@xxxxxxxxxxxxxxxxx>
---
lib/maple_tree.c | 39 ---------------------------------------
1 file changed, 39 deletions(-)
diff --git a/lib/maple_tree.c b/lib/maple_tree.c
index 1aba6cced71307245cbbca26986e14e74b35a14f..e86eee43aa0ada6963995cd74495d9344f6ccd06 100644
--- a/lib/maple_tree.c
+++ b/lib/maple_tree.c
@@ -763,43 +763,6 @@ static inline void ma_set_meta(struct maple_node *mn, enum maple_type mt,
meta->end = end;
}
-/*
- * mt_clear_meta() - clear the metadata information of a node, if it exists
- * @mt: The maple tree
- * @mn: The maple node
- * @type: The maple node type
- */
-static inline void mt_clear_meta(struct maple_tree *mt, struct maple_node *mn,
- enum maple_type type)
-{
- struct maple_metadata *meta;
- unsigned long *pivots;
- void __rcu **slots;
- void *next;
-
- switch (type) {
- case maple_range_64:
- pivots = mn->mr64.pivot;
- if (unlikely(pivots[MAPLE_RANGE64_SLOTS - 2])) {
- slots = mn->mr64.slot;
- next = mt_slot_locked(mt, slots,
- MAPLE_RANGE64_SLOTS - 1);
- if (unlikely((mte_to_node(next) &&
- mte_node_type(next))))
- return; /* no metadata, could be node */
- }
- fallthrough;
- case maple_arange_64:
- meta = ma_meta(mn, type);
- break;
- default:
- return;
- }
-
- meta->gap = 0;
- meta->end = 0;
-}
-
/*
* ma_meta_end() - Get the data end of a node from the metadata
* @mn: The maple node
@@ -4885,8 +4848,6 @@ static void mt_destroy_walk(struct maple_enode *enode, struct maple_tree *mt,
free_leaf:
if (free)
kfree(node);
- else
- mt_clear_meta(mt, node, node->type);
}
/*
--
2.47.3