From 99df69f6032eec7f437dabf26324a5599871fe08 Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Thu, 10 Jul 2025 18:23:54 +0300 Subject: [PATCH] btree/balance/validation: fix use-after-free of rightmost ptr validation We can use `right_page_id` directly to perform the validation instead of carrying a raw pointer around which might be invalidated by the time we do the validation. --- core/storage/btree.rs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/core/storage/btree.rs b/core/storage/btree.rs index 4b69cde6f..b7dffedaa 100644 --- a/core/storage/btree.rs +++ b/core/storage/btree.rs @@ -3232,7 +3232,7 @@ impl BTreeCursor { is_table_leaf, cells_debug, sibling_count_new, - rightmost_pointer, + right_page_id, ); // We have to free pages that are not used anymore @@ -3303,7 +3303,7 @@ impl BTreeCursor { leaf_data: bool, mut cells_debug: Vec>, sibling_count_new: usize, - rightmost_pointer: &mut [u8], + right_page_id: u32, ) { let mut valid = true; let mut current_index_cell = 0; @@ -3416,7 +3416,6 @@ impl BTreeCursor { if sibling_count_new == 0 { // Balance-shallower case // We need to check data in parent page - let rightmost = read_u32(rightmost_pointer, 0); debug_validate_cells!(parent_contents, self.usable_space() as u16); if pages_to_balance_new[0].is_none() { @@ -3455,32 +3454,32 @@ impl BTreeCursor { valid = false; } - if rightmost == page.get().id as u32 - || rightmost == parent_page.get().get().id as u32 + if right_page_id == page.get().id as u32 + || right_page_id == parent_page.get().get().id as u32 { tracing::error!("balance_non_root(balance_shallower_rightmost_pointer, page_id={}, parent_page_id={}, rightmost={})", page.get().id, parent_page.get().get().id, - rightmost, + right_page_id, ); valid = false; } if let Some(rm) = contents.rightmost_pointer() { - if rm != rightmost { + if rm != right_page_id { tracing::error!("balance_non_root(balance_shallower_rightmost_pointer, page_rightmost={}, rightmost={})", rm, - rightmost, + right_page_id, ); valid = false; } } if let Some(rm) = parent_contents.rightmost_pointer() { - if rm != rightmost { + if rm != right_page_id { tracing::error!("balance_non_root(balance_shallower_rightmost_pointer, parent_rightmost={}, rightmost={})", rm, - rightmost, + right_page_id, ); valid = false; } @@ -3521,15 +3520,14 @@ impl BTreeCursor { // We will only validate rightmost pointer of parent page, we will not validate rightmost if it's a cell and not the last pointer because, // insert cell could've defragmented the page and invalidated the pointer. // right pointer, we just check right pointer points to this page. - if cell_divider_idx == parent_contents.cell_count() { - let rightmost = read_u32(rightmost_pointer, 0); - if rightmost != page.get().id as u32 { - tracing::error!("balance_non_root(cell_divider_right_pointer, should point to {}, but points to {})", + if cell_divider_idx == parent_contents.cell_count() + && right_page_id != page.get().id as u32 + { + tracing::error!("balance_non_root(cell_divider_right_pointer, should point to {}, but points to {})", page.get().id, - rightmost + right_page_id ); - valid = false; - } + valid = false; } } else { // divider cell might be an overflow cell