aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
Diffstat (limited to 'executor')
-rw-r--r--executor/common.h6
-rw-r--r--executor/common_kvm_amd64.h (renamed from executor/common_kvm.h)29
-rw-r--r--executor/common_kvm_arm64.h84
-rw-r--r--executor/test_kvm.cc22
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.