From d9d2c4e581c336ab11b5e1d9159f0c932b196798 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Mon, 15 Jan 2024 14:07:50 +0100 Subject: [PATCH] fix uc_mem write with cow when using upper half of the address uc->target_page_align is a uint32_t. When the binary not will only invert the 32 bit of the value. Used this in a binary and operator with a uint64_t will case the upper 32bit of the address to be 0. Therefor the bug only appears when the upper 32bit of the address are used. Now a local uint64_t variable is used for the alignemend and the test uses a not page alligned address which does not fit in 32bit. --- tests/unit/test_mem.c | 16 +++++++++------- uc.c | 7 +++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/tests/unit/test_mem.c b/tests/unit/test_mem.c index 2bf197a6..15120aa4 100644 --- a/tests/unit/test_mem.c +++ b/tests/unit/test_mem.c @@ -379,27 +379,29 @@ static void test_context_snapshot(void) { uc_engine *uc; uc_context *ctx; + uint64_t baseaddr = 0xfffff1000; + uint64_t offset = 0x10; uint64_t tmp = 1; OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); OK(uc_ctl_context_mode(uc, UC_CTL_CONTEXT_MEMORY | UC_CTL_CONTEXT_CPU)); - OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL)); + OK(uc_mem_map(uc, baseaddr, 0x1000, UC_PROT_ALL)); OK(uc_context_alloc(uc, &ctx)); OK(uc_context_save(uc, ctx)); - OK(uc_mem_write(uc, 0x1000, &tmp, sizeof(tmp))); - OK(uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp))); + OK(uc_mem_write(uc, baseaddr + offset, &tmp, sizeof(tmp))); + OK(uc_mem_read(uc, baseaddr + offset, &tmp, sizeof(tmp))); TEST_CHECK(tmp == 1); OK(uc_context_restore(uc, ctx)); - OK(uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp))); + OK(uc_mem_read(uc, baseaddr + offset, &tmp, sizeof(tmp))); TEST_CHECK(tmp == 0); tmp = 2; - OK(uc_mem_write(uc, 0x1000, &tmp, sizeof(tmp))); - OK(uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp))); + OK(uc_mem_write(uc, baseaddr + offset, &tmp, sizeof(tmp))); + OK(uc_mem_read(uc, baseaddr + offset, &tmp, sizeof(tmp))); TEST_CHECK(tmp == 2); OK(uc_context_restore(uc, ctx)); - OK(uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp))); + OK(uc_mem_read(uc, baseaddr + offset, &tmp, sizeof(tmp))); TEST_CHECK(tmp == 0); OK(uc_context_free(ctx)); diff --git a/uc.c b/uc.c index e2248fbd..10983447 100644 --- a/uc.c +++ b/uc.c @@ -780,6 +780,7 @@ uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, MemoryRegion *mr = uc->memory_mapping(uc, address); if (mr) { uint32_t operms = mr->perms; + uint64_t align = uc->target_page_align; if (!(operms & UC_PROT_WRITE)) { // write protected // but this is not the program accessing memory, so temporarily // mark writable @@ -788,10 +789,8 @@ uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, len = memory_region_len(uc, mr, address, size - count); if (uc->snapshot_level && uc->snapshot_level > mr->priority) { - mr = uc->memory_cow(uc, mr, address & ~uc->target_page_align, - (len + (address & uc->target_page_align) + - uc->target_page_align) & - ~uc->target_page_align); + mr = uc->memory_cow(uc, mr, address & ~align, + (len + (address & align) + align) & ~align); if (!mr) { return UC_ERR_NOMEM; }