handle memory fetch as invalid memory access. now we can also report error if exec memory is unmapped (UC_ERR_MEM_FETCH)

This commit is contained in:
Nguyen Anh Quynh 2015-09-04 11:55:17 +08:00
parent 84e3b5c897
commit 022f8d82d1
6 changed files with 73 additions and 33 deletions

View File

@ -41,20 +41,22 @@ const (
UC_ERR_VERSION = 5 UC_ERR_VERSION = 5
UC_ERR_MEM_READ = 6 UC_ERR_MEM_READ = 6
UC_ERR_MEM_WRITE = 7 UC_ERR_MEM_WRITE = 7
UC_ERR_CODE_INVALID = 8 UC_ERR_MEM_FETCH = 8
UC_ERR_HOOK = 9 UC_ERR_CODE_INVALID = 9
UC_ERR_INSN_INVALID = 10 UC_ERR_HOOK = 10
UC_ERR_MAP = 11 UC_ERR_INSN_INVALID = 11
UC_ERR_WRITE_PROT = 12 UC_ERR_MAP = 12
UC_ERR_READ_PROT = 13 UC_ERR_WRITE_PROT = 13
UC_ERR_EXEC_PROT = 14 UC_ERR_READ_PROT = 14
UC_ERR_INVAL = 15 UC_ERR_EXEC_PROT = 15
UC_ERR_INVAL = 16
UC_MEM_READ = 16 UC_MEM_READ = 16
UC_MEM_WRITE = 17 UC_MEM_WRITE = 17
UC_MEM_READ_WRITE = 18 UC_MEM_READ_WRITE = 18
UC_MEM_WRITE_PROT = 19 UC_MEM_EXEC = 19
UC_MEM_READ_PROT = 20 UC_MEM_WRITE_PROT = 20
UC_MEM_EXEC_PROT = 21 UC_MEM_READ_PROT = 21
UC_MEM_EXEC_PROT = 22
UC_HOOK_INTR = 32 UC_HOOK_INTR = 32
UC_HOOK_INSN = 33 UC_HOOK_INSN = 33
UC_HOOK_CODE = 34 UC_HOOK_CODE = 34

View File

@ -39,20 +39,22 @@ UC_ERR_MODE = 4
UC_ERR_VERSION = 5 UC_ERR_VERSION = 5
UC_ERR_MEM_READ = 6 UC_ERR_MEM_READ = 6
UC_ERR_MEM_WRITE = 7 UC_ERR_MEM_WRITE = 7
UC_ERR_CODE_INVALID = 8 UC_ERR_MEM_FETCH = 8
UC_ERR_HOOK = 9 UC_ERR_CODE_INVALID = 9
UC_ERR_INSN_INVALID = 10 UC_ERR_HOOK = 10
UC_ERR_MAP = 11 UC_ERR_INSN_INVALID = 11
UC_ERR_WRITE_PROT = 12 UC_ERR_MAP = 12
UC_ERR_READ_PROT = 13 UC_ERR_WRITE_PROT = 13
UC_ERR_EXEC_PROT = 14 UC_ERR_READ_PROT = 14
UC_ERR_INVAL = 15 UC_ERR_EXEC_PROT = 15
UC_ERR_INVAL = 16
UC_MEM_READ = 16 UC_MEM_READ = 16
UC_MEM_WRITE = 17 UC_MEM_WRITE = 17
UC_MEM_READ_WRITE = 18 UC_MEM_READ_WRITE = 18
UC_MEM_WRITE_PROT = 19 UC_MEM_EXEC = 19
UC_MEM_READ_PROT = 20 UC_MEM_WRITE_PROT = 20
UC_MEM_EXEC_PROT = 21 UC_MEM_READ_PROT = 21
UC_MEM_EXEC_PROT = 22
UC_HOOK_INTR = 32 UC_HOOK_INTR = 32
UC_HOOK_INSN = 33 UC_HOOK_INSN = 33
UC_HOOK_CODE = 34 UC_HOOK_CODE = 34

View File

@ -113,6 +113,7 @@ typedef enum uc_err {
UC_ERR_VERSION, // Unsupported version (bindings) UC_ERR_VERSION, // Unsupported version (bindings)
UC_ERR_MEM_READ, // Quit emulation due to invalid memory READ: uc_emu_start() UC_ERR_MEM_READ, // Quit emulation due to invalid memory READ: uc_emu_start()
UC_ERR_MEM_WRITE, // Quit emulation due to invalid memory WRITE: uc_emu_start() UC_ERR_MEM_WRITE, // Quit emulation due to invalid memory WRITE: uc_emu_start()
UC_ERR_MEM_FETCH, // Quit emulation due to invalid memory FETCH: uc_emu_start()
UC_ERR_CODE_INVALID, // Quit emulation due to invalid code address: uc_emu_start() UC_ERR_CODE_INVALID, // Quit emulation due to invalid code address: uc_emu_start()
UC_ERR_HOOK, // Invalid hook type: uc_hook_add() UC_ERR_HOOK, // Invalid hook type: uc_hook_add()
UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start() UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start()
@ -152,6 +153,7 @@ typedef enum uc_mem_type {
UC_MEM_READ = 16, // Memory is read from UC_MEM_READ = 16, // Memory is read from
UC_MEM_WRITE, // Memory is written to UC_MEM_WRITE, // Memory is written to
UC_MEM_READ_WRITE, // Memory is accessed (either READ or WRITE) UC_MEM_READ_WRITE, // Memory is accessed (either READ or WRITE)
UC_MEM_EXEC, // Unmapped memory is fetched, but unmapped (invalid memory access)
UC_MEM_WRITE_PROT, // write to write protected memory UC_MEM_WRITE_PROT, // write to write protected memory
UC_MEM_READ_PROT, // read from read protected memory UC_MEM_READ_PROT, // read from read protected memory
UC_MEM_EXEC_PROT, // fetch from non-executable memory UC_MEM_EXEC_PROT, // fetch from non-executable memory

View File

@ -182,8 +182,24 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
MemoryRegion *mr = memory_mapping(uc, addr); MemoryRegion *mr = memory_mapping(uc, addr);
#if defined(SOFTMMU_CODE_ACCESS) #if defined(SOFTMMU_CODE_ACCESS)
// Unicorn: callback on fetch from unmapped memory
if (mr == NULL) { // memory is not mapped
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, UC_MEM_EXEC, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
} else {
env->invalid_addr = addr;
env->invalid_error = UC_ERR_MEM_FETCH;
// printf("***** Invalid fetch (unmapped memory) at " TARGET_FMT_lx "\n", addr);
cpu_exit(uc->current_cpu);
return 0;
}
}
// Unicorn: callback on fetch from NX // Unicorn: callback on fetch from NX
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { //non-executable if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
@ -199,7 +215,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#endif #endif
// Unicorn: callback on memory read // Unicorn: callback on memory read
if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { if (READ_ACCESS_TYPE == MMU_DATA_LOAD && env->uc->hook_mem_read) {
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr); struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr);
if (trace) { if (trace) {
((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ, ((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ,
@ -208,7 +224,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
} }
// Unicorn: callback on invalid memory // Unicorn: callback on invalid memory
if (env->uc->hook_mem_idx && mr == NULL) { if (READ_ACCESS_TYPE == MMU_DATA_LOAD && env->uc->hook_mem_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)( if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)(
env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, env->uc, UC_MEM_READ, addr, DATA_SIZE, 0,
env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) { env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) {
@ -224,7 +240,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
} }
// Unicorn: callback on non-readable memory // Unicorn: callback on non-readable memory
if (mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
@ -340,8 +356,24 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
MemoryRegion *mr = memory_mapping(uc, addr); MemoryRegion *mr = memory_mapping(uc, addr);
#if defined(SOFTMMU_CODE_ACCESS) #if defined(SOFTMMU_CODE_ACCESS)
// Unicorn: callback on fetch from unmapped memory
if (mr == NULL) { // memory is not mapped
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, UC_MEM_EXEC, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
} else {
env->invalid_addr = addr;
env->invalid_error = UC_ERR_MEM_FETCH;
// printf("***** Invalid fetch (unmapped memory) at " TARGET_FMT_lx "\n", addr);
cpu_exit(uc->current_cpu);
return 0;
}
}
// Unicorn: callback on fetch from NX // Unicorn: callback on fetch from NX
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { //non-executable if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
@ -357,7 +389,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#endif #endif
// Unicorn: callback on memory read // Unicorn: callback on memory read
if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { if (READ_ACCESS_TYPE == MMU_DATA_LOAD && env->uc->hook_mem_read) {
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr); struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr);
if (trace) { if (trace) {
((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ, ((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ,
@ -366,7 +398,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
} }
// Unicorn: callback on invalid memory // Unicorn: callback on invalid memory
if (env->uc->hook_mem_idx && mr == NULL) { if (READ_ACCESS_TYPE == MMU_DATA_LOAD && env->uc->hook_mem_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)( if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)(
env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, env->uc, UC_MEM_READ, addr, DATA_SIZE, 0,
env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) { env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) {
@ -382,7 +414,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
} }
// Unicorn: callback on non-readable memory // Unicorn: callback on non-readable memory
if (mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_idx].user_data)) {

View File

@ -6,7 +6,7 @@ import unicorn
ADDR = 0xffaabbcc ADDR = 0xffaabbcc
def hook_mem_invalid(mu, access, address, size, value, user_data): def hook_mem_invalid(mu, access, address, size, value, user_data):
print ">>> Expected value: 0x%x, actual value: 0x%x" % (ADDR, address) print ">>> Access type: %u, Expected value: 0x%x, actual value: 0x%x" % (access, ADDR, address)
assert(address == ADDR) assert(address == ADDR)
mu.mem_map(address & 0xfffff000, 4 * 1024) mu.mem_map(address & 0xfffff000, 4 * 1024)
mu.mem_write(address, b'\xcc') mu.mem_write(address, b'\xcc')

6
uc.c
View File

@ -73,12 +73,14 @@ const char *uc_strerror(uc_err code)
return "Invalid memory read (UC_ERR_MEM_READ)"; return "Invalid memory read (UC_ERR_MEM_READ)";
case UC_ERR_MEM_WRITE: case UC_ERR_MEM_WRITE:
return "Invalid memory write (UC_ERR_MEM_WRITE)"; return "Invalid memory write (UC_ERR_MEM_WRITE)";
case UC_ERR_MEM_FETCH:
return "Invalid memory fetch (UC_ERR_MEM_FETCH)";
case UC_ERR_CODE_INVALID: case UC_ERR_CODE_INVALID:
return "Invalid code address (UC_ERR_CODE_INVALID)"; return "Invalid code address (UC_ERR_CODE_INVALID)";
case UC_ERR_INSN_INVALID:
return "Invalid instruction (UC_ERR_INSN_INVALID)";
case UC_ERR_HOOK: case UC_ERR_HOOK:
return "Invalid hook type (UC_ERR_HOOK)"; return "Invalid hook type (UC_ERR_HOOK)";
case UC_ERR_INSN_INVALID:
return "Invalid instruction (UC_ERR_INSN_INVALID)";
case UC_ERR_MAP: case UC_ERR_MAP:
return "Invalid memory mapping (UC_ERR_MAP)"; return "Invalid memory mapping (UC_ERR_MAP)";
case UC_ERR_WRITE_PROT: case UC_ERR_WRITE_PROT: