]> git.lizzy.rs Git - rust.git/commitdiff
miri: detect too large dynamically sized objects
authorRalf Jung <post@ralfj.de>
Tue, 27 Aug 2019 10:54:46 +0000 (12:54 +0200)
committerRalf Jung <post@ralfj.de>
Fri, 30 Aug 2019 05:44:51 +0000 (07:44 +0200)
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/traits.rs

index ac01d436bdc9b1cc4d6795e28dd23373607c590f..054b65f0e1a9edc0c8ba0da1a17b391bf895b396 100644 (file)
@@ -442,27 +442,30 @@ pub(super) fn size_and_align_of(
 
                 // Issue #27023: must add any necessary padding to `size`
                 // (to make it a multiple of `align`) before returning it.
-                //
-                // Namely, the returned size should be, in C notation:
-                //
-                //   `size + ((size & (align-1)) ? align : 0)`
-                //
-                // emulated via the semi-standard fast bit trick:
-                //
-                //   `(size + (align-1)) & -align`
-
-                Ok(Some((size.align_to(align), align)))
+                let size = size.align_to(align);
+
+                // Check if this brought us over the size limit.
+                if size.bytes() >= self.tcx.data_layout().obj_size_bound() {
+                    throw_ub_format!("wide pointer metadata contains invalid information: \
+                        total size is bigger than largest supported object");
+                }
+                Ok(Some((size, align)))
             }
             ty::Dynamic(..) => {
                 let vtable = metadata.expect("dyn trait fat ptr must have vtable");
-                // the second entry in the vtable is the dynamic size of the object.
+                // Read size and align from vtable (already checks size).
                 Ok(Some(self.read_size_and_align_from_vtable(vtable)?))
             }
 
             ty::Slice(_) | ty::Str => {
                 let len = metadata.expect("slice fat ptr must have vtable").to_usize(self)?;
                 let elem = layout.field(self, 0)?;
-                Ok(Some((elem.size * len, elem.align.abi)))
+
+                // Make sure the slice is not too big.
+                let size = elem.size.checked_mul(len, &*self.tcx)
+                    .ok_or_else(|| err_ub_format!("invalid slice: \
+                        total size is bigger than largest supported object"))?;
+                Ok(Some((size, elem.align.abi)))
             }
 
             ty::Foreign(_) => {
index 34a10de7de7fc045e130c0a899de01b1e8cf8c8a..10b767ebba191174fa663f9192a8f9c980641646 100644 (file)
@@ -1,5 +1,5 @@
 use rustc::ty::{self, Ty, Instance, TypeFoldable};
-use rustc::ty::layout::{Size, Align, LayoutOf};
+use rustc::ty::layout::{Size, Align, LayoutOf, HasDataLayout};
 use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,};
 
 use super::{InterpCx, Machine, MemoryKind, FnVal};
@@ -151,6 +151,11 @@ pub fn read_size_and_align_from_vtable(
             vtable.offset(pointer_size * 2, self)?,
         )?.not_undef()?;
         let align = self.force_bits(align, pointer_size)? as u64;
+
+        if size >= self.tcx.data_layout().obj_size_bound() {
+            throw_ub_format!("invalid vtable: \
+                size is bigger than largest supported object");
+        }
         Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap()))
     }
 }