diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 9b9c84ee64..e83d3bc857 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -1797,6 +1797,22 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, if (handled) { uc->invalid_error = UC_ERR_OK; + mr = uc->memory_mapping(uc, paddr); + if (mr == NULL || !(mr->perms & UC_PROT_EXEC)) { + uc->invalid_addr = paddr; + uc->invalid_error = mr == NULL ? UC_ERR_MAP : UC_ERR_FETCH_PROT; + if (uc->nested_level > 0 && !uc->cpu->stopped) { + cpu_exit(uc->cpu); + cpu_loop_exit_restore(uc->cpu, retaddr); + } + return 0; + } + tlb_fill(env_cpu(env), addr, size, + access_type, mmu_idx, retaddr); + index = tlb_index(env, mmu_idx, addr); + entry = tlb_entry(env, mmu_idx, addr); + tlb_addr = entry->addr_code; + tlb_addr &= ~TLB_INVALID_MASK; tlb_hook_state_restore(env, &hook_state); } else { uc->invalid_addr = paddr; diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index 8deb08daed..a15274edeb 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -1691,6 +1691,53 @@ static void test_x86_lazy_mapping(void) OK(uc_close(uc)); } +static bool test_x86_fetch_prot_mem_protect_callback(uc_engine *uc, + uc_mem_type type, + uint64_t address, int size, + int64_t value, + void *user_data) +{ + int *hook_count = (int *)user_data; + (*hook_count)++; + + TEST_CHECK(type == UC_MEM_FETCH_PROT); + TEST_CHECK(address == 0x200000); + OK(uc_mem_protect(uc, 0x200000, 0x1000, UC_PROT_ALL)); + + return true; +} + +static void test_x86_fetch_prot_mem_protect(void) +{ + uc_engine *uc; + uc_hook hook; + int hook_count = 0; + uint64_t rip = 0; + uint64_t rsp = 0x300800; + char code[] = "\x48\xb8\x00\x00\x20\x00\x00\x00\x00\x00\xff\xe0"; + char target[] = "\x90\x90\x90\xf4"; // nop; nop; nop; hlt + + OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); + OK(uc_mem_map(uc, 0x100000, 0x1000, UC_PROT_ALL)); + OK(uc_mem_map(uc, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE)); + OK(uc_mem_map(uc, 0x300000, 0x1000, UC_PROT_ALL)); + OK(uc_mem_write(uc, 0x100000, code, sizeof(code) - 1)); + OK(uc_mem_write(uc, 0x200000, target, sizeof(target) - 1)); + OK(uc_mem_protect(uc, 0x200000, 0x1000, UC_PROT_READ)); + OK(uc_reg_write(uc, UC_X86_REG_RSP, &rsp)); + OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_FETCH_PROT, + test_x86_fetch_prot_mem_protect_callback, &hook_count, 1, + 0)); + + OK(uc_emu_start(uc, 0x100000, 0, 0, 100)); + OK(uc_reg_read(uc, UC_X86_REG_RIP, &rip)); + TEST_CHECK(hook_count == 1); + TEST_CHECK(rip == 0x200004); + + OK(uc_hook_del(uc, hook)); + OK(uc_close(uc)); +} + static void test_x86_16_incorrect_ip_cb(uc_engine *uc, uint64_t address, uint32_t size, void *data) { @@ -2787,6 +2834,7 @@ TEST_LIST = { #endif {"test_x86_lazy_mapping", test_x86_lazy_mapping}, + {"test_x86_fetch_prot_mem_protect", test_x86_fetch_prot_mem_protect}, {"test_x86_16_incorrect_ip", test_x86_16_incorrect_ip}, {"test_x86_mmu", test_x86_mmu}, {"test_x86_read_virtual", test_x86_read_virtual},