diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index ddb96d80..556b6c17 100755 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -116,7 +116,8 @@ typedef enum uc_err { UC_ERR_HOOK, // Invalid hook type: uc_hook_add() UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start() UC_ERR_MAP, // Invalid memory mapping: uc_mem_map() - UC_ERR_MEM_WRITE_RO, // Quit emulation due to invalid memory WRITE: uc_emu_start() + UC_ERR_MEM_WRITE_NW, // Quit emulation due to write to non-writable: uc_emu_start() + UC_ERR_MEM_READ_NR, // Quit emulation due to read from non-readable: uc_emu_start() } uc_err; @@ -148,7 +149,8 @@ typedef enum uc_mem_type { UC_MEM_READ = 16, // Memory is read from UC_MEM_WRITE, // Memory is written to UC_MEM_READ_WRITE, // Memory is accessed (either READ or WRITE) - UC_MEM_WRITE_RO, // Read only memory is written to + UC_MEM_WRITE_NW, // write to non-writable + UC_MEM_READ_NR, // read from non-readable } uc_mem_type; // All type of hooks for uc_hook_add() API. diff --git a/qemu/softmmu_template.h b/qemu/softmmu_template.h index 86bca884..56f657a4 100755 --- a/qemu/softmmu_template.h +++ b/qemu/softmmu_template.h @@ -178,6 +178,9 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, uintptr_t haddr; DATA_TYPE res; + struct uc_struct *uc = env->uc; + MemoryRegion *mr = memory_mapping(uc, addr); + // Unicorn: callback on memory read if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_READ, addr); @@ -188,7 +191,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } // Unicorn: callback on invalid memory - if (env->uc->hook_mem_idx && !memory_mapping(env->uc, addr)) { + if (env->uc->hook_mem_idx && mr == NULL) { if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)( (uch)env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) { @@ -203,6 +206,26 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } } + // Unicorn: callback on read only memory + if (mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable + bool result = false; + if (uc->hook_mem_idx) { + result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + (uch)uc, UC_MEM_READ_NR, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_idx].user_data); + } + if (result) { + env->invalid_error = UC_ERR_OK; + } + else { + env->invalid_addr = addr; + env->invalid_error = UC_ERR_MEM_READ_NR; + // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); + cpu_exit(uc->current_cpu); + return 0; + } + } + /* Adjust the given return address. */ retaddr -= GETPC_ADJ; @@ -300,6 +323,9 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, uintptr_t haddr; DATA_TYPE res; + struct uc_struct *uc = env->uc; + MemoryRegion *mr = memory_mapping(uc, addr); + // Unicorn: callback on memory read if (env->uc->hook_mem_read && READ_ACCESS_TYPE == MMU_DATA_LOAD) { struct hook_struct *trace = hook_find((uch)env->uc, UC_MEM_READ, addr); @@ -310,7 +336,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } // Unicorn: callback on invalid memory - if (env->uc->hook_mem_idx && !memory_mapping(env->uc, addr)) { + if (env->uc->hook_mem_idx && mr == NULL) { if (!((uc_cb_eventmem_t)env->uc->hook_callbacks[env->uc->hook_mem_idx].callback)( (uch)env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, env->uc->hook_callbacks[env->uc->hook_mem_idx].user_data)) { @@ -325,6 +351,26 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx, } } + // Unicorn: callback on read only memory + if (mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable + bool result = false; + if (uc->hook_mem_idx) { + result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( + (uch)uc, UC_MEM_READ_NR, addr, DATA_SIZE, 0, + uc->hook_callbacks[uc->hook_mem_idx].user_data); + } + if (result) { + env->invalid_error = UC_ERR_OK; + } + else { + env->invalid_addr = addr; + env->invalid_error = UC_ERR_MEM_READ_NR; + // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); + cpu_exit(uc->current_cpu); + return 0; + } + } + /* Adjust the given return address. */ retaddr -= GETPC_ADJ; @@ -493,7 +539,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, bool result = false; if (uc->hook_mem_idx) { result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_WRITE_RO, addr, DATA_SIZE, (int64_t)val, + (uch)uc, UC_MEM_WRITE_NW, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data); } if (result) { @@ -501,7 +547,7 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_WRITE_RO; + env->invalid_error = UC_ERR_MEM_WRITE_NW; // printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return; @@ -631,7 +677,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, bool result = false; if (uc->hook_mem_idx) { result = ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( - (uch)uc, UC_MEM_WRITE_RO, addr, DATA_SIZE, (int64_t)val, + (uch)uc, UC_MEM_WRITE_NW, addr, DATA_SIZE, (int64_t)val, uc->hook_callbacks[uc->hook_mem_idx].user_data); } if (result) { @@ -639,7 +685,7 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val, } else { env->invalid_addr = addr; - env->invalid_error = UC_ERR_MEM_WRITE_RO; + env->invalid_error = UC_ERR_MEM_WRITE_NW; // printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->current_cpu); return; diff --git a/regress/Makefile b/regress/Makefile index ed82f3aa..a75cde02 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -4,7 +4,7 @@ LDFLAGS = -L.. -lunicorn TESTS = map_crash map_write TESTS += sigill sigill2 TESTS += block_test -TESTS += ro_mem_test +TESTS += ro_mem_test nr_mem_test all: $(TESTS) diff --git a/regress/ro_mem_test.c b/regress/ro_mem_test.c index a9755eb5..38e84cd0 100644 --- a/regress/ro_mem_test.c +++ b/regress/ro_mem_test.c @@ -1,3 +1,24 @@ +/* + +non-writable memory test case + +Copyright(c) 2015 Chris Eagle + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + #include #include #include @@ -61,7 +82,7 @@ static bool hook_mem_invalid(uch handle, uc_mem_type type, printf(">>> Missing memory is being WRITTEN at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", address, size, value); return false; - case UC_MEM_WRITE_RO: + case UC_MEM_WRITE_NR: printf(">>> RO memory is being WRITTEN at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", address, size, value); return false; diff --git a/uc.c b/uc.c index 0352380c..3192c627 100755 --- a/uc.c +++ b/uc.c @@ -89,8 +89,10 @@ const char *uc_strerror(uc_err code) return "Invalid hook type (UC_ERR_HOOK)"; case UC_ERR_MAP: return "Invalid memory mapping (UC_ERR_MAP)"; - case UC_ERR_MEM_WRITE_RO: - return "Invalid memory write (UC_ERR_MEM_WRITE_RO)"; + case UC_ERR_MEM_WRITE_NW: + return "Write to non-writable (UC_ERR_MEM_WRITE_NW)"; + case UC_ERR_MEM_READ_NR: + return "Read from non-readable (UC_ERR_MEM_READ_NR)"; } }