From 02a9ca804a40968e57a7f0d51e23c14ebcc025c8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 4 Oct 2022 12:59:23 -0700 Subject: [PATCH 1/2] Check for isize overflow before Layout construction --- src/identifier.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/identifier.rs b/src/identifier.rs index fbe1df02..9c2bdbd7 100644 --- a/src/identifier.rs +++ b/src/identifier.rs @@ -103,6 +103,7 @@ impl Identifier { // SAFETY: string must be ASCII and not contain \0 bytes. pub(crate) unsafe fn new_unchecked(string: &str) -> Self { let len = string.len(); + debug_assert!(len <= isize::MAX as usize); match len as u64 { 0 => Self::empty(), 1..=8 => { @@ -118,8 +119,21 @@ impl Identifier { // SAFETY: len is in a range that does not contain 0. let size = bytes_for_varint(unsafe { NonZeroUsize::new_unchecked(len) }) + len; let align = 2; + // On 32-bit and 16-bit architecture, check for size overflowing + // isize::MAX. Making an allocation request bigger than this to + // the allocator is considered UB. All allocations (including + // static ones) are limited to isize::MAX so we're guaranteed + // len <= isize::MAX, and we know bytes_for_varint(len) <= 5 + // because 128**5 > isize::MAX, which means the only problem + // that can arise is when isize::MAX - 5 <= len <= isize::MAX. + // This is pretty much guaranteed to be malicious input so we + // don't need to care about returning a good error message. + if mem::size_of::() < 8 { + let max_alloc = usize::MAX / 2 - align; + assert!(size <= max_alloc); + } // SAFETY: align is not zero, align is a power of two, and - // rounding size up to align does not overflow usize::MAX. + // rounding size up to align does not overflow isize::MAX. let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; // SAFETY: layout's size is nonzero. let ptr = unsafe { alloc(layout) }; @@ -200,7 +214,7 @@ impl Clone for Identifier { let size = bytes_for_varint(len) + len.get(); let align = 2; // SAFETY: align is not zero, align is a power of two, and rounding - // size up to align does not overflow usize::MAX. This is just + // size up to align does not overflow isize::MAX. This is just // duplicating a previous allocation where all of these guarantees // were already made. let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; From 6b0af67c50aee569c1b715ff81cd8d1211ede0b1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 4 Oct 2022 13:56:13 -0700 Subject: [PATCH 2/2] Restore compatibility with rustc older than 1.43 error[E0599]: no associated item named `MAX` found for type `isize` in the current scope --> src/identifier.rs:106:37 | 106 | debug_assert!(len <= isize::MAX as usize); | ^^^ associated item not found in `isize` | help: you are looking for the module in `std`, not the primitive type | 106 | debug_assert!(len <= std::isize::MAX as usize); | ^^^^^^^^^^^^^^^ error[E0599]: no associated item named `MAX` found for type `usize` in the current scope --> src/identifier.rs:132:44 | 132 | let max_alloc = usize::MAX / 2 - align; | ^^^ associated item not found in `usize` | help: you are looking for the module in `std`, not the primitive type | 132 | let max_alloc = std::usize::MAX / 2 - align; | ^^^^^^^^^^^^^^^ --- src/identifier.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/identifier.rs b/src/identifier.rs index 9c2bdbd7..0273ae62 100644 --- a/src/identifier.rs +++ b/src/identifier.rs @@ -67,11 +67,13 @@ // allows size_of::() == size_of::>(). use crate::alloc::alloc::{alloc, dealloc, handle_alloc_error, Layout}; +use core::isize; use core::mem; use core::num::{NonZeroU64, NonZeroUsize}; use core::ptr::{self, NonNull}; use core::slice; use core::str; +use core::usize; const PTR_BYTES: usize = mem::size_of::>();