diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-01-12 11:57:17 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-01-12 11:57:17 +0100 |
| commit | ff8c0180ab432ad1bf8671407f828078cda86551 (patch) | |
| tree | f2f6472e985c51cbf8125198cd562db715d69468 /executor | |
| parent | bcfae12bec951e6e4261a9910eab4b971f767329 (diff) | |
sys, executor: more kvm improvements
1. Basic support for arm64 kvm testing.
2. Fix compiler warnings in x86 kvm code.
3. Test all pseudo syz calls in csource.
4. Fix handling of real code in x86.
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. |
