From f5dd7df296affcb1bfccf4f62a8c086fa1c9acbf Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Fri, 2 Aug 2024 13:24:45 +1000 Subject: [PATCH] read: validate DW_OP_deref_size when evaluating (#739) We document that the size field of EvaluationResult::RequiresMemory will be at most the word size of the target, so we should check that. --- src/read/mod.rs | 5 +++++ src/read/op.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/read/mod.rs b/src/read/mod.rs index e90d4239..5c2b6cc8 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -383,6 +383,8 @@ pub enum Error { UnsupportedTypeOperation, /// The shift value in an expression must be a non-negative integer. InvalidShiftExpression, + /// The size of a deref expression must not be larger than the size of an address. + InvalidDerefSize(u8), /// An unknown DW_CFA_* instruction. UnknownCallFrameInstruction(constants::DwCfa), /// The end of an address range was before the beginning. @@ -545,6 +547,9 @@ impl Error { Error::InvalidShiftExpression => { "The shift value in an expression must be a non-negative integer." } + Error::InvalidDerefSize(_) => { + "The size of a deref expression must not be larger than the size of an address." + } Error::UnknownCallFrameInstruction(_) => "An unknown DW_CFA_* instructiion", Error::InvalidAddressRange => { "The end of an address range must not be before the beginning." diff --git a/src/read/op.rs b/src/read/op.rs index 42d3cee8..0f9261a0 100644 --- a/src/read/op.rs +++ b/src/read/op.rs @@ -1243,6 +1243,9 @@ impl> Evaluation { size, space, } => { + if size > self.encoding.address_size { + return Err(Error::InvalidDerefSize(size)); + } let entry = self.pop()?; let addr = entry.to_u64(self.addr_mask)?; let addr_space = if space { @@ -3507,6 +3510,46 @@ mod tests { Ok(result) }, ); + + #[rustfmt::skip] + let program = [ + Op(DW_OP_addr), U32(0x7fff_ffff), + Op(DW_OP_deref_size), U8(8), + ]; + check_eval_with_args( + &program, + Err(Error::InvalidDerefSize(8)), + encoding4(), + None, + None, + None, + |eval, mut result| { + while result != EvaluationResult::Complete { + result = match result { + EvaluationResult::RequiresMemory { + address, + size, + space, + base_type, + } => { + assert_eq!(base_type, UnitOffset(0)); + let mut v = address << 2; + if let Some(value) = space { + v += value; + } + v &= (1u64 << (8 * size)) - 1; + eval.resume_with_memory(Value::Generic(v))? + } + EvaluationResult::RequiresRelocatedAddress(address) => { + eval.resume_with_relocated_address(address)? + } + _ => panic!("Unexpected result: {:?}", result), + }; + } + + Ok(result) + }, + ); } #[test]