From fb7e6fb2808f90f77af247307f478daf6203b287 Mon Sep 17 00:00:00 2001 From: PThorpe92 Date: Tue, 26 Aug 2025 10:54:55 -0400 Subject: [PATCH] Guard against all overflow when calculating IO offsets --- core/storage/database.rs | 12 +++++++++--- sync/engine/src/database_sync_operations.rs | 10 +++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/core/storage/database.rs b/core/storage/database.rs index 11d1d107b..a08554074 100644 --- a/core/storage/database.rs +++ b/core/storage/database.rs @@ -91,7 +91,9 @@ impl DatabaseStorage for DatabaseFile { if !(512..=65536).contains(&size) || size & (size - 1) != 0 { return Err(LimboError::NotADB); } - let pos = (page_idx as u64 - 1) * size as u64; + let Some(pos) = (page_idx as u64 - 1).checked_mul(size as u64) else { + return Err(LimboError::IntegerOverflow); + }; if let Some(ctx) = io_ctx.encryption_context() { let encryption_ctx = ctx.clone(); @@ -142,7 +144,9 @@ impl DatabaseStorage for DatabaseFile { assert!(buffer_size >= 512); assert!(buffer_size <= 65536); assert_eq!(buffer_size & (buffer_size - 1), 0); - let pos = (page_idx as u64 - 1) * buffer_size as u64; + let Some(pos) = (page_idx as u64 - 1).checked_mul(buffer_size as u64) else { + return Err(LimboError::IntegerOverflow); + }; let buffer = { if let Some(ctx) = io_ctx.encryption_context() { encrypt_buffer(page_idx, buffer, ctx) @@ -166,7 +170,9 @@ impl DatabaseStorage for DatabaseFile { assert!(page_size <= 65536); assert_eq!(page_size & (page_size - 1), 0); - let pos = (first_page_idx as u64 - 1) * (page_size as u64); + let Some(pos) = (first_page_idx as u64 - 1).checked_mul(page_size as u64) else { + return Err(LimboError::IntegerOverflow); + }; let buffers = { if let Some(ctx) = io_ctx.encryption_context() { buffers diff --git a/sync/engine/src/database_sync_operations.rs b/sync/engine/src/database_sync_operations.rs index 2f7462517..5157071a0 100644 --- a/sync/engine/src/database_sync_operations.rs +++ b/sync/engine/src/database_sync_operations.rs @@ -123,7 +123,7 @@ pub async fn wal_apply_from_file( // todo(sivukhin): we need to error out in case of partial read assert!(size as usize == WAL_FRAME_SIZE); }); - let c = frames_file.pread(offset as usize, c)?; + let c = frames_file.pread(offset, c)?; while !c.is_completed() { coro.yield_(ProtocolCommand::IO).await?; } @@ -243,7 +243,7 @@ pub async fn wal_pull_to_file_v1( while !c.is_completed() { coro.yield_(ProtocolCommand::IO).await?; } - offset += WAL_FRAME_SIZE; + offset += WAL_FRAME_SIZE as u64; } let c = Completion::new_sync(move |_| { @@ -323,7 +323,7 @@ pub async fn wal_pull_to_file_legacy( coro.yield_(ProtocolCommand::IO).await?; } - last_offset += WAL_FRAME_SIZE; + last_offset += WAL_FRAME_SIZE as u64; buffer_len = 0; start_frame += 1; @@ -974,7 +974,7 @@ pub async fn bootstrap_db_file_v1( }; assert!(rc as usize == 0); }); - let c = file.truncate(header.db_size as usize * PAGE_SIZE, c)?; + let c = file.truncate(header.db_size * PAGE_SIZE as u64, c)?; while !c.is_completed() { coro.yield_(ProtocolCommand::IO).await?; } @@ -984,7 +984,7 @@ pub async fn bootstrap_db_file_v1( while let Some(page_data) = wait_proto_message::(coro, &completion, &mut bytes).await? { - let offset = page_data.page_id as usize * PAGE_SIZE; + let offset = page_data.page_id * PAGE_SIZE as u64; let page = decode_page(&header, page_data)?; if page.len() != PAGE_SIZE { return Err(Error::DatabaseSyncEngineError(format!(