Merge pull request #5 from schumilo/qemu-nyx-4.2.0-dev
Bug Fix: don't reuse ram_offset to blocklist specific PF
This commit is contained in:
commit
67b3f2545c
@ -1,6 +1,6 @@
|
||||
# QEMU-NYX
|
||||
|
||||
This repository contains Nyx's fork of Qemu. To enable Hypervisor based snapshots, Intel-PT based tracing, and Redqueen style magic byte resolution, we made various extensions to QEMU. This includes the ability to quickly reset memory and devices, ontain precise disassembly of the code running (even when code is partially swapped out / unavailable) & intel-PT decoding, instrument code running in the VM with breakpoint based hooks as well as communicating with a fuzzing frontend (e.g. based on libnyx).
|
||||
This repository contains Nyx's fork of QEMU. To enable Hypervisor based snapshots, Intel-PT based tracing, and REDQUEEN style magic byte resolution, we made various extensions to QEMU. This includes the ability to quickly reset memory and devices, obtain precise disassembly of the code running (even when code is partially swapped out / unavailable) & Intel-PT decoding, instrument code running in the VM with breakpoint-based hooks as well as communicating with a fuzzing frontend (e.g. based on [libnyx](https://github.com/nyx-fuzz/libnyx)).
|
||||
|
||||
You can find more detailed information in our main repository.
|
||||
|
||||
@ -20,7 +20,7 @@ If you found and fixed a bug on your own: We are very open to patches, please cr
|
||||
|
||||
### License
|
||||
|
||||
This tool is provided under **AGPL license**.
|
||||
This tool is provided under **GPLv2 license**.
|
||||
|
||||
**Free Software Hell Yeah!**
|
||||
|
||||
|
@ -81,15 +81,9 @@ compile () {
|
||||
echo "[!] QEMU-Nyx is ready!"
|
||||
}
|
||||
|
||||
cd libxdc
|
||||
git submodule init
|
||||
git submodule update
|
||||
cd ..
|
||||
|
||||
cd capstone_v4
|
||||
git submodule init
|
||||
git submodule update
|
||||
cd ..
|
||||
git submodule update libxdc
|
||||
git submodule update capstone_v4
|
||||
|
||||
if [ "$#" == 0 ] ; then
|
||||
error
|
||||
|
@ -18,6 +18,7 @@
|
||||
void nyx_abort(char* msg){
|
||||
set_abort_reason_auxiliary_buffer(GET_GLOBAL_STATE()->auxilary_buffer, msg, strlen(msg));
|
||||
synchronization_lock();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bool is_called_in_fuzzing_mode(const char* hypercall){
|
||||
@ -104,6 +105,10 @@ static void resize_coverage_bitmap(uint32_t new_bitmap_size){
|
||||
|
||||
/* pass the actual bitmap buffer size to the front-end */
|
||||
GET_GLOBAL_STATE()->auxilary_buffer->capabilites.agent_coverage_bitmap_size = new_bitmap_size;
|
||||
|
||||
if(new_bitmap_size & (PAGE_SIZE-1)){
|
||||
GET_GLOBAL_STATE()->shared_bitmap_size = (new_bitmap_size & ~(PAGE_SIZE-1)) + PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
bool apply_capabilities(CPUState *cpu){
|
||||
@ -127,6 +132,11 @@ bool apply_capabilities(CPUState *cpu){
|
||||
debug_printf("GET_GLOBAL_STATE()->cap_cr3: %lx\n", GET_GLOBAL_STATE()->cap_cr3);
|
||||
debug_printf("--------------------------\n");
|
||||
|
||||
if (GET_GLOBAL_STATE()->input_buffer_size != GET_GLOBAL_STATE()->shared_payload_buffer_size){
|
||||
resize_shared_memory(GET_GLOBAL_STATE()->input_buffer_size, &GET_GLOBAL_STATE()->shared_payload_buffer_size, NULL, GET_GLOBAL_STATE()->shared_payload_buffer_fd);
|
||||
GET_GLOBAL_STATE()->shared_payload_buffer_size = GET_GLOBAL_STATE()->input_buffer_size;
|
||||
}
|
||||
|
||||
if(GET_GLOBAL_STATE()->cap_compile_time_tracing_buffer_vaddr&0xfff){
|
||||
fprintf(stderr, "[QEMU-Nyx] Error: guest's trace bitmap v_addr (0x%lx) is not page aligned!\n", GET_GLOBAL_STATE()->cap_compile_time_tracing_buffer_vaddr);
|
||||
return false;
|
||||
@ -157,10 +167,6 @@ bool apply_capabilities(CPUState *cpu){
|
||||
set_cap_agent_ijon_trace_bitmap(GET_GLOBAL_STATE()->auxilary_buffer, true);
|
||||
}
|
||||
|
||||
if (GET_GLOBAL_STATE()->input_buffer_size != GET_GLOBAL_STATE()->shared_payload_buffer_size){
|
||||
resize_shared_memory(GET_GLOBAL_STATE()->input_buffer_size, &GET_GLOBAL_STATE()->shared_payload_buffer_size, NULL, GET_GLOBAL_STATE()->shared_payload_buffer_fd);
|
||||
GET_GLOBAL_STATE()->shared_payload_buffer_size = GET_GLOBAL_STATE()->input_buffer_size;
|
||||
}
|
||||
|
||||
/* pass the actual input buffer size to the front-end */
|
||||
GET_GLOBAL_STATE()->auxilary_buffer->capabilites.agent_input_buffer_size = GET_GLOBAL_STATE()->shared_payload_buffer_size;
|
||||
|
@ -12,6 +12,11 @@ void handle_hypercall_kafl_get_host_config(struct kvm_run *run, CPUState *cpu, u
|
||||
return;
|
||||
}
|
||||
|
||||
if (GET_GLOBAL_STATE()->get_host_config_done){
|
||||
nyx_abort((char*)"KVM_EXIT_KAFL_GET_HOST_CONFIG called twice...");
|
||||
return;
|
||||
}
|
||||
|
||||
memset((void*)&config, 0, sizeof(host_config_t));
|
||||
|
||||
config.host_magic = NYX_HOST_MAGIC;
|
||||
@ -21,6 +26,7 @@ void handle_hypercall_kafl_get_host_config(struct kvm_run *run, CPUState *cpu, u
|
||||
config.payload_buffer_size = GET_GLOBAL_STATE()->shared_payload_buffer_size;
|
||||
|
||||
write_virtual_memory(vaddr, (uint8_t*)&config, sizeof(host_config_t), cpu);
|
||||
GET_GLOBAL_STATE()->get_host_config_done = true;
|
||||
}
|
||||
|
||||
void handle_hypercall_kafl_set_agent_config(struct kvm_run *run, CPUState *cpu, uint64_t hypercall_arg){
|
||||
@ -31,6 +37,11 @@ void handle_hypercall_kafl_set_agent_config(struct kvm_run *run, CPUState *cpu,
|
||||
return;
|
||||
}
|
||||
|
||||
if (GET_GLOBAL_STATE()->set_agent_config_done){
|
||||
nyx_abort((char*)"KVM_EXIT_KAFL_SET_AGENT_CONFIG called twice...");
|
||||
return;
|
||||
}
|
||||
|
||||
X86CPU *cpux86 = X86_CPU(cpu);
|
||||
CPUX86State *env = &cpux86->env;
|
||||
|
||||
@ -89,4 +100,5 @@ void handle_hypercall_kafl_set_agent_config(struct kvm_run *run, CPUState *cpu,
|
||||
fprintf(stderr, "[QEMU-Nyx] Error: %s - failed (vaddr: 0x%lx)!\n", __func__, vaddr);
|
||||
exit(1);
|
||||
}
|
||||
GET_GLOBAL_STATE()->set_agent_config_done = true;
|
||||
}
|
@ -108,6 +108,12 @@ bool handle_hypercall_kafl_next_payload(struct kvm_run *run, CPUState *cpu, uint
|
||||
synchronization_lock();
|
||||
|
||||
} else {
|
||||
|
||||
if (GET_GLOBAL_STATE()->set_agent_config_done == false){
|
||||
nyx_abort((char*)"KVM_EXIT_KAFL_SET_AGENT_CONFIG was not called...");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!setup_snapshot_once){
|
||||
//pt_reset_bitmap();
|
||||
|
||||
@ -193,6 +199,11 @@ static void handle_hypercall_get_payload(struct kvm_run *run, CPUState *cpu, uin
|
||||
return;
|
||||
}
|
||||
|
||||
if (GET_GLOBAL_STATE()->get_host_config_done == false){
|
||||
nyx_abort((char*)"KVM_EXIT_KAFL_GET_HOST_CONFIG was not called...");
|
||||
return;
|
||||
}
|
||||
|
||||
if(hypercall_enabled && !setup_snapshot_once){
|
||||
QEMU_PT_PRINTF(CORE_PREFIX, "Payload Address:\t%lx", hypercall_arg);
|
||||
kvm_arch_get_registers(cpu);
|
||||
|
@ -167,13 +167,13 @@ bool remap_payload_slot(uint64_t phys_addr, uint32_t slot, CPUState *cpu){
|
||||
|
||||
uint32_t i = slot;
|
||||
|
||||
phys_addr = address_to_ram_offset(phys_addr);
|
||||
uint64_t phys_addr_ram_offset = address_to_ram_offset(phys_addr);
|
||||
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||
if(!memcmp(block->idstr, "pc.ram", 6)){
|
||||
/* TODO: put assert calls here */
|
||||
munmap((void*)(((uint64_t)block->host) + phys_addr), x86_64_PAGE_SIZE);
|
||||
mmap((void*)(((uint64_t)block->host) + phys_addr), 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, GET_GLOBAL_STATE()->shared_payload_buffer_fd, (i*x86_64_PAGE_SIZE));
|
||||
munmap((void*)(((uint64_t)block->host) + phys_addr_ram_offset), x86_64_PAGE_SIZE);
|
||||
mmap((void*)(((uint64_t)block->host) + phys_addr_ram_offset), 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, GET_GLOBAL_STATE()->shared_payload_buffer_fd, (i*x86_64_PAGE_SIZE));
|
||||
|
||||
//printf("MMUNMAP: %d\n", munmap((void*)(((uint64_t)block->host) + phys_addr), x86_64_PAGE_SIZE));
|
||||
//printf("MMAP: %p\n", mmap((void*)(((uint64_t)block->host) + phys_addr), 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, GET_GLOBAL_STATE()->shared_payload_buffer_fd, (i*x86_64_PAGE_SIZE)));
|
||||
@ -205,9 +205,8 @@ bool remap_slot(uint64_t addr, uint32_t slot, CPUState *cpu, int fd, uint64_t sh
|
||||
fprintf(stderr, "[QEMU-Nyx] Check if the buffer is present in the guest's memory...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
phys_addr = address_to_ram_offset(phys_addr);
|
||||
}
|
||||
uint64_t phys_addr_ram_offset = address_to_ram_offset(phys_addr);
|
||||
|
||||
//printf("phys_addr -> %lx\n", phys_addr);
|
||||
|
||||
@ -216,8 +215,8 @@ bool remap_slot(uint64_t addr, uint32_t slot, CPUState *cpu, int fd, uint64_t sh
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||
if(!memcmp(block->idstr, "pc.ram", 6)){
|
||||
/* TODO: put assert calls here */
|
||||
munmap((void*)(((uint64_t)block->host) + phys_addr), x86_64_PAGE_SIZE);
|
||||
mmap((void*)(((uint64_t)block->host) + phys_addr), 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, (i*x86_64_PAGE_SIZE));
|
||||
munmap((void*)(((uint64_t)block->host) + phys_addr_ram_offset), x86_64_PAGE_SIZE);
|
||||
mmap((void*)(((uint64_t)block->host) + phys_addr_ram_offset), 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, (i*x86_64_PAGE_SIZE));
|
||||
|
||||
//printf("MMUNMAP: %d\n", munmap((void*)(((uint64_t)block->host) + phys_addr), x86_64_PAGE_SIZE));
|
||||
//printf("MMAP: %p\n", mmap((void*)(((uint64_t)block->host) + phys_addr), 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, (i*x86_64_PAGE_SIZE)));
|
||||
@ -239,14 +238,14 @@ bool remap_payload_slot_protected(uint64_t phys_addr, uint32_t slot, CPUState *c
|
||||
|
||||
uint32_t i = slot;
|
||||
|
||||
phys_addr = address_to_ram_offset(phys_addr);
|
||||
uint64_t phys_addr_ram_offset = address_to_ram_offset(phys_addr);
|
||||
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||
if(!memcmp(block->idstr, "pc.ram", 6)){
|
||||
|
||||
/* TODO: put assert calls here */
|
||||
munmap((void*)(((uint64_t)block->host) + phys_addr), x86_64_PAGE_SIZE);
|
||||
mmap((void*)(((uint64_t)block->host) + phys_addr), 0x1000, PROT_READ , MAP_SHARED | MAP_FIXED, GET_GLOBAL_STATE()->shared_payload_buffer_fd, (i*x86_64_PAGE_SIZE));
|
||||
munmap((void*)(((uint64_t)block->host) + phys_addr_ram_offset), x86_64_PAGE_SIZE);
|
||||
mmap((void*)(((uint64_t)block->host) + phys_addr_ram_offset), 0x1000, PROT_READ , MAP_SHARED | MAP_FIXED, GET_GLOBAL_STATE()->shared_payload_buffer_fd, (i*x86_64_PAGE_SIZE));
|
||||
|
||||
//printf("MMUNMAP: %d\n", munmap((void*)(((uint64_t)block->host) + phys_addr), x86_64_PAGE_SIZE));
|
||||
//printf("MMAP: %p\n", mmap((void*)(((uint64_t)block->host) + phys_addr), 0x1000, PROT_READ , MAP_SHARED | MAP_FIXED, GET_GLOBAL_STATE()->shared_payload_buffer_fd, (i*x86_64_PAGE_SIZE)));
|
||||
@ -296,28 +295,28 @@ bool remap_payload_buffer(uint64_t virt_guest_addr, CPUState *cpu){
|
||||
|
||||
assert(phys_addr != INVALID_ADDRESS);
|
||||
|
||||
phys_addr = address_to_ram_offset(phys_addr);
|
||||
uint64_t phys_addr_ram_offset = address_to_ram_offset(phys_addr);
|
||||
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||
if(!memcmp(block->idstr, "pc.ram", 6)){
|
||||
//printf("MMUNMAP: %d\n", munmap((void*)(((uint64_t)block->host) + phys_addr), x86_64_PAGE_SIZE));
|
||||
if(munmap((void*)(((uint64_t)block->host) + phys_addr), x86_64_PAGE_SIZE) == -1){
|
||||
if(munmap((void*)(((uint64_t)block->host) + phys_addr_ram_offset), x86_64_PAGE_SIZE) == -1){
|
||||
fprintf(stderr, "munmap failed!\n");
|
||||
//exit(1);
|
||||
assert(false);
|
||||
}
|
||||
//printf("MMAP: %lx\n", mmap((void*)(((uint64_t)block->host) + phys_addr), 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, shared_payload_buffer_fd, (i*x86_64_PAGE_SIZE)));
|
||||
|
||||
if(mmap((void*)(((uint64_t)block->host) + phys_addr), 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, GET_GLOBAL_STATE()->shared_payload_buffer_fd, (i*x86_64_PAGE_SIZE)) == MAP_FAILED){
|
||||
if(mmap((void*)(((uint64_t)block->host) + phys_addr_ram_offset), 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, GET_GLOBAL_STATE()->shared_payload_buffer_fd, (i*x86_64_PAGE_SIZE)) == MAP_FAILED){
|
||||
fprintf(stderr, "mmap failed!\n");
|
||||
//exit(1);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
memset((block->host) + phys_addr, 0xab, 0x1000);
|
||||
memset((block->host) + phys_addr_ram_offset, 0xab, 0x1000);
|
||||
|
||||
if(GET_GLOBAL_STATE()->protect_payload_buffer){
|
||||
mprotect((block->host) + phys_addr, 0x1000, PROT_READ);
|
||||
mprotect((block->host) + phys_addr_ram_offset, 0x1000, PROT_READ);
|
||||
}
|
||||
|
||||
fast_reload_blacklist_page(get_fast_reload_snapshot(), phys_addr);
|
||||
|
@ -128,6 +128,10 @@ void deserialize_state(const char* filename_prefix){
|
||||
|
||||
assert(apply_capabilities(qemu_get_cpu(0)));
|
||||
remap_payload_buffer(nyx_global_state->payload_buffer, ((CPUState *)qemu_get_cpu(0)) );
|
||||
|
||||
/* makes sure that we are allowed to enter the fuzzing loop */
|
||||
nyx_global_state->get_host_config_done = true;
|
||||
nyx_global_state->set_agent_config_done = true;
|
||||
}
|
||||
else{
|
||||
fprintf(stderr, "[QEMU-Nyx]: this feature is currently missing\n");
|
||||
|
@ -107,6 +107,9 @@ void state_init_global(void){
|
||||
global_state.pt_trace_mode_force = false;
|
||||
|
||||
global_state.num_dirty_pages = 0;
|
||||
|
||||
global_state.get_host_config_done = false;
|
||||
global_state.set_agent_config_done = false;
|
||||
|
||||
global_state.sharedir = sharedir_new();
|
||||
|
||||
|
@ -139,6 +139,9 @@ typedef struct qemu_nyx_state_s{
|
||||
|
||||
uint32_t num_dirty_pages;
|
||||
|
||||
bool get_host_config_done;
|
||||
bool set_agent_config_done;
|
||||
|
||||
/* capabilites */
|
||||
uint8_t cap_timeout_detection;
|
||||
uint8_t cap_only_reload_mode;
|
||||
|
Loading…
x
Reference in New Issue
Block a user