Skip to content

Commit

Permalink
feat: check for uninitialized value access in write (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
mstarzinger committed Mar 7, 2021
1 parent 052b500 commit 4abef6c
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 31 deletions.
2 changes: 1 addition & 1 deletion examples/memory-invalid-read.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ uint64_t main() {
x = malloc(8);

// address out of range
x = x + 2147483648
x = x + 268435456

read(0, x, 1);

Expand Down
2 changes: 1 addition & 1 deletion examples/memory-invalid-write.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ uint64_t main() {
x = malloc(8);

// address out of range
x = x + 2147483648
x = x + 268435456

write(1, x, 1);

Expand Down
12 changes: 12 additions & 0 deletions examples/memory-uninitialized-write.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
uint64_t main() {
uint64_t* x;

x = malloc(16);

*x = 0;

// accesses uninitialized memory
write(1, x, 12);

return 0;
}
83 changes: 55 additions & 28 deletions src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,31 @@ where
}
}

fn check_for_valid_memory_range(
&mut self,
instruction: &str,
address: u64,
size: u64,
) -> Result<Option<Bug>, EngineError> {
if !self.is_in_vaddr_range(address) || !self.is_in_vaddr_range(address + size) {
trace!(
"{}: buffer {:#x} - {:#x} out of virtual address range (0x0 - {:#x}) => computing reachability",
instruction,
address,
address + size,
self.memory.len() * 8,
);

self.is_running = false;

self.execute_query(Query::Reachable, |info| Bug::AccessToOutOfRangeAddress {
info,
})
} else {
Ok(None)
}
}

#[allow(clippy::unnecessary_wraps)]
fn execute_lui(&mut self, utype: UType) -> Result<Option<Bug>, EngineError> {
let immediate = u64::from(utype.imm()) << 12;
Expand Down Expand Up @@ -508,19 +533,9 @@ where

trace!("read: fd={} buffer={:#x} size={}", 0, buffer, size,);

if !self.is_in_vaddr_range(buffer) || !self.is_in_vaddr_range(buffer + size) {
trace!(
"read: buffer {:#x} - {:#x} out of virtual address range (0x0 - {:#x}) => computing reachability",
buffer,
buffer + size,
self.memory.len() * 8,
);

self.is_running = false;

return self.execute_query(Query::Reachable, |info| Bug::AccessToOutOfRangeAddress {
info,
});
let bug = self.check_for_valid_memory_range("read", buffer, size)?;
if bug.is_some() {
return Ok(bug);
}

let size_of_u64 = size_of::<u64>() as u64;
Expand Down Expand Up @@ -575,7 +590,7 @@ where
Ok(None)
}

fn execute_write(&mut self) -> Result<Option<Bug>, EngineError> {
fn execute_write(&mut self, instruction: Instruction) -> Result<Option<Bug>, EngineError> {
if !matches!(self.regs[Register::A0 as usize], Value::Concrete(1)) {
return not_supported("can not handle other fd than stdout in write syscall");
}
Expand All @@ -596,19 +611,31 @@ where

trace!("write: fd={} buffer={:#x} size={}", 1, buffer, size,);

if !self.is_in_vaddr_range(buffer) || !self.is_in_vaddr_range(buffer + size) {
trace!(
"write: buffer {:#x} - {:#x} out of virtual address range (0x0 - {:#x}) => computing reachability",
buffer,
buffer + size,
self.memory.len() * 8,
);
let bug = self.check_for_valid_memory_range("write", buffer, size)?;
if bug.is_some() {
return Ok(bug);
}

self.is_running = false;
let size_of_u64 = size_of::<u64>() as u64;
let start = buffer / size_of_u64;
let bytes_to_read = size + buffer % size_of_u64;
let words_to_read = (bytes_to_read + size_of_u64 - 1) / size_of_u64;

return self.execute_query(Query::Reachable, |info| Bug::AccessToOutOfRangeAddress {
info,
});
for word_count in 0..words_to_read {
if self.memory[(start + word_count) as usize] == Value::Uninitialized {
trace!(
"write: access to uninitialized memory at {:#x} => computing reachability",
(start + word_count) * size_of_u64,
);

return self.execute_query(Query::Reachable, |info| {
Bug::AccessToUnitializedMemory {
info,
instruction,
operands: vec![],
}
});
}
}

self.regs[Register::A0 as usize] = Value::Concrete(size);
Expand Down Expand Up @@ -782,7 +809,7 @@ where
}
}

fn execute_ecall(&mut self) -> Result<Option<Bug>, EngineError> {
fn execute_ecall(&mut self, instruction: Instruction) -> Result<Option<Bug>, EngineError> {
trace!("[{:#010x}] ecall", self.pc);

let result = match self.regs[Register::A7 as usize] {
Expand All @@ -793,7 +820,7 @@ where
self.execute_read()
}
Value::Concrete(syscall_id) if syscall_id == (SyscallId::Write as u64) => {
self.execute_write()
self.execute_write(instruction)
}
Value::Concrete(syscall_id) if syscall_id == (SyscallId::Exit as u64) => {
self.execute_exit()
Expand Down Expand Up @@ -955,7 +982,7 @@ where

fn execute(&mut self, instruction: Instruction) -> Result<Option<Bug>, EngineError> {
match instruction {
Instruction::Ecall(_) => self.execute_ecall(),
Instruction::Ecall(_) => self.execute_ecall(instruction),
Instruction::Lui(utype) => self.execute_lui(utype),
Instruction::Addi(itype) => self.execute_itype(instruction, itype, u64::wrapping_add),
Instruction::Add(rtype) => self.execute_rtype(instruction, rtype, u64::wrapping_add),
Expand Down
4 changes: 3 additions & 1 deletion tests/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::{
time::Duration,
};

const TEST_FILES: [&str; 17] = [
const TEST_FILES: [&str; 18] = [
"arithmetic.c",
"echo-line.c",
"if-else.c", // needs timeout
Expand All @@ -28,6 +28,7 @@ const TEST_FILES: [&str; 17] = [
//"memory-access-1-35.c",
"memory-invalid-read.c",
"memory-invalid-write.c",
"memory-uninitialized-write.c",
"nested-if-else-reverse-1-35",
"nested-recursion-1-35.c",
"recursive-ackermann-1-35.c",
Expand Down Expand Up @@ -187,6 +188,7 @@ fn execute_riscu<S: Solver>(source: PathBuf, object: PathBuf, solver: &S) {
//("memory-access-1-35.c", Bug::
("memory-invalid-read.c", Bug::AccessToOutOfRangeAddress { .. }) |
("memory-invalid-write.c", Bug::AccessToOutOfRangeAddress { .. }) |
("memory-uninitialized-write.c", Bug::AccessToUnitializedMemory { .. }) |
("nested-if-else-reverse-1-35", Bug::ExitCodeGreaterZero { .. }) |
("nested-recursion-1-35.c", Bug::ExitCodeGreaterZero { .. }) |
("recursive-ackermann-1-35.c", Bug::ExitCodeGreaterZero { .. }) |
Expand Down

0 comments on commit 4abef6c

Please sign in to comment.