update to FnVal changes; implement basic Dlsym support and use it for getentropy

This commit is contained in:
Ralf Jung 2019-06-30 16:03:13 +02:00
parent cb09fab5ff
commit 2ca1b94e6d
6 changed files with 110 additions and 43 deletions

View file

@ -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)?;

View file

@ -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};

View file

@ -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<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<Tag, Self::AllocExtra>)>;
@ -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<PlaceTy<'tcx, Tag>>,
ret: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
ecx.call_dlsym(fn_val, args, dest, ret)
}
#[inline(always)]
fn call_intrinsic(
ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>,

49
src/shims/dlsym.rs Normal file
View file

@ -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<Dlsym> {
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<PlaceTy<'tcx, Tag>>,
ret: Option<mir::BasicBlock>,
) -> 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(())
}
}

View file

@ -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<Tag>,
) -> InterpResult<'tcx> {
if len == 0 {
// Nothing to do
return Ok(());
fn gen_random(
&mut self,
len: usize,
dest: Scalar<Tag>,
) -> 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=<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=<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)
}
}

View file

@ -1,6 +1,7 @@
pub mod foreign_items;
pub mod intrinsics;
pub mod tls;
pub mod dlsym;
use rustc::{ty, mir};