From 2ca1b94e6d7e1a078b7fcef9a10e2ed07145e1bd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:03:13 +0200 Subject: [PATCH] update to FnVal changes; implement basic Dlsym support and use it for getentropy --- src/eval.rs | 4 +- src/lib.rs | 1 + src/machine.rs | 13 +++++- src/shims/dlsym.rs | 49 ++++++++++++++++++++++ src/shims/foreign_items.rs | 85 ++++++++++++++++++++------------------ src/shims/mod.rs | 1 + 6 files changed, 110 insertions(+), 43 deletions(-) create mode 100644 src/shims/dlsym.rs diff --git a/src/eval.rs b/src/eval.rs index 6132c502531f..bf99d3e61166 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -11,7 +11,7 @@ use rustc::mir; use crate::{ InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, - Scalar, Tag, Pointer, + Scalar, Tag, Pointer, FnVal, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, }; @@ -93,7 +93,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut args = ecx.frame().body.args_iter(); // First argument: pointer to `main()`. - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); + let main_ptr = ecx.memory_mut().create_fn_alloc(FnVal::Instance(main_instance)); let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; diff --git a/src/lib.rs b/src/lib.rs index 31e707077769..295c8e519e13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ pub use crate::shims::{EvalContextExt as ShimsEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; +pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/machine.rs b/src/machine.rs index 0875331131bd..77e02dba266a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -135,6 +135,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryExtra = MemoryExtra; type AllocExtra = AllocExtra; type PointerTag = Tag; + type ExtraFnVal = Dlsym; type MemoryMap = MonoHashMap, Allocation)>; @@ -145,7 +146,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.memory().extra.validate } - /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, @@ -157,6 +157,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.find_fn(instance, args, dest, ret) } + #[inline(always)] + fn call_extra_fn( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + fn_val: Dlsym, + args: &[OpTy<'tcx, Tag>], + dest: Option>, + ret: Option, + ) -> InterpResult<'tcx> { + ecx.call_dlsym(fn_val, args, dest, ret) + } + #[inline(always)] fn call_intrinsic( ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs new file mode 100644 index 000000000000..1c2567b951ca --- /dev/null +++ b/src/shims/dlsym.rs @@ -0,0 +1,49 @@ +use rustc::mir; + +use crate::*; + +#[derive(Debug, Copy, Clone)] +pub enum Dlsym { + GetEntropy, +} + +impl Dlsym { + pub fn from_str(name: &str) -> Option { + use self::Dlsym::*; + Some(match name { + "getentropy" => GetEntropy, + _ => return None, + }) + } +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + args: &[OpTy<'tcx, Tag>], + dest: Option>, + ret: Option, + ) -> InterpResult<'tcx> { + use self::Dlsym::*; + + let this = self.eval_context_mut(); + + let dest = dest.expect("we don't support any diverging dlsym"); + let ret = ret.expect("dest is `Some` but ret is `None`"); + + match dlsym { + GetEntropy => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let len = this.read_scalar(args[1])?.to_usize(this)?; + this.gen_random(len as usize, ptr)?; + this.write_null(dest)?; + } + } + + this.goto_block(Some(ret))?; + this.dump_place(*dest); + Ok(()) + } +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2fe2ecc19581..fb1d08d0bc20 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -307,7 +307,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // neither of which have any effect on our current PRNG let _flags = this.read_scalar(args[3])?.to_i32()?; - gen_random(this, len as usize, ptr)?; + this.gen_random(len as usize, ptr)?; this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { @@ -324,10 +324,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); - return err!(Unimplemented(format!( - "miri does not support dynamically loading libraries (requested symbol: {})", - symbol_name - ))); + if let Some(dlsym) = Dlsym::from_str(symbol_name) { + let ptr = this.memory_mut().create_fn_alloc(FnVal::Other(dlsym)); + this.write_scalar(Scalar::from(ptr), dest)?; + } else { + return err!(Unimplemented(format!( + "Unsupported dlsym: {}", symbol_name + ))); + } } "__rust_maybe_catch_panic" => { @@ -340,7 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We abort on panic, so not much is going on here, but we still have to call the closure. let f = this.read_scalar(args[0])?.to_ptr()?; let data = this.read_scalar(args[1])?.not_undef()?; - let f_instance = this.memory().get_fn(f)?; + let f_instance = this.memory().get_fn(f)?.as_instance()?; this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); @@ -659,7 +663,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { - Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr.to_ptr()?)?), + Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?.as_instance()?), None => None, }; @@ -766,7 +770,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; - gen_random(this, len as usize, ptr)?; + this.gen_random(len as usize, ptr)?; this.write_null(dest)?; } @@ -934,7 +938,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SystemFunction036" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_u32()?; - gen_random(this, len as usize, ptr)?; + this.gen_random(len as usize, ptr)?; this.write_scalar(Scalar::from_bool(true), dest)?; } @@ -966,36 +970,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } -} -fn gen_random<'mir, 'tcx>( - this: &mut MiriEvalContext<'mir, 'tcx>, - len: usize, - dest: Scalar, -) -> InterpResult<'tcx> { - if len == 0 { - // Nothing to do - return Ok(()); + fn gen_random( + &mut self, + len: usize, + dest: Scalar, + ) -> InterpResult<'tcx> { + if len == 0 { + // Nothing to do + return Ok(()); + } + let this = self.eval_context_mut(); + let ptr = dest.to_ptr()?; + + let data = match &mut this.memory_mut().extra.rng { + Some(rng) => { + let mut rng = rng.borrow_mut(); + let mut data = vec![0; len]; + rng.fill_bytes(&mut data); + data + } + None => { + return err!(Unimplemented( + "miri does not support gathering system entropy in deterministic mode! + Use '-Zmiri-seed=' to enable random number generation. + WARNING: Miri does *not* generate cryptographically secure entropy - + do not use Miri to run any program that needs secure random number generation".to_owned(), + )); + } + }; + let tcx = &{this.tcx.tcx}; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data) } - let ptr = dest.to_ptr()?; - - let data = match &mut this.memory_mut().extra.rng { - Some(rng) => { - let mut rng = rng.borrow_mut(); - let mut data = vec![0; len]; - rng.fill_bytes(&mut data); - data - } - None => { - return err!(Unimplemented( - "miri does not support gathering system entropy in deterministic mode! - Use '-Zmiri-seed=' to enable random number generation. - WARNING: Miri does *not* generate cryptographically secure entropy - - do not use Miri to run any program that needs secure random number generation".to_owned(), - )); - } - }; - let tcx = &{this.tcx.tcx}; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data) -} +} \ No newline at end of file diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 3258cf3d9c1d..c06373005ff9 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,6 +1,7 @@ pub mod foreign_items; pub mod intrinsics; pub mod tls; +pub mod dlsym; use rustc::{ty, mir};