Skip to content

Commit

Permalink
Fix interpreter jumps (#1471)
Browse files Browse the repository at this point in the history
* Fix interpreter jumps

* Apply comments
  • Loading branch information
LindaGuiga authored Jan 22, 2024
1 parent b8a16b3 commit 8e1969d
Showing 1 changed file with 42 additions and 28 deletions.
70 changes: 42 additions & 28 deletions evm/src/cpu/kernel/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ impl MemoryState {
}

pub(crate) struct Interpreter<'a> {
jumpdests: Vec<usize>,
pub(crate) generation_state: GenerationState<F>,
prover_inputs_map: &'a HashMap<usize, ProverInputFn>,
pub(crate) halt_offsets: Vec<usize>,
Expand Down Expand Up @@ -173,7 +172,6 @@ impl<'a> Interpreter<'a> {
prover_inputs: &'a HashMap<usize, ProverInputFn>,
) -> Self {
let mut result = Self {
jumpdests: find_jumpdests(code),
generation_state: GenerationState::new(GenerationInputs::default(), code)
.expect("Default inputs are known-good"),
prover_inputs_map: prover_inputs,
Expand Down Expand Up @@ -1020,8 +1018,6 @@ impl<'a> Interpreter<'a> {
let addr = self.pop()?;
let (context, segment, offset) = unpack_address!(addr);

// Not strictly needed but here to avoid surprises with MSIZE.
assert_ne!(segment, Segment::MainMemory, "Call KECCAK256 instead.");
let size = self.pop()?.as_usize();
let bytes = (offset..offset + size)
.map(|i| {
Expand Down Expand Up @@ -1091,13 +1087,37 @@ impl<'a> Interpreter<'a> {
self.push(syscall_info)
}

fn set_jumpdest_bit(&mut self, x: U256) -> U256 {
if self.generation_state.memory.contexts[self.context()].segments
[Segment::JumpdestBits.unscale()]
.content
.len()
> x.low_u32() as usize
{
self.generation_state.memory.get(MemoryAddress {
context: self.context(),
segment: Segment::JumpdestBits.unscale(),
virt: x.low_u32() as usize,
})
} else {
0.into()
}
}
fn run_jump(&mut self) -> anyhow::Result<(), ProgramError> {
let x = self.pop()?;

let jumpdest_bit = self.set_jumpdest_bit(x);

// Check that the destination is valid.
let x: u32 = x
.try_into()
.map_err(|_| ProgramError::InvalidJumpDestination)?;
self.jump_to(x as usize)

if !self.is_kernel() && jumpdest_bit != U256::one() {
return Err(ProgramError::InvalidJumpDestination);
}

self.jump_to(x as usize, false)
}

fn run_jumpi(&mut self) -> anyhow::Result<(), ProgramError> {
Expand All @@ -1107,9 +1127,13 @@ impl<'a> Interpreter<'a> {
let x: u32 = x
.try_into()
.map_err(|_| ProgramError::InvalidJumpiDestination)?;
self.jump_to(x as usize)?;
self.jump_to(x as usize, true)?;
}
let jumpdest_bit = self.set_jumpdest_bit(x);

if !b.is_zero() && !self.is_kernel() && jumpdest_bit != U256::one() {
return Err(ProgramError::InvalidJumpiDestination);
}
Ok(())
}

Expand All @@ -1129,14 +1153,20 @@ impl<'a> Interpreter<'a> {
Ok(())
}

fn jump_to(&mut self, offset: usize) -> anyhow::Result<(), ProgramError> {
// The JUMPDEST rule is not enforced in kernel mode.
if !self.is_kernel() && self.jumpdests.binary_search(&offset).is_err() {
return Err(ProgramError::InvalidJumpDestination);
}

fn jump_to(&mut self, offset: usize, is_jumpi: bool) -> anyhow::Result<(), ProgramError> {
self.generation_state.registers.program_counter = offset;

if offset == KERNEL.global_labels["observe_new_address"] {
let tip_u256 = stack_peek(&self.generation_state, 0)?;
let tip_h256 = H256::from_uint(&tip_u256);
let tip_h160 = H160::from(tip_h256);
self.generation_state.observe_address(tip_h160);
} else if offset == KERNEL.global_labels["observe_new_contract"] {
let tip_u256 = stack_peek(&self.generation_state, 0)?;
let tip_h256 = H256::from_uint(&tip_u256);
self.generation_state.observe_contract(tip_h256)?;
}

if self.halt_offsets.contains(&offset) {
self.running = false;
}
Expand Down Expand Up @@ -1431,22 +1461,6 @@ const SIGN_MASK: U256 = U256([
0x7fffffffffffffff,
]);

/// Return the (ordered) JUMPDEST offsets in the code.
fn find_jumpdests(code: &[u8]) -> Vec<usize> {
let mut offset = 0;
let mut res = Vec::new();
while offset < code.len() {
let opcode = code[offset];
match opcode {
0x5b => res.push(offset),
x if (0x60..0x80).contains(&x) => offset += x as usize - 0x5f, // PUSH instruction, disregard data.
_ => (),
}
offset += 1;
}
res
}

fn get_mnemonic(opcode: u8) -> &'static str {
match opcode {
0x00 => "STOP",
Expand Down

0 comments on commit 8e1969d

Please sign in to comment.