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.
This commit is contained in:
Takacs, Philipp 2024-01-15 14:07:50 +01:00
parent 5e39cc602a
commit d9d2c4e581
2 changed files with 12 additions and 11 deletions

View File

@ -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));

7
uc.c
View File

@ -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;
}