From 5adc269e115df8cf75e5c5a6c0ed723026189aaa Mon Sep 17 00:00:00 2001 From: Sayan Nandan Date: Thu, 8 Jul 2021 21:16:09 +0530 Subject: [PATCH] Add endian info and pointer-width check When a file created by a 64-bit system is read on a 16/32 bit system, there may be a size overflow. If so, we should do a runtime panic. --- server/src/storage/mod.rs | 100 +++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/server/src/storage/mod.rs b/server/src/storage/mod.rs index babd3a20..485333e1 100644 --- a/server/src/storage/mod.rs +++ b/server/src/storage/mod.rs @@ -44,6 +44,99 @@ modified to be endian independent. */ +/* + Endian and pointer "appendix": + We assume a fixed size of 1 for all the cases. All sizes don't hit over isize::MAX as + guaranteed by our allocation methods. Also, 32-bit to 64-bit and vice versa aren't + worth discussing here (irrespective of endianness). That's because all sizes are stored + as unsigned 64-bit integers. So, get the correct byte order, raw cast to u64, down cast + or up cast as required by the target's pointer width. + + Current limitations: + - 32-bit is compatible with 64-bit + - 16-bit is compatible with 64-bit + - But 64-bit may not be compatible with 32/16 bit due to the difference in sizes + + Additional context: + - RBIT doesn't exist on LE architectures like x86 (exclusive of fancy instructions) + + ------------------------------------------------------ + Appendix I: Same endian, different pointer width (R/W) + ------------------------------------------------------ + (1) Little endian on little endian (64-bit) + (A) Writing + In-memory size: [0, 0, 0, 0, 0, 0, 0, 1] =(u64)> [0, 0, 0, 0, 0, 0, 0, 1] (no op) + We write to file: [0, 0, 0, 0, 0, 0, 0, 1] + (B) Reading + This is read: [0, 0, 0, 0, 0, 0, 0, 1] + Raw cast =(usize)> [0, 0, 0, 0, 0, 0, 0, 1] (one memcpy) + + (2) Little endian on little endian (32-bit) + (A) Writing + In-memory size: [0, 0, 0, 1] =(u64)> [0, 0, 0, 0, 0, 0, 0, 1] (up cast) + We write to file: [0, 0, 0, 0, 0, 0, 0, 1] + (B) Reading + This is read: [0, 0, 0, 0, 0, 0, 0, 1] + Raw cast =(u64)> [0, 0, 0, 0, 0, 0, 0, 1] (one memcpy) + Lossy cast =(usize)> [0, 0, 0, 1] + + (3) Big endian on big endian (64-bit) + (A) Writing + In-memory size: [1, 0, 0, 0, 0, 0, 0, 0] =(u64)> [1, 0, 0, 0, 0, 0, 0, 0] (no op) + We write to file: [1, 0, 0, 0, 0, 0, 0, 0] + (B) Reading + This is read: [1, 0, 0, 0, 0, 0, 0, 0] + Raw cast =(usize)> [1, 0, 0, 0, 0, 0, 0, 0] (one memcpy) + + (4) Big endian (64-bit) on big endian (32-bit) + (A) Writing + In-memory size: [1, 0, 0, 0] =(u64)> [1, 0, 0, 0, 0, 0, 0, 0] (up cast) + We write to file: [1, 0, 0, 0, 0, 0, 0, 0] + (B) Reading + This is read: [1, 0, 0, 0, 0, 0, 0, 0] + Raw cast =(u64)> [1, 0, 0, 0, 0, 0, 0, 0] (one memcpy) + Lossy cast =(usize)> [1, 0, 0, 0] + + ------------------------------------------------------ + Appendix II: Different endian, same pointer width (R/W) + ------------------------------------------------------ + (1) Little endian on big endian (64-bit) + (A) Writing + ^^ See Appendix I/1/A + (B) Reading + This is read: [0, 0, 0, 0, 0, 0, 0, 1] + Raw cast =(u64)> [0, 0, 0, 0, 0, 0, 0, 1] (one memcpy) + Reverse the bits: [1, 0, 0, 0, 0, 0, 0, 0] (constant time ptr swap except for hardware instructions like RBIT) + Cast =(usize)> [1, 0, 0, 0, 0, 0, 0, 0] (no op) + + (2) Big endian on little endian (64-bit) + (A) Writing + ^^ See Appendix I/3/A + (B) Reading + This is read: [1, 0, 0, 0, 0, 0, 0, 0] + Raw cast =(u64)> [1, 0, 0, 0, 0, 0, 0, 0] (one memcpy) + Reverse the bits: [0, 0, 0, 0, 0, 0, 0, 1] (constant time ptr swap) + Cast =(usize)> [0, 0, 0, 0, 0, 0, 0, 1] (no op) + + (3) Little endian on big endian (32-bit) + (A) Writing + ^^ See Appendix I/2/A + (B) Reading + This is read: [0, 0, 0, 0, 0, 0, 0, 1] + Raw cast =(u64)> [0, 0, 0, 0, 0, 0, 0, 1] (one memcpy) + Reverse the bits: [1, 0, 0, 0, 0, 0, 0, 0] (constant time ptr swap except for hardware instructions like RBIT) + Lossy cast =(usize)> [1, 0, 0, 0] + + (4) Big endian on little endian (32-bit) + (A) Writing + ^^ See Appendix I/4/A + (B) Reading + This is read: [1, 0, 0, 0, 0, 0, 0, 0] + Raw cast =(u64)> [1, 0, 0, 0, 0, 0, 0, 0] (one memcpy) + Reverse the bits: [0, 0, 0, 0, 0, 0, 0, 1] (constant time ptr swap) + Lossy cast =(usize)> [0, 0, 0, 1] +*/ + use crate::coredb::htable::Coremap; use crate::coredb::Data; use core::mem; @@ -141,10 +234,15 @@ pub fn deserialize(data: Vec) -> Option> { unsafe fn transmute_len(start_ptr: *const u8) -> usize { // guarantee that all addresses are aligned debug_assert!((start_ptr as usize % mem::align_of::() == 0)); - #[cfg(target_pointer_width = "32")] + #[cfg(not(target_pointer_width = "64"))] return { // zero the higher bits on 32-bit let ret1: u64 = ptr::read(start_ptr.cast()); + if ret1 > isize::MAX { + // this is a backup method for us incase a giant 48-bit address is + // somehow forced to be read on this machine + panic!("RT panic: Very high size for current pointer width"); + } ret1 as usize }; #[cfg(target_pointer_width = "64")]