Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
more dos protection (#8104)
Browse files Browse the repository at this point in the history
  • Loading branch information
NikVolf authored and tomusdrw committed Mar 16, 2018
1 parent e6fd016 commit 5d0478b
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 42 deletions.
6 changes: 6 additions & 0 deletions ethcore/vm/src/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ pub struct WasmCosts {
pub initial_mem: u32,
/// Grow memory cost, per page (64kb)
pub grow_mem: u32,
/// Memory copy cost, per byte
pub memcpy: u32,
/// Max stack height (native WebAssembly stack limiter)
pub max_stack_height: u32,
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
pub opcodes_mul: u32,
/// Cost of wasm opcode is calculated as TABLE_ENTRY_COST * `opcodes_mul` / `opcodes_div`
Expand All @@ -153,6 +157,8 @@ impl Default for WasmCosts {
static_address: 40,
initial_mem: 4096,
grow_mem: 8192,
memcpy: 1,
max_stack_height: 64*1024,
opcodes_mul: 3,
opcodes_div: 8,
}
Expand Down
46 changes: 23 additions & 23 deletions ethcore/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ impl From<runtime::Error> for vm::Error {
}
}

enum ExecutionOutcome {
Suicide,
Return,
NotSpecial,
}

impl vm::Vm for WasmInterpreter {

fn exec(&mut self, params: ActionParams, ext: &mut vm::Ext) -> vm::Result<GasLeft> {
Expand Down Expand Up @@ -117,31 +123,25 @@ impl vm::Vm for WasmInterpreter {

let module_instance = module_instance.run_start(&mut runtime).map_err(Error)?;

match module_instance.invoke_export("call", &[], &mut runtime) {
Ok(_) => { },
Err(InterpreterError::Host(boxed)) => {
match boxed.downcast_ref::<runtime::Error>() {
None => {
return Err(vm::Error::Wasm("Invalid user error used in interpreter".to_owned()));
}
Some(runtime_err) => {
match *runtime_err {
runtime::Error::Suicide => {
// Suicide uses trap to break execution
}
ref any_err => {
trace!(target: "wasm", "Error executing contract: {:?}", boxed);
return Err(vm::Error::from(Error::from(InterpreterError::Host(Box::new(any_err.clone())))));
}
}
}
}
},
Err(err) => {
trace!(target: "wasm", "Error executing contract: {:?}", err);
return Err(vm::Error::from(Error::from(err)))
let invoke_result = module_instance.invoke_export("call", &[], &mut runtime);

let mut execution_outcome = ExecutionOutcome::NotSpecial;
if let Err(InterpreterError::Host(ref boxed)) = invoke_result {
let ref runtime_err = boxed.downcast_ref::<runtime::Error>()
.expect("Host errors other than runtime::Error never produced; qed");

match **runtime_err {
runtime::Error::Suicide => { execution_outcome = ExecutionOutcome::Suicide; },
runtime::Error::Return => { execution_outcome = ExecutionOutcome::Return; },
_ => {}
}
}

if let (ExecutionOutcome::NotSpecial, Err(e)) = (execution_outcome, invoke_result) {
trace!(target: "wasm", "Error executing contract: {:?}", e);
return Err(vm::Error::from(Error::from(e)));
}

(
runtime.gas_left().expect("Cannot fail since it was not updated since last charge"),
runtime.into_result(),
Expand Down
13 changes: 10 additions & 3 deletions ethcore/wasm/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pub enum Error {
MemoryAccessViolation,
/// Native code resulted in suicide
Suicide,
/// Native code requested execution to finish
Return,
/// Suicide was requested but coudn't complete
SuicideAbort,
/// Invalid gas state inside interpreter
Expand Down Expand Up @@ -98,6 +100,7 @@ impl ::std::fmt::Display for Error {
Error::InvalidGasState => write!(f, "Invalid gas state"),
Error::BalanceQueryError => write!(f, "Balance query resulted in an error"),
Error::Suicide => write!(f, "Suicide result"),
Error::Return => write!(f, "Return result"),
Error::Unknown => write!(f, "Unknown runtime function invoked"),
Error::AllocationFailed => write!(f, "Memory allocation failed (OOM)"),
Error::BadUtf8 => write!(f, "String encoding is bad utf-8 sequence"),
Expand Down Expand Up @@ -273,7 +276,7 @@ impl<'a> Runtime<'a> {

self.result = self.memory.get(ptr, len as usize)?;

Ok(())
Err(Error::Return)
}

/// Destroy the runtime, returning currently recorded result of the execution.
Expand Down Expand Up @@ -305,6 +308,10 @@ impl<'a> Runtime<'a> {
/// Write input bytes to the memory location using the passed pointer
fn fetch_input(&mut self, args: RuntimeArgs) -> Result<()> {
let ptr: u32 = args.nth(0)?;

let args_len = self.args.len() as u64;
self.charge(|s| args_len * s.wasm().memcpy as u64)?;

self.memory.set(ptr, &self.args[..])?;
Ok(())
}
Expand Down Expand Up @@ -525,8 +532,8 @@ impl<'a> Runtime<'a> {
fn debug(&mut self, args: RuntimeArgs) -> Result<()>
{
trace!(target: "wasm", "Contract debug message: {}", {
let msg_ptr: u32 = args.nth_checked(0)?;
let msg_len: u32 = args.nth_checked(1)?;
let msg_ptr: u32 = args.nth(0)?;
let msg_len: u32 = args.nth(1)?;

String::from_utf8(self.memory.get(msg_ptr, msg_len as usize)?)
.map_err(|_| Error::BadUtf8)?
Expand Down
32 changes: 16 additions & 16 deletions ethcore/wasm/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ fn dispersion() {
result,
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
);
assert_eq!(gas_left, U256::from(93_972));
assert_eq!(gas_left, U256::from(94_013));
}

#[test]
Expand Down Expand Up @@ -237,7 +237,7 @@ fn suicide_not() {
result,
vec![0u8]
);
assert_eq!(gas_left, U256::from(94_970));
assert_eq!(gas_left, U256::from(94_984));
}

#[test]
Expand Down Expand Up @@ -269,7 +269,7 @@ fn suicide() {
};

assert!(ext.suicides.contains(&refund));
assert_eq!(gas_left, U256::from(94_933));
assert_eq!(gas_left, U256::from(94_925));
}

#[test]
Expand Down Expand Up @@ -299,15 +299,15 @@ fn create() {
assert!(ext.calls.contains(
&FakeCall {
call_type: FakeCallType::Create,
gas: U256::from(60_917),
gas: U256::from(60_914),
sender_address: None,
receive_address: None,
value: Some(1_000_000_000.into()),
data: vec![0u8, 2, 4, 8, 16, 32, 64, 128],
code_address: None,
}
));
assert_eq!(gas_left, U256::from(60_903));
assert_eq!(gas_left, U256::from(60_900));
}

#[test]
Expand Down Expand Up @@ -467,7 +467,7 @@ fn realloc() {
}
};
assert_eq!(result, vec![0u8; 2]);
assert_eq!(gas_left, U256::from(94_352));
assert_eq!(gas_left, U256::from(94_372));
}

#[test]
Expand Down Expand Up @@ -543,7 +543,7 @@ fn keccak() {
};

assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
assert_eq!(gas_left, U256::from(84_223));
assert_eq!(gas_left, U256::from(84_240));
}

// math_* tests check the ability of wasm contract to perform big integer operations
Expand Down Expand Up @@ -572,7 +572,7 @@ fn math_add() {
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(93_818));
assert_eq!(gas_left, U256::from(93_814));
}

// multiplication
Expand All @@ -594,7 +594,7 @@ fn math_mul() {
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(93_304));
assert_eq!(gas_left, U256::from(93_300));
}

// subtraction
Expand All @@ -616,7 +616,7 @@ fn math_sub() {
U256::from_dec_str("111111111111111111111111111111").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(93_831));
assert_eq!(gas_left, U256::from(93_826));
}

// subtraction with overflow
Expand Down Expand Up @@ -658,7 +658,7 @@ fn math_div() {
U256::from_dec_str("1125000").unwrap(),
(&result[..]).into()
);
assert_eq!(gas_left, U256::from(90_607));
assert_eq!(gas_left, U256::from(90_603));
}

#[test]
Expand Down Expand Up @@ -686,7 +686,7 @@ fn storage_metering() {
};

// 0 -> not 0
assert_eq!(gas_left, U256::from(74_410));
assert_eq!(gas_left, U256::from(74_338));

// #2

Expand All @@ -705,7 +705,7 @@ fn storage_metering() {
};

// not 0 -> not 0
assert_eq!(gas_left, U256::from(89_410));
assert_eq!(gas_left, U256::from(89_338));
}

// This test checks the ability of wasm contract to invoke
Expand Down Expand Up @@ -793,7 +793,7 @@ fn externs() {
"Gas limit requested and returned does not match"
);

assert_eq!(gas_left, U256::from(92_089));
assert_eq!(gas_left, U256::from(92_110));
}

#[test]
Expand All @@ -819,7 +819,7 @@ fn embedded_keccak() {
};

assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
assert_eq!(gas_left, U256::from(84_223));
assert_eq!(gas_left, U256::from(84_240));
}

/// This test checks the correctness of log extern
Expand Down Expand Up @@ -854,5 +854,5 @@ fn events() {
assert_eq!(&log_entry.data, b"gnihtemos");

assert_eq!(&result, b"gnihtemos");
assert_eq!(gas_left, U256::from(81_235));
assert_eq!(gas_left, U256::from(81_292));
}

0 comments on commit 5d0478b

Please sign in to comment.