Skip to content

Commit bc87e4a

Browse files
committed
fix: vmem_write use uc_invalidate_tb
without this using vmem_write out of a hook might cause problems.
1 parent 2767024 commit bc87e4a

File tree

2 files changed

+120
-4
lines changed

2 files changed

+120
-4
lines changed

tests/unit/test_mem.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,118 @@ static void test_virtual_write(void)
589589
OK(uc_close(uc));
590590
}
591591

592+
static void test_virtual_write_tb_invalidation_callback(uc_engine *uc, uint64_t rip, uint32_t size, void *userdata)
593+
{
594+
/*
595+
* mov rax,QWORD PTR ds:0x2000
596+
* test rax,rax
597+
* je rip+0x10000000
598+
* mov rbx,QWORD PTR ds:0x2008
599+
* test rax,rax
600+
* jz rip+0x10000000 <_main+0x22>
601+
* hlt
602+
*/
603+
char code1[] = { 0x48, 0x8B, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0x48, 0x85, 0xC0, 0x74, 0x10, 0x48, 0x8B, 0x1C, 0x25, 0x08, 0x20, 0x00, 0x00, 0x48, 0x85, 0xC0, 0x74, 0x03, 0xF4, 0x90, 0x90 };
604+
/*
605+
* mov rax,QWORD PTR ds:0x2000
606+
* test rax,rax
607+
* je rip+0x10000000
608+
* mov rbx,QWORD PTR ds:0x2008
609+
* test rax,rax
610+
* jz rip+0x10000000
611+
* hlt
612+
*/
613+
char code2[] = { 0x48, 0x8B, 0x04, 0x25, 0x00, 0x28, 0x00, 0x00, 0x48, 0x85, 0xC0, 0x74, 0x10, 0x48, 0x8B, 0x1C, 0x25, 0x08, 0x28, 0x00, 0x00, 0x48, 0x85, 0xC0, 0x74, 0x03, 0xF4, 0x90, 0x90 };
614+
615+
int state = *(int*)userdata;
616+
617+
if (state == 0) {
618+
return;
619+
}
620+
if (state == 1 && (rip & 0xff00) == 0x1000 && (rip & 0xff) == 0x0d) {
621+
*(int*)userdata = 0; //hook is called twice because the loop break
622+
//so set state to 0 again to indicate we are done at this point
623+
OK(uc_vmem_write(uc, 0x1800, UC_PROT_EXEC, code2, sizeof(code2)));
624+
return;
625+
}
626+
if (state == 2 && (rip & 0xff00) == 0x1800 && (rip & 0xff) == 0x0d) {
627+
*(int*)userdata = 0; //hook is called twice because the loop break
628+
//so set state to 0 again to indicate we are done at this point
629+
OK(uc_vmem_write(uc, 0x1800, UC_PROT_EXEC, code1, sizeof(code1)));
630+
return;
631+
}
632+
}
633+
634+
static void test_virtual_write_tb_invalidation(void)
635+
{
636+
uc_engine *uc;
637+
uc_hook hook1, hook2;
638+
int state = 0;
639+
uint64_t rax1 = 0x01;
640+
uint64_t rbx1 = 0x02;
641+
uint64_t rax2 = 0x11;
642+
uint64_t rbx2 = 0x12;
643+
uint64_t res = 0;
644+
/*
645+
* mov rax,QWORD PTR ds:0x2000
646+
* test rax,rax
647+
* je 1d <bla>
648+
* mov rbx,QWORD PTR ds:0x2008
649+
* test rax,rax
650+
* je 1d <bla>
651+
* hlt
652+
* nop
653+
* nop
654+
* bla:
655+
*/
656+
char code1[] = { 0x48, 0x8B, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0x48, 0x85, 0xC0, 0x74, 0x10, 0x48, 0x8B, 0x1C, 0x25, 0x08, 0x20, 0x00, 0x00, 0x48, 0x85, 0xC0, 0x74, 0x03, 0xF4, 0x90, 0x90 };
657+
658+
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
659+
OK(uc_ctl_tlb_mode(uc, UC_TLB_VIRTUAL));
660+
OK(uc_hook_add(uc, &hook1, UC_HOOK_TLB_FILL, test_virtual_write_tlb_fill, NULL, 1, 0));
661+
OK(uc_hook_add(uc, &hook2, UC_HOOK_BLOCK, &test_virtual_write_tb_invalidation_callback, &state, 1, 0));
662+
OK(uc_mem_map(uc, 0x0, 0x2000, UC_PROT_ALL));
663+
664+
OK(uc_vmem_write(uc, 0x1000, UC_PROT_EXEC, code1, sizeof(code1)));
665+
OK(uc_vmem_write(uc, 0x1800, UC_PROT_EXEC, code1, sizeof(code1)));
666+
OK(uc_vmem_write(uc, 0x2000, UC_PROT_READ, &rax1, sizeof(rax1)));
667+
OK(uc_vmem_write(uc, 0x2008, UC_PROT_READ, &rbx1, sizeof(rbx1)));
668+
OK(uc_vmem_write(uc, 0x2800, UC_PROT_READ, &rax2, sizeof(rax2)));
669+
OK(uc_vmem_write(uc, 0x2808, UC_PROT_READ, &rbx2, sizeof(rbx2)));
670+
671+
/*
672+
* run all code once to ensure that the tb are created
673+
*/
674+
OK(uc_emu_start(uc, 0x1000, 0, 0, 0));
675+
OK(uc_emu_start(uc, 0x1800, 0, 0, 0));
676+
677+
/*
678+
* state one:
679+
* run code1 at 0x1000
680+
* write code2 to 0x1800
681+
* run code2 at 0x1800
682+
*/
683+
state = 1;
684+
OK(uc_emu_start(uc, 0x1000, 0, 0, 0));
685+
OK(uc_emu_start(uc, 0x1800, 0, 0, 0));
686+
687+
OK(uc_reg_read(uc, UC_X86_REG_RAX, &res));
688+
TEST_CHECK(rax2 == res);
689+
OK(uc_reg_read(uc, UC_X86_REG_RBX, &res));
690+
TEST_CHECK(rbx2 == res);
691+
692+
state = 2;
693+
OK(uc_emu_start(uc, 0x1000, 0, 0, 0));
694+
OK(uc_emu_start(uc, 0x1800, 0, 0, 0));
695+
696+
OK(uc_reg_read(uc, UC_X86_REG_RAX, &res));
697+
TEST_CHECK(rax2 == res);
698+
OK(uc_reg_read(uc, UC_X86_REG_RBX, &res));
699+
TEST_CHECK(rbx1 == res);
700+
701+
OK(uc_close(uc));
702+
}
703+
592704
TEST_LIST = {{"test_map_correct", test_map_correct},
593705
{"test_map_wrapping", test_map_wrapping},
594706
{"test_mem_protect", test_mem_protect},
@@ -608,4 +720,5 @@ TEST_LIST = {{"test_map_correct", test_map_correct},
608720
test_mem_read_and_write_large_memory_block},
609721
{"test_virtual_to_physical", test_virtual_to_physical},
610722
{"test_virtual_write", test_virtual_write},
723+
{"test_virtual_write_tb_invalidation", test_virtual_write_tb_invalidation},
611724
{NULL, NULL}};

uc.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -900,14 +900,17 @@ uc_err uc_vmem_write(uc_engine *uc, uint64_t address, uc_prot prot,
900900
restore_jit_state(uc);
901901
return UC_ERR_WRITE_PROT;
902902
}
903-
if (uc_ctl_remove_cache(uc, address, address + len) != UC_ERR_OK) {
904-
restore_jit_state(uc);
905-
return UC_ERR_WRITE_PROT;
906-
}
903+
uc->uc_invalidate_tb(uc, address, len);
907904
bytes += len;
908905
address += len;
909906
count += len;
910907
}
908+
if (uc->nested_level) {
909+
uc->quit_request = true;
910+
uc->skip_sync_pc_on_exit = true;
911+
break_translation_loop(uc);
912+
}
913+
911914
assert(count == size);
912915
restore_jit_state(uc);
913916
return UC_ERR_OK;

0 commit comments

Comments
 (0)