From 3b7466b943b5126cb450f32b99d54bfb536e510d Mon Sep 17 00:00:00 2001 From: Marios Pomonis Date: Tue, 1 Apr 2025 01:43:18 -0700 Subject: executor/kvm: add x86-64 SYZOS fuzzer This commit adds the actual SyzOS fuzzer for x86-64 and a small test. It also updates some necessary parts of the ARM version and adds some glue for i386. --- executor/common_kvm_amd64_syzos.h | 96 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 executor/common_kvm_amd64_syzos.h (limited to 'executor/common_kvm_amd64_syzos.h') diff --git a/executor/common_kvm_amd64_syzos.h b/executor/common_kvm_amd64_syzos.h new file mode 100644 index 000000000..b98b33337 --- /dev/null +++ b/executor/common_kvm_amd64_syzos.h @@ -0,0 +1,96 @@ +// Copyright 2025 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 provides guest code running inside the AMD64 KVM. + +#include "kvm.h" +#include +#include + +// Host will map the code in this section into the guest address space. +#define GUEST_CODE __attribute__((section("guest"))) + +// Prevent function inlining. This attribute is applied to every guest_handle_* function, +// making sure they remain small so that the compiler does not attempt to be too clever +// (e.g. generate switch tables). +#define noinline __attribute__((noinline)) + +// Start/end of the guest section. +extern char *__start_guest, *__stop_guest; + +typedef enum { + SYZOS_API_UEXIT, + SYZOS_API_CODE, + SYZOS_API_STOP, // Must be the last one +} syzos_api_id; + +struct api_call_header { + uint64 call; + uint64 size; +}; + +struct api_call_uexit { + struct api_call_header header; + uint64 exit_code; +}; + +struct api_call_code { + struct api_call_header header; + uint8 insns[]; +}; + +static void guest_uexit(uint64 exit_code); +static void guest_execute_code(uint8* insns, uint64 size); + +typedef enum { + UEXIT_END = (uint64)-1, + UEXIT_IRQ = (uint64)-2, + UEXIT_ASSERT = (uint64)-3, +} uexit_code; + +// Main guest function that performs necessary setup and passes the control to the user-provided +// payload. +__attribute__((used)) +GUEST_CODE static void +guest_main(uint64 size, uint64 cpu) +{ + uint64 addr = X86_ADDR_USER_CODE + cpu * KVM_PAGE_SIZE; + + while (size >= sizeof(struct api_call_header)) { + struct api_call_header* cmd = (struct api_call_header*)addr; + if (cmd->call >= SYZOS_API_STOP) + return; + if (cmd->size > size) + return; + switch (cmd->call) { + case SYZOS_API_UEXIT: { + struct api_call_uexit* ucmd = (struct api_call_uexit*)cmd; + guest_uexit(ucmd->exit_code); + break; + } + case SYZOS_API_CODE: { + struct api_call_code* ccmd = (struct api_call_code*)cmd; + guest_execute_code(ccmd->insns, cmd->size - sizeof(struct api_call_header)); + break; + } + } + addr += cmd->size; + size -= cmd->size; + }; + guest_uexit((uint64)-1); +} + +GUEST_CODE static noinline void guest_execute_code(uint8* insns, uint64 size) +{ + volatile void (*fn)() = (volatile void (*)())insns; + fn(); +} + +// Perform a userspace exit that can be handled by the host. +// The host returns from ioctl(KVM_RUN) with kvm_run.exit_reason=KVM_EXIT_MMIO, +// and can handle the call depending on the data passed as exit code. +GUEST_CODE static noinline void guest_uexit(uint64 exit_code) +{ + volatile uint64* ptr = (volatile uint64*)X86_ADDR_UEXIT; + *ptr = exit_code; +} -- cgit mrf-deployment