diff options
Diffstat (limited to 'executor')
| -rw-r--r-- | executor/common_kvm_ppc64.h | 77 | ||||
| -rw-r--r-- | executor/common_linux.h | 2 | ||||
| -rw-r--r-- | executor/test.h | 4 | ||||
| -rw-r--r-- | executor/test_linux.h | 8 |
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, ®s)) + 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, ®s)) + 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 } |
