diff options
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common.h | 6 | ||||
| -rw-r--r-- | executor/common_kvm_amd64.h (renamed from executor/common_kvm.h) | 29 | ||||
| -rw-r--r-- | executor/common_kvm_arm64.h | 84 | ||||
| -rw-r--r-- | executor/test_kvm.cc | 22 |
4 files changed, 117 insertions, 24 deletions
diff --git a/executor/common.h b/executor/common.h index ba0303752..004dcc341 100644 --- a/executor/common.h +++ b/executor/common.h @@ -369,7 +369,11 @@ static uintptr_t syz_fuseblk_mount(uintptr_t a0, uintptr_t a1, uintptr_t a2, uin #endif #ifdef __NR_syz_kvm_setup_cpu -#include "common_kvm.h" +#if defined(__x86_64__) +#include "common_kvm_amd64.h" +#elif defined(__aarch64__) +#include "common_kvm_arm64.h" +#endif #endif // #ifdef __NR_syz_kvm_setup_cpu static uintptr_t execute_syscall(int nr, uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8) diff --git a/executor/common_kvm.h b/executor/common_kvm_amd64.h index 30055cb16..558026d5c 100644 --- a/executor/common_kvm.h +++ b/executor/common_kvm_amd64.h @@ -177,7 +177,8 @@ static void setup_32bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t g sregs->idt.base = guest_mem + ADDR_VAR_IDT; sregs->idt.limit = 0x1ff; uint64_t* idt = (uint64_t*)(host_mem + sregs->idt.base); - for (int i = 0; i < 32; i++) { + int i; + for (i = 0; i < 32; i++) { struct kvm_segment gate; gate.selector = i << 3; switch (i % 6) { @@ -229,7 +230,8 @@ static void setup_64bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t g sregs->idt.base = guest_mem + ADDR_VAR_IDT; sregs->idt.limit = 0x1ff; uint64_t* idt = (uint64_t*)(host_mem + sregs->idt.base); - for (int i = 0; i < 32; i++) { + int i; + for (i = 0; i < 32; i++) { struct kvm_segment gate; gate.selector = (i * 2) << 3; gate.type = (i & 1) ? 14 : 15; // interrupt or trap gate @@ -282,8 +284,7 @@ static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uin const uintptr_t guest_mem_size = 24 * page_size; const uintptr_t guest_mem = 0; - if (text_count != 1) - fail("syz_kvm_setup_cpu: bad text count %d, want 1", text_count); + (void)text_count; // fuzzer can spoof count and we need just 1 text, so ignore text_count int text_type = 0; const void* text = 0; int text_size = 0; @@ -534,7 +535,7 @@ static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uin fill_segment_descriptor_dword(gdt, ldt, &seg_cgate64); int kvmfd = open("/dev/kvm", O_RDWR); - char buf[sizeof(kvm_cpuid2) + 128 * sizeof(struct kvm_cpuid_entry2)]; + char buf[sizeof(struct kvm_cpuid2) + 128 * sizeof(struct kvm_cpuid_entry2)]; memset(buf, 0, sizeof(buf)); struct kvm_cpuid2* cpuid = (struct kvm_cpuid2*)buf; cpuid->nent = 128; @@ -546,7 +547,7 @@ static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uin int text_prefix_size = 0; char* host_text = host_mem + ADDR_TEXT; - if (text_type == 16) { + if (text_type == 8) { if (flags & KVM_SETUP_SMM) { if (flags & KVM_SETUP_PROTECTED) { sregs.cs = seg_cs16; @@ -584,19 +585,21 @@ static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uin text_prefix = kvm_asm32_vm86; text_prefix_size = sizeof(kvm_asm32_vm86) - 1; } - } else if (flags & KVM_SETUP_PROTECTED) { - sregs.cr0 |= CR0_PE; - sregs.cs = seg_cs16; - sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16; - } else if (flags & KVM_SETUP_CPL3) { + } else { + sregs.cs.selector = 0; + sregs.cs.base = 0; + } + } else if (text_type == 16) { + if (flags & KVM_SETUP_CPL3) { sregs.cs = seg_cs16; sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16; text_prefix = kvm_asm16_cpl3; text_prefix_size = sizeof(kvm_asm16_cpl3) - 1; } else { - sregs.cs.selector = 0; - sregs.cs.base = 0; + sregs.cr0 |= CR0_PE; + sregs.cs = seg_cs16; + sregs.ds = sregs.es = sregs.fs = sregs.gs = sregs.ss = seg_ds16; } } else if (text_type == 32) { sregs.cr0 |= CR0_PE; diff --git a/executor/common_kvm_arm64.h b/executor/common_kvm_arm64.h new file mode 100644 index 000000000..b3dadc87c --- /dev/null +++ b/executor/common_kvm_arm64.h @@ -0,0 +1,84 @@ +// Copyright 2017 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +// This file is shared between executor and csource package. + +// Implementation of syz_kvm_setup_cpu pseudo-syscall. + +struct kvm_text { + uintptr_t typ; + const void* text; + uintptr_t size; +}; + +struct kvm_opt { + uint64_t typ; + uint64_t val; +}; + +// syz_kvm_setup_cpu(fd fd_kvmvm, cpufd fd_kvmcpu, usermem vma[24], text ptr[in, array[kvm_text, 1]], ntext len[text], flags flags[kvm_setup_flags], opts ptr[in, array[kvm_setup_opt, 0:2]], nopt len[opts]) +static uintptr_t syz_kvm_setup_cpu(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7) +{ + const int vmfd = a0; + const int cpufd = a1; + char* const host_mem = (char*)a2; + const struct kvm_text* const text_array_ptr = (struct kvm_text*)a3; + const uintptr_t text_count = a4; + const uintptr_t flags = a5; + const struct kvm_opt* const opt_array_ptr = (struct kvm_opt*)a6; + uintptr_t opt_count = a7; + + (void)flags; + (void)opt_count; + + const uintptr_t page_size = 4 << 10; + const uintptr_t guest_mem = 0; + const uintptr_t guest_mem_size = 24 * page_size; + + (void)text_count; // fuzzer can spoof count and we need just 1 text, so ignore text_count + int text_type = 0; + const void* text = 0; + int text_size = 0; + NONFAILING(text_type = text_array_ptr[0].typ); + NONFAILING(text = text_array_ptr[0].text); + NONFAILING(text_size = text_array_ptr[0].size); + (void)text_type; + (void)opt_array_ptr; + + uint32_t features = 0; + if (opt_count > 1) + opt_count = 1; + uintptr_t i; + for (i = 0; i < opt_count; i++) { + uint64_t typ = 0; + uint64_t val = 0; + NONFAILING(typ = opt_array_ptr[i].typ); + NONFAILING(val = opt_array_ptr[i].val); + switch (typ) { + case 1: + features = val; + break; + } + } + + for (i = 0; i < guest_mem_size / page_size; i++) { + struct kvm_userspace_memory_region memreg; + memreg.slot = i; + memreg.flags = 0; // can be KVM_MEM_LOG_DIRTY_PAGES | KVM_MEM_READONLY + memreg.guest_phys_addr = guest_mem + i * page_size; + memreg.memory_size = page_size; + memreg.userspace_addr = (uintptr_t)host_mem + i * page_size; + ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg); + } + + struct kvm_vcpu_init init; + ioctl(cpufd, KVM_ARM_PREFERRED_TARGET, &init); + init.features[0] = features; + ioctl(cpufd, KVM_ARM_VCPU_INIT, &init); + + if (text_size > 1000) + text_size = 1000; + NONFAILING(memcpy(host_mem, text, text_size)); + + return 0; +} diff --git a/executor/test_kvm.cc b/executor/test_kvm.cc index ac696204b..4d990dc19 100644 --- a/executor/test_kvm.cc +++ b/executor/test_kvm.cc @@ -108,16 +108,18 @@ extern "C" int test_kvm() //if (res = test_one(32, text32_div0, sizeof(text32_div0)-1, 0, KVM_EXIT_HLT, true)) // return res; - const char text16[] = "\x66\xb8\xde\xc0\xad\x0b"; - if (res = test_one(16, text16, sizeof(text16) - 1, 0, KVM_EXIT_HLT, true)) + const char text8[] = "\x66\xb8\xde\xc0\xad\x0b"; + if (res = test_one(8, text8, sizeof(text8) - 1, 0, KVM_EXIT_HLT, true)) return res; - if (res = test_one(16, text16, sizeof(text16) - 1, KVM_SETUP_PROTECTED, KVM_EXIT_HLT, true)) + if (res = test_one(8, text8, sizeof(text8) - 1, KVM_SETUP_VIRT86, KVM_EXIT_SHUTDOWN, true)) return res; - if (res = test_one(16, text16, sizeof(text16) - 1, KVM_SETUP_CPL3, KVM_EXIT_SHUTDOWN, true)) + if (res = test_one(8, text8, sizeof(text8) - 1, KVM_SETUP_VIRT86 | KVM_SETUP_PAGING, KVM_EXIT_SHUTDOWN, true)) return res; - if (res = test_one(16, text16, sizeof(text16) - 1, KVM_SETUP_VIRT86, KVM_EXIT_SHUTDOWN, true)) + + const char text16[] = "\x66\xb8\xde\xc0\xad\x0b"; + if (res = test_one(16, text16, sizeof(text16) - 1, 0, KVM_EXIT_HLT, true)) return res; - if (res = test_one(16, text16, sizeof(text16) - 1, KVM_SETUP_VIRT86 | KVM_SETUP_PAGING, KVM_EXIT_SHUTDOWN, true)) + if (res = test_one(16, text16, sizeof(text16) - 1, KVM_SETUP_CPL3, KVM_EXIT_SHUTDOWN, true)) return res; const char text32[] = "\xb8\xde\xc0\xad\x0b"; @@ -142,14 +144,14 @@ extern "C" int test_kvm() // Note: SMM does not work on 3.13 kernels. if (ver >= 404) { - const char text16_smm[] = "\x66\xb8\xde\xc0\xad\x0b"; - if (res = test_one(16, text16_smm, sizeof(text16_smm) - 1, KVM_SETUP_SMM, KVM_EXIT_HLT, true)) + const char text8_smm[] = "\x66\xb8\xde\xc0\xad\x0b"; + if (res = test_one(8, text8_smm, sizeof(text8_smm) - 1, KVM_SETUP_SMM, KVM_EXIT_HLT, true)) return res; - if (res = test_one(16, text16_smm, sizeof(text16_smm) - 1, KVM_SETUP_SMM | KVM_SETUP_PROTECTED, KVM_EXIT_HLT, true)) + if (res = test_one(8, text8_smm, sizeof(text8_smm) - 1, KVM_SETUP_SMM | KVM_SETUP_PROTECTED, KVM_EXIT_HLT, true)) return res; //const char text32_smm[] = "\xb8\xde\xc0\xad\x0b"; - if (res = test_one(32, text16_smm, sizeof(text16_smm) - 1, KVM_SETUP_SMM, KVM_EXIT_HLT, true)) + if (res = test_one(32, text8_smm, sizeof(text8_smm) - 1, KVM_SETUP_SMM, KVM_EXIT_HLT, true)) return res; // Also ensure that we are actually in SMM. |
