use crate::sims::fs::FileMode;
use crate::state::{State, StateStatus};
use crate::value::Value;
const MAX_LEN: u64 = 8192;
pub fn syscall(syscall_name: &str, state: &mut State, args: &[Value]) -> Value {
match syscall_name {
"indirect_syscall" => indirect(state, args),
"open" => open(state, args),
"openat" => openat(state, args),
"close" => close(state, args),
"read" => read(state, args),
"write" => write(state, args),
"access" => access(state, args),
"stat" => stat(state, args),
"fstat" => fstat(state, args),
"lstat" => lstat(state, args),
"lseek" => lseek(state, args),
"mprotect" => mmap(state, args),
"mmap" => mmap(state, args),
"munmap" => munmap(state, args),
"brk" => brk(state, args),
"sbrk" => sbrk(state, args),
"getpid" => getpid(state, args),
"getuid" => getuid(state, args),
"geteuid" => getuid(state, args),
"getgid" => getuid(state, args),
"getegid" => getuid(state, args),
"fork" => fork(state, args),
"exit" => exit(state, args),
"ptrace" => ptrace(state, args),
_ => error(state, args), }
}
pub fn indirect(state: &mut State, args: &[Value]) -> Value {
let sn = state.solver.evalcon_to_u64(&args[0]).unwrap();
let sys_str = state.r2api.get_syscall_str(sn).unwrap();
syscall(sys_str.as_str(), state, &args[1..])
}
pub fn open(state: &mut State, args: &[Value]) -> Value {
let addr = state.solver.evalcon_to_u64(&args[0]).unwrap();
let len = state.memory_strlen(&args[0], &Value::Concrete(MAX_LEN, 0));
let length = state.solver.evalcon_to_u64(&len).unwrap();
let path = state.memory_read_string(addr, length as usize);
if let Some(fd) = state.filesystem.open(path.as_str(), FileMode::Read) {
Value::Concrete(fd as u64, 0)
} else {
Value::Concrete(-1i64 as u64, 0)
}
}
pub fn openat(state: &mut State, args: &[Value]) -> Value {
open(state, &args[1..])
}
pub fn close(state: &mut State, args: &[Value]) -> Value {
let fd = state.solver.evalcon_to_u64(&args[0]);
state.filesystem.close(fd.unwrap() as usize);
Value::Concrete(0, 0)
}
pub fn read(state: &mut State, args: &[Value]) -> Value {
let fd = state.solver.evalcon_to_u64(&args[0]).unwrap();
let length = state.solver.max_value(&args[2]) & 0xffffffff;
let data = state.filesystem.read(fd as usize, length as usize);
let len = data.len();
state.memory_write(&args[1], &data, &args[2]);
Value::Concrete(len as u64, args[2].get_taint())
}
pub fn write(state: &mut State, args: &[Value]) -> Value {
let fd = state.solver.evalcon_to_u64(&args[0]).unwrap();
let data = state.memory_read(&args[1], &args[2]);
let len = data.len();
state.filesystem.write(fd as usize, data);
Value::Concrete(len as u64, 0)
}
pub fn access(state: &mut State, args: &[Value]) -> Value {
let addr = state.solver.evalcon_to_u64(&args[0]).unwrap();
let len = state.memory_strlen(&args[0], &Value::Concrete(MAX_LEN, 0));
let length = state.solver.evalcon_to_u64(&len).unwrap();
let path = state.memory_read_string(addr, length as usize);
state.filesystem.access(path.as_str())
}
pub fn stat(state: &mut State, args: &[Value]) -> Value {
let path_addr = state.solver.evalcon_to_u64(&args[0]).unwrap();
let path_len = state.memory_strlen(&args[0], &Value::Concrete(4096, 0)); let path = state.memory_read_string(path_addr, path_len.as_u64().unwrap() as usize);
let statopt = state.filesystem.stat(&path);
let statbuf = state.solver.evalcon_to_u64(&args[1]).unwrap();
if let Some(statdata) = statopt {
state
.memory
.write_value(statbuf, &Value::Concrete(statdata.st_dev, 0), 8);
state
.memory
.write_value(statbuf + 8, &Value::Concrete(statdata.st_ino, 0), 8);
state.memory.write_value(
statbuf + 16,
&Value::Concrete(statdata.st_mode as u64, 0),
8,
);
state.memory.write_value(
statbuf + 24,
&Value::Concrete(statdata.st_nlink as u64, 0),
4,
);
state
.memory
.write_value(statbuf + 28, &Value::Concrete(statdata.st_uid as u64, 0), 4);
state
.memory
.write_value(statbuf + 32, &Value::Concrete(statdata.st_gid as u64, 0), 4);
state
.memory
.write_value(statbuf + 36, &Value::Concrete(statdata.__pad0 as u64, 0), 4);
state
.memory
.write_value(statbuf + 40, &Value::Concrete(statdata.st_rdev, 0), 8);
state.memory.write_value(
statbuf + 48,
&Value::Concrete(statdata.st_size as u64, 0),
8,
);
state.memory.write_value(
statbuf + 56,
&Value::Concrete(statdata.st_blksize as u64, 0),
8,
);
state.memory.write_value(
statbuf + 64,
&Value::Concrete(statdata.st_blocks as u64, 0),
8,
);
state
.memory
.write_value(statbuf + 72, &Value::Concrete(statdata.st_atime, 0), 8);
state
.memory
.write_value(statbuf + 80, &Value::Concrete(statdata.st_atimensec, 0), 8);
state
.memory
.write_value(statbuf + 88, &Value::Concrete(statdata.st_mtime, 0), 8);
state
.memory
.write_value(statbuf + 96, &Value::Concrete(statdata.st_mtimensec, 0), 8);
state
.memory
.write_value(statbuf + 104, &Value::Concrete(statdata.st_ctime, 0), 8);
state
.memory
.write_value(statbuf + 112, &Value::Concrete(statdata.st_ctimensec, 0), 8);
state.memory.write_value(
statbuf + 120,
&Value::Concrete(statdata.__glibc_reserved[0] as u64, 0),
4,
);
state.memory.write_value(
statbuf + 124,
&Value::Concrete(statdata.__glibc_reserved[1] as u64, 0),
4,
);
Value::Concrete(0, 0)
} else {
Value::Concrete(-1i64 as u64, 0)
}
}
pub fn fstat(state: &mut State, args: &[Value]) -> Value {
let fd = state.solver.evalcon_to_u64(&args[0]).unwrap();
let path = state.filesystem.getpath(fd as usize);
state.filesystem.stat(path.unwrap().as_str());
Value::Concrete(0, 0)
}
pub fn lstat(state: &mut State, args: &[Value]) -> Value {
stat(state, args)
}
pub fn lseek(state: &mut State, args: &[Value]) -> Value {
let fd = state.solver.evalcon_to_u64(&args[0]).unwrap();
let pos = state.solver.evalcon_to_u64(&args[1]).unwrap();
state.filesystem.seek(fd as usize, pos as usize);
Value::Concrete(pos, 0)
}
pub fn error(_state: &mut State, _args: &[Value]) -> Value {
Value::Concrete(-1i64 as u64, 0)
}
pub fn success(_state: &mut State, _args: &[Value]) -> Value {
Value::Concrete(0, 0)
}
pub fn mmap(state: &mut State, args: &[Value]) -> Value {
let mut addr = state.solver.evalcon_to_u64(&args[0]).unwrap();
let size = state.solver.evalcon_to_u64(&args[1]).unwrap();
let prot = state.solver.evalcon_to_u64(&args[2]).unwrap();
if addr == 0 {
addr = state.memory_alloc(&args[1]).as_u64().unwrap();
}
let perms = state.memory.prot_to_str(prot);
state
.memory
.add_segment("mmapped", addr, size, perms.as_str());
Value::Concrete(addr, 0)
}
pub fn munmap(state: &mut State, args: &[Value]) -> Value {
let addr = state.solver.evalcon_to_u64(&args[0]).unwrap();
let mut ind = -1i32 as usize;
for (i, seg) in state.memory.segs.iter().enumerate() {
if seg.addr == addr {
ind = i;
break;
}
}
if ind as i32 != -1 {
state.memory.segs.remove(ind);
Value::Concrete(0, 0)
} else {
Value::Concrete(-1i64 as u64, 0)
}
}
pub fn brk(state: &mut State, args: &[Value]) -> Value {
let addr = state.solver.evalcon_to_u64(&args[0]).unwrap();
Value::Concrete(state.memory.brk(addr), 0)
}
pub fn sbrk(state: &mut State, args: &[Value]) -> Value {
let inc = state.solver.evalcon_to_u64(&args[0]).unwrap();
Value::Concrete(state.memory.sbrk(inc), 0)
}
pub fn fork(state: &mut State, _args: &[Value]) -> Value {
let cpid = state.pid + 1;
state.pid = cpid;
let pid = state.bv(format!("pid_{}", cpid).as_str(), 64);
let a = pid
._eq(&state.bvv(cpid, 64))
.or(&pid._eq(&state.bvv(0, 64)))
.or(&pid._eq(&state.bvv(-1i64 as u64, 64)));
state.solver.assert_bv(&a);
Value::Symbolic(pid, 0)
}
pub fn getpid(state: &mut State, _args: &[Value]) -> Value {
Value::Concrete(state.pid, 0)
}
pub fn getuid(_state: &mut State, _args: &[Value]) -> Value {
Value::Concrete(0, 0)
}
pub fn ptrace(_state: &mut State, _args: &[Value]) -> Value {
Value::Concrete(0, 0) }
pub fn exit(state: &mut State, args: &[Value]) -> Value {
state.status = StateStatus::Inactive;
args[0].to_owned()
}