aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
Diffstat (limited to 'executor')
-rw-r--r--executor/common_kvm_ppc64.h77
-rw-r--r--executor/common_linux.h2
-rw-r--r--executor/test.h4
-rw-r--r--executor/test_linux.h8
4 files changed, 89 insertions, 2 deletions
diff --git a/executor/common_kvm_ppc64.h b/executor/common_kvm_ppc64.h
new file mode 100644
index 000000000..f03ce42df
--- /dev/null
+++ b/executor/common_kvm_ppc64.h
@@ -0,0 +1,77 @@
+// Copyright 2020 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.
+// See Intel Software Developer’s Manual Volume 3: System Programming Guide
+// for details on what happens here.
+
+#include "kvm.h"
+
+struct kvm_text {
+ uintptr_t typ;
+ const void* text;
+ uintptr_t size;
+};
+
+// 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 long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4, volatile long a5, volatile long a6, volatile long 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 page_size = 16 << 10;
+ const uintptr_t guest_mem_size = 256 << 20;
+ const uintptr_t guest_mem = 0;
+
+ (void)text_count; // fuzzer can spoof count and we need just 1 text, so ignore text_count
+ const void* text = 0;
+ uintptr_t text_size = 0;
+ NONFAILING(text = text_array_ptr[0].text);
+ NONFAILING(text_size = text_array_ptr[0].size);
+
+ for (uintptr_t 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_regs regs;
+ struct kvm_sregs sregs;
+ if (ioctl(cpufd, KVM_GET_SREGS, &sregs))
+ return -1;
+ if (ioctl(cpufd, KVM_GET_REGS, &regs))
+ return -1;
+
+ // PPC64LE, real mode: MSR_LE | MSR_SF
+ regs.msr = 1ULL | (1ULL << 63);
+
+ memcpy(host_mem, text, text_size);
+
+ if (ioctl(cpufd, KVM_SET_SREGS, &sregs))
+ return -1;
+ if (ioctl(cpufd, KVM_SET_REGS, &regs))
+ return -1;
+
+ // Hypercalls need to be enable so we enable them all here to
+ // allow fuzzing
+#define MAX_HCALL 0x450
+ for (unsigned hcall = 4; hcall < MAX_HCALL; hcall += 4) {
+ struct kvm_enable_cap cap = {
+ .cap = KVM_CAP_PPC_ENABLE_HCALL,
+ .flags = 0,
+ .args = {hcall, 1},
+ };
+ ioctl(vmfd, KVM_ENABLE_CAP, &cap);
+ }
+
+ return 0;
+}
diff --git a/executor/common_linux.h b/executor/common_linux.h
index acb3acde7..16b78e99a 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -2905,6 +2905,8 @@ error_clear_loop:
#include "common_kvm_amd64.h"
#elif GOARCH_arm64
#include "common_kvm_arm64.h"
+#elif GOARCH_ppc64 || GOARCH_ppc64le
+#include "common_kvm_ppc64.h"
#elif !GOARCH_arm
static long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4, volatile long a5, volatile long a6, volatile long a7)
{
diff --git a/executor/test.h b/executor/test.h
index bd30fb372..37d03b65a 100644
--- a/executor/test.h
+++ b/executor/test.h
@@ -1,7 +1,7 @@
// 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.
-#if GOOS_linux && GOARCH_amd64
+#if GOOS_linux && (GOARCH_amd64 | GOARCH_ppc64 | GOARCH_ppc64le)
#include "test_linux.h"
#endif
@@ -208,7 +208,7 @@ static struct {
{"test_copyin", test_copyin},
{"test_csum_inet", test_csum_inet},
{"test_csum_inet_acc", test_csum_inet_acc},
-#if GOOS_linux && GOARCH_amd64
+#if GOOS_linux && (GOARCH_amd64 || GOARCH_ppc64 || GOARCH_ppc64le)
{"test_kvm", test_kvm},
#endif
};
diff --git a/executor/test_linux.h b/executor/test_linux.h
index fcd8d855e..428fba967 100644
--- a/executor/test_linux.h
+++ b/executor/test_linux.h
@@ -75,11 +75,13 @@ static int test_one(int text_type, const char* text, int text_size, int flags, u
dump_cpu_state(cpufd, (char*)vm_mem);
return 1;
}
+#ifdef GOARCH_amd64
if (check_rax && regs.rax != 0xbadc0de) {
printf("wrong result: rax=0x%llx\n", (long long)regs.rax);
dump_cpu_state(cpufd, (char*)vm_mem);
return 1;
}
+#endif
munmap(vm_mem, vm_mem_size);
munmap(cpu_mem, cpu_mem_size);
close(cpufd);
@@ -108,6 +110,7 @@ static int test_kvm()
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;
+#ifdef GOARCH_amd64
if ((res = test_one(8, text8, sizeof(text8) - 1, KVM_SETUP_VIRT86, KVM_EXIT_SHUTDOWN, true)))
return res;
if ((res = test_one(8, text8, sizeof(text8) - 1, KVM_SETUP_VIRT86 | KVM_SETUP_PAGING, KVM_EXIT_SHUTDOWN, true)))
@@ -161,6 +164,7 @@ static int test_kvm()
if ((res = test_one(32, text_rsm, sizeof(text_rsm) - 1, KVM_SETUP_SMM, KVM_EXIT_HLT, false)))
return res;
}
+#endif
return 0;
}
@@ -179,14 +183,17 @@ static unsigned host_kernel_version()
return major * 100 + minor;
}
+#ifdef GOARCH_amd64
static void dump_seg(const char* name, struct kvm_segment* seg)
{
printf("%s: base=0x%llx limit=0x%x sel=0x%x type=%d p=%d dpl=%d, db=%d s=%d l=%d g=%d\n",
name, seg->base, seg->limit, seg->selector, seg->type, seg->present, seg->dpl, seg->db, seg->s, seg->l, seg->g);
}
+#endif
static void dump_cpu_state(int cpufd, char* vm_mem)
{
+#ifdef GOARCH_amd64
struct kvm_sregs sregs;
if (ioctl(cpufd, KVM_GET_SREGS, &sregs)) {
printf("KVM_GET_SREGS failed (%d)\n", errno);
@@ -219,4 +226,5 @@ static void dump_cpu_state(int cpufd, char* vm_mem)
((long long*)vm_mem)[i], ((long long*)vm_mem)[i + 1], ((long long*)vm_mem)[i + 2], ((long long*)vm_mem)[i + 3]);
}
}
+#endif
}