From 639fe950d0217b16536400a5af94300ca108eb45 Mon Sep 17 00:00:00 2001 From: Tamas K Lengyel Date: Fri, 21 Feb 2025 22:06:46 -0500 Subject: [PATCH] Update tsffs.h --- xen/0001-TSFFS.patch | 379 ------------------------ xen/arch/x86/hvm/vmx/vmx.c | 3 +- xen/include/xen/sched.h | 2 - xen/include/xen/tsffs.h | 575 +++++++++++++++++++++++++++++-------- 4 files changed, 461 insertions(+), 498 deletions(-) delete mode 100644 xen/0001-TSFFS.patch diff --git a/xen/0001-TSFFS.patch b/xen/0001-TSFFS.patch deleted file mode 100644 index 7b637bf174..0000000000 --- a/xen/0001-TSFFS.patch +++ /dev/null @@ -1,379 +0,0 @@ -From eb65003ff273a7b0488f534ebe184d3bf9f076c0 Mon Sep 17 00:00:00 2001 -From: Tamas K Lengyel -Date: Fri, 2 Feb 2024 08:27:44 -0500 -Subject: [PATCH] TSFFS - ---- - xen/arch/x86/domctl.c | 3 + - xen/arch/x86/hvm/hypercall.c | 48 +++++++++++-- - xen/arch/x86/hvm/vmx/vmx.c | 2 + - xen/common/ubsan/ubsan.c | 3 + - xen/drivers/char/console.c | 5 ++ - xen/include/xen/kfx.h | 32 +++++++++ - xen/include/xen/sched.h | 4 ++ - xen/include/xen/tsffs.h | 131 +++++++++++++++++++++++++++++++++++ - 8 files changed, 223 insertions(+), 5 deletions(-) - create mode 100644 xen/include/xen/kfx.h - create mode 100644 xen/include/xen/tsffs.h - -diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c -index 9a72d57333..8b97186331 100644 ---- a/xen/arch/x86/domctl.c -+++ b/xen/arch/x86/domctl.c -@@ -21,6 +21,9 @@ - #include - #include - -+#include -+#include -+ - #include - #include - #include -diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c -index eeb73e1aa5..cdf6a9d61f 100644 ---- a/xen/arch/x86/hvm/hypercall.c -+++ b/xen/arch/x86/hvm/hypercall.c -@@ -11,6 +11,8 @@ - #include - #include - -+#include -+ - #include - #include - #include -@@ -104,8 +106,40 @@ int hvm_hypercall(struct cpu_user_regs *regs) - struct vcpu *curr = current; - struct domain *currd = curr->domain; - int mode = hvm_guest_x86_mode(curr); -- unsigned long eax = regs->eax; -+ unsigned long eax; - unsigned int token; -+ int ret; -+ -+ struct cpu_user_regs fme = *regs; -+ size_t _size = sizeof(struct cpu_user_regs); -+ HARNESS_START(&fme, &_size); -+ -+ regs->r8 = fme.r8; -+ regs->r9 = fme.r9; -+ regs->r10 = fme.r10; -+ regs->r11 = fme.r11; -+ regs->r12 = fme.r12; -+ regs->r13 = fme.r13; -+ regs->r14 = fme.r14; -+ regs->r15 = fme.r15; -+ regs->rax = fme.rax; -+ regs->rbx = fme.rbx; -+ regs->rcx = fme.rcx; -+ regs->rdx = fme.rdx; -+ regs->rsi = fme.rsi; -+ regs->rdi = fme.rdi; -+ regs->rip = fme.rip; -+ regs->rsp = fme.rsp; -+ regs->rbp = fme.rbp; -+ regs->rflags = fme.rflags; -+ regs->cs = fme.cs; -+ regs->ss = fme.ss; -+ regs->es = fme.es; -+ regs->ds = fme.ds; -+ regs->fs = fme.fs; -+ regs->gs = fme.gs; -+ -+ eax = regs->eax; - - switch ( mode ) - { -@@ -123,7 +157,8 @@ int hvm_hypercall(struct cpu_user_regs *regs) - { - default: - regs->rax = -EPERM; -- return HVM_HCALL_completed; -+ ret = HVM_HCALL_completed; -+ goto out; - } - case 0: - break; -@@ -131,8 +166,6 @@ int hvm_hypercall(struct cpu_user_regs *regs) - - if ( (eax & 0x80000000U) && is_viridian_domain(currd) ) - { -- int ret; -- - /* See comment below. */ - token = hvmemul_cache_disable(curr); - -@@ -140,7 +173,7 @@ int hvm_hypercall(struct cpu_user_regs *regs) - - hvmemul_cache_restore(curr, token); - -- return ret; -+ goto out; - } - - /* -@@ -188,7 +221,12 @@ int hvm_hypercall(struct cpu_user_regs *regs) - - perfc_incra(hypercalls, eax); - -+ HARNESS_STOP(); - return curr->hcall_preempted ? HVM_HCALL_preempted : HVM_HCALL_completed; -+ -+ out: -+ HARNESS_STOP(); -+ return ret; - } - - enum mc_disposition hvm_do_multicall_call(struct mc_state *state) -diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c -index 1500dca603..9e1230ee45 100644 ---- a/xen/arch/x86/hvm/vmx/vmx.c -+++ b/xen/arch/x86/hvm/vmx/vmx.c -@@ -4780,6 +4780,8 @@ bool asmlinkage vmx_vmenter_helper(const struct cpu_user_regs *regs) - struct hvm_vcpu_asid *p_asid; - bool need_flush; - -+ HARNESS_STOP(); -+ - ASSERT(hvmemul_cache_disabled(curr)); - - /* Shadow EPTP can't be updated here because irqs are disabled */ -diff --git a/xen/common/ubsan/ubsan.c b/xen/common/ubsan/ubsan.c -index 5d50c10742..6f734aa473 100644 ---- a/xen/common/ubsan/ubsan.c -+++ b/xen/common/ubsan/ubsan.c -@@ -13,6 +13,9 @@ - #include - #include - -+#include -+#include -+ - #define __noreturn noreturn - #define pr_err(...) printk(XENLOG_ERR __VA_ARGS__) - struct xen_ubsan { int in_ubsan; }; -diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c -index dce0226e87..d7a2751bcd 100644 ---- a/xen/drivers/char/console.c -+++ b/xen/drivers/char/console.c -@@ -33,6 +33,9 @@ - #include - #include - -+#include -+#include -+ - #ifdef CONFIG_X86 - #include - #include -@@ -1269,6 +1272,8 @@ void panic(const char *fmt, ...) - static DEFINE_SPINLOCK(lock); - static char buf[128]; - -+ HARNESS_ASSERT(); -+ - spin_debug_disable(); - spinlock_profile_printall('\0'); - debugtrace_dump(); -diff --git a/xen/include/xen/kfx.h b/xen/include/xen/kfx.h -new file mode 100644 -index 0000000000..afde305796 ---- /dev/null -+++ b/xen/include/xen/kfx.h -@@ -0,0 +1,32 @@ -+#ifndef KFX_H -+#define KFX_H -+ -+static inline void harness_extended(unsigned int magic, void *a, size_t s) -+{ -+ asm volatile ("cpuid" -+ : "=a" (magic), "=c" (magic), "=S" (magic) -+ : "a" (magic), "c" (s), "S" (a) -+ : "bx", "dx"); -+} -+ -+static inline void harness(void) -+{ -+ unsigned int tmp; -+ -+ asm volatile ("cpuid" -+ : "=a" (tmp) -+ : "a" (0x13371337) -+ : "bx", "cx", "dx"); -+} -+ -+static inline void kfx_sink(void) -+{ -+ unsigned int tmp; -+ -+ asm volatile ("int3" -+ : "=a" (tmp) -+ : "a" (0x13371337) -+ : "bx", "cx", "dx"); -+} -+ -+#endif -diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h -index 9da91e0e62..8f04f6110f 100644 ---- a/xen/include/xen/sched.h -+++ b/xen/include/xen/sched.h -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -792,6 +793,9 @@ void vcpu_end_shutdown_deferral(struct vcpu *v); - void __domain_crash(struct domain *d); - #define domain_crash(d, ...) \ - do { \ -+ HARNESS_STOP(); \ -+ __arch_harness_stop(MAGIC_ALT_0); \ -+ __arch_harness_stop(MAGIC_ALT_1); \ - if ( count_args(__VA_ARGS__) == 0 ) \ - printk(XENLOG_ERR "domain_crash called from %s:%d\n", \ - __FILE__, __LINE__); \ -diff --git a/xen/include/xen/tsffs.h b/xen/include/xen/tsffs.h -new file mode 100644 -index 0000000000..c2afe7ace3 ---- /dev/null -+++ b/xen/include/xen/tsffs.h -@@ -0,0 +1,131 @@ -+/// Definitions and macros for compiled-in harnessing of C and C++ target -+/// software for the RISC-V (64-bit) architecture -+/// -+/// Example: -+/// ```c -+/// #include "tsffs-gcc-x86_64.h" -+/// -+/// int main() { -+/// char buf[0x10]; -+/// size_t size = 0x10; -+/// size_t *size_ptr = &size; -+/// HARNESS_START((char *)buf, size_ptr); -+/// int retval = YourSpecialDecoder(buf, *size_ptr); -+/// if (!retval) { -+/// HARNESS_ASSERT(); -+/// } else { -+/// HARNESS_STOP(); -+/// } -+/// } -+/// ``` -+ -+#ifndef TSFFS_H -+#define TSFFS_H -+ -+/// Define common with LibFuzzer and other fuzzers to allow code that is -+/// fuzzing-specific to be left in the codebase. See -+/// https://llvm.org/docs/LibFuzzer.html#id35 for more information -+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -+#define FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION (1) -+#endif // FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -+ -+/// Magic value defined by SIMICS as the "leaf" value of a CPUID instruction -+/// that is treated as a magic instruction. -+#define MAGIC (0x4711U) -+/// Default magic instruction `n` value to signal the TSFFS fuzzer to start the -+/// fuzzing loop -+#define MAGIC_START (0x0001U) -+/// Default magic instruction `n` value to signal the TSFFS fuzzer to stop and -+/// reset the fuzzing loop -+#define MAGIC_STOP (0x0002U) -+/// Default magic instruction `n` value to signal the TSFFS fuzzer that an error -+/// has occurred and the testcase input should be saved as a solution -+#define MAGIC_ASSERT (0x0003U) -+ -+/// Alternative magic numbers that can be used for start and stop events in -+/// conjunction with setting the magic number for each event via the SIMICS or -+/// SIMICS Python script interface -+#define MAGIC_ALT_0 (0x0004U) -+#define MAGIC_ALT_1 (0x0005U) -+#define MAGIC_ALT_2 (0x0006U) -+#define MAGIC_ALT_3 (0x0007U) -+#define MAGIC_ALT_4 (0x0008U) -+#define MAGIC_ALT_5 (0x0009U) -+#define MAGIC_ALT_6 (0x000aU) -+#define MAGIC_ALT_7 (0x000bU) -+ -+/// Invoke the magic instruction defined by SIMICS for the x86-64 architecture -+/// (`cpuid`) with a specific value of `n`, after setting register `rdi` to the -+/// value of the pointer to the testcase and register `rsi` to the value of the -+/// pointer to the testcase size. These registers are accessed by the fuzzer and -+/// are defined per-architecture. -+#define __cpuid_extended2(value, inout_ptr_0, inout_ptr_1) \ -+ unsigned int _a __attribute__((unused)) = 0; \ -+ __asm__ __volatile__("cpuid" \ -+ : "=a"(_a) \ -+ : "a"(value), "D"(inout_ptr_0), "S"(inout_ptr_1) \ -+ : "rbx", "rcx", "rdx"); -+ -+/// Invoke the magic instruction defined by SIMICS for the x86-64 architecture -+/// (`cpuid`) with a specific value of `n` -+#define __cpuid(value) \ -+ unsigned int _a __attribute__((unused)) = 0; \ -+ __asm__ __volatile__("cpuid\n\t" \ -+ : "=a"(_a) \ -+ : "a"(value) \ -+ : "rbx", "rcx", "rdx") -+ -+/// Signal the fuzzer using a specific magic value `start` to start the fuzzing -+/// loop at the point this macro is called. A snapshot will be taken when the -+/// macro is called, and the maximum testcase size `*size_ptr` will be saved as -+/// `max_testcase_size`. Each iteration of the fuzzing loop, the fuzzer input -+/// (the "testcase") will be written to `*testcase_ptr` as if running -+/// `memcpy(testcase_ptr, current_testcase, max_testcase_size)`, and the actual -+/// size of the current testcase will be written to -+/// `*size_ptr` as if running `*size_ptr = current_testcase_size`. -+#define __arch_harness_start(start, testcase_ptr, size_ptr) \ -+ do { \ -+ unsigned int magic = (start << 0x10U) | MAGIC; \ -+ __cpuid_extended2(magic, testcase_ptr, size_ptr); \ -+ } while (0) -+ -+/// Signal the fuzzer using the a specific magic value (`stop`) to stop and -+/// reset to the beginning of the fuzzing loop with a "normal" stop status, -+/// indicating no solution has occurred. -+#define __arch_harness_stop(stop) \ -+ do { \ -+ unsigned int magic = (stop << 0x10U) | MAGIC; \ -+ __cpuid(magic); \ -+ } while (0) -+ -+/// Signal the fuzzer using the default magic value to start the fuzzing loop at -+/// the point this macro is called. A snapshot will be taken when the macro is -+/// called, and the maximum testcase size `*size_ptr` will be saved as -+/// `max_testcase_size`. Each iteration of the fuzzing loop, the fuzzer input -+/// (the "testcase") will be written to -+/// `*testcase_ptr` as if running `memcpy(testcase_ptr, current_testcase, -+/// max_testcase_size)`, and the actual size of the current testcase will be -+/// written to -+/// `*size_ptr` as if running `*size_ptr = current_testcase_size`. -+#define HARNESS_START(testcase_ptr, size_ptr) \ -+ do { \ -+ __arch_harness_start(MAGIC_START, testcase_ptr, size_ptr); \ -+ } while (0) -+ -+/// Signal the fuzzer using the default magic value to stop and reset to the -+/// beginning of the fuzzing loop with a "normal" stop status, indicating no -+/// solution has occurred. -+#define HARNESS_STOP() \ -+ do { \ -+ __arch_harness_stop(MAGIC_STOP); \ -+ } while (0) -+ -+/// Signal the fuzzer using the default magic value to stop and reset to the -+/// beginning of the fuzzing loop with a "solution" stop status, indicating some -+/// custom error has occurred. -+#define HARNESS_ASSERT() \ -+ do { \ -+ __arch_harness_stop(MAGIC_ASSERT); \ -+ } while (0) -+ -+#endif // TSFFS_H -\ No newline at end of file --- -2.34.1 - diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index d6effaefc7..34aaefa2bf 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -4073,9 +4073,8 @@ void asmlinkage vmx_vmexit_handler(struct cpu_user_regs *regs) __vmread(GUEST_RSP, ®s->rsp); __vmread(GUEST_RFLAGS, ®s->rflags); - tsffs_size = sizeof(struct tsffs_fme); memcpy(&tsffs_fme.regs, regs, sizeof(struct cpu_user_regs)); - HARNESS_START(&tsffs_fme, &tsffs_size); + HARNESS_START_WITH_MAXIMUM_SIZE(&tsffs_fme, sizeof(struct tsffs_fme)); regs->r8 = tsffs_fme.regs.r8; regs->r9 = tsffs_fme.regs.r9; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 4341e55c7e..8931e15159 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -818,8 +818,6 @@ void __domain_crash(struct domain *d); #define domain_crash(d, ...) \ do { \ HARNESS_STOP(); \ - __arch_harness_stop(MAGIC_ALT_0); \ - __arch_harness_stop(MAGIC_ALT_1); \ if ( count_args(__VA_ARGS__) == 0 ) \ printk(XENLOG_ERR "domain_crash called from %s:%d\n", \ __FILE__, __LINE__); \ diff --git a/xen/include/xen/tsffs.h b/xen/include/xen/tsffs.h index 874b629200..865adc2c94 100644 --- a/xen/include/xen/tsffs.h +++ b/xen/include/xen/tsffs.h @@ -1,23 +1,8 @@ +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + /// Definitions and macros for compiled-in harnessing of C and C++ target -/// software for the RISC-V (64-bit) architecture -/// -/// Example: -/// ```c -/// #include "tsffs-gcc-x86_64.h" -/// -/// int main() { -/// char buf[0x10]; -/// size_t size = 0x10; -/// size_t *size_ptr = &size; -/// HARNESS_START((char *)buf, size_ptr); -/// int retval = YourSpecialDecoder(buf, *size_ptr); -/// if (!retval) { -/// HARNESS_ASSERT(); -/// } else { -/// HARNESS_STOP(); -/// } -/// } -/// ``` +/// software for the x86_64 architecture. #ifndef TSFFS_H #define TSFFS_H @@ -29,104 +14,465 @@ #define FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION (1) #endif // FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +/// __cpuid +/// +/// Invoke the CPUID instruction with a specific value `value` in register +/// `rax`. +/// +/// # Arguments +/// +/// - `value`: The value to load into the `rax` register before invoking the +/// CPUID instruction +#define __cpuid(value) \ + unsigned int _a __attribute__((unused)) = 0; \ + unsigned int _b __attribute__((unused)) = 0; \ + unsigned int _c __attribute__((unused)) = 0; \ + unsigned int _d __attribute__((unused)) = 0; \ + __asm__ __volatile__("cpuid\n\t" \ + : "=a"(_a), "=b"(_b), "=c"(_c), "=d"(_d) \ + : "a"(value)); + +/// __cpuid_extended1 +/// +/// Invoke the CPUID instruction with a specific value `value` in register +/// `rax` and a pseudo-argument in register `rdi`. +/// +/// # Arguments +/// +/// - `value`: The value to load into the `rax` register before invoking the +/// CPUID instruction +/// - `arg0`: The value to load into the `rdi` register before invoking the +/// CPUID instruction +#define __cpuid_extended1(value, arg0) \ + unsigned int _a __attribute__((unused)) = 0; \ + unsigned int _b __attribute__((unused)) = 0; \ + unsigned int _c __attribute__((unused)) = 0; \ + unsigned int _d __attribute__((unused)) = 0; \ + __asm__ __volatile__("cpuid\n\t" \ + : "=a"(_a), "=b"(_b), "=c"(_c), "=d"(_d) \ + : "a"(value), "D"(arg0)); + +/// __cpuid_extended2 +/// +/// Invoke the CPUID instruction with a specific value `value` in register +/// `rax` and a pseudo-arguments in registers `rdi` and `rsi`. +/// +/// # Arguments +/// +/// - `value`: The value to load into the `rax` register before invoking the +/// CPUID instruction +/// - `arg0`: The value to load into the `rdi` register before invoking the +/// CPUID instruction +/// - `arg1`: The value to load into the `rsi` register before invoking the +/// CPUID instruction +#define __cpuid_extended2(value, arg0, arg1) \ + unsigned int _a __attribute__((unused)) = 0; \ + unsigned int _b __attribute__((unused)) = 0; \ + unsigned int _c __attribute__((unused)) = 0; \ + unsigned int _d __attribute__((unused)) = 0; \ + __asm__ __volatile__("cpuid\n\t" \ + : "=a"(_a), "=b"(_b), "=c"(_c), "=d"(_d) \ + : "a"(value), "D"(arg0), "S"(arg1)); + +/// __cpuid_extended3 +/// +/// Invoke the CPUID instruction with a specific value `value` in register +/// `rax` and a pseudo-arguments in registers `rdi`, `rsi`, and `rdx`. +/// +/// # Arguments +/// +/// - `value`: The value to load into the `rax` register before invoking the +/// CPUID instruction +/// - `arg0`: The value to load into the `rdi` register before invoking the +/// CPUID instruction +/// - `arg1`: The value to load into the `rsi` register before invoking the +/// CPUID instruction +/// - `arg2`: The value to load into the `rdx` register before invoking the +/// CPUID instruction +#define __cpuid_extended3(value, arg0, arg1, arg2) \ + unsigned int _a __attribute__((unused)) = 0; \ + unsigned int _b __attribute__((unused)) = 0; \ + unsigned int _c __attribute__((unused)) = 0; \ + unsigned int _d __attribute__((unused)) = 0; \ + __asm__ __volatile__("cpuid\n\t" \ + : "=a"(_a), "=b"(_b), "=c"(_c), "=d"(_d) \ + : "a"(value), "D"(arg0), "S"(arg1), "d"(arg2)); + +/// __cpuid_extended4 +/// +/// Invoke the CPUID instruction with a specific value `value` in register +/// `rax` and a pseudo-arguments in registers `rdi`, `rsi`, `rdx`, and `rcx`. +/// +/// # Arguments +/// +/// - `value`: The value to load into the `rax` register before invoking the +/// CPUID instruction +/// - `arg0`: The value to load into the `rdi` register before invoking the +/// CPUID instruction +/// - `arg1`: The value to load into the `rsi` register before invoking the +/// CPUID instruction +/// - `arg2`: The value to load into the `rdx` register before invoking the +/// CPUID instruction +/// - `arg3`: The value to load into the `rcx` register before invoking the +/// CPUID instruction +#define __cpuid_extended4(value, arg0, arg1, arg2, arg3) \ + unsigned int _a __attribute__((unused)) = 0; \ + unsigned int _b __attribute__((unused)) = 0; \ + unsigned int _c __attribute__((unused)) = 0; \ + unsigned int _d __attribute__((unused)) = 0; \ + __asm__ __volatile__("cpuid\n\t" \ + : "=a"(_a), "=b"(_b), "=c"(_c), "=d"(_d) \ + : "a"(value), "D"(arg0), "S"(arg1), "d"(arg2), \ + "c"(arg3)); + /// Magic value defined by SIMICS as the "leaf" value of a CPUID instruction /// that is treated as a magic instruction. #define MAGIC (0x4711U) -/// Default magic instruction `n` value to signal the TSFFS fuzzer to start the -/// fuzzing loop -#define MAGIC_START (0x0001U) -/// Default magic instruction `n` value to signal the TSFFS fuzzer to stop and -/// reset the fuzzing loop -#define MAGIC_STOP (0x0002U) -/// Default magic instruction `n` value to signal the TSFFS fuzzer that an error -/// has occurred and the testcase input should be saved as a solution -#define MAGIC_ASSERT (0x0003U) - -/// Alternative magic numbers that can be used for start and stop events in -/// conjunction with setting the magic number for each event via the SIMICS or -/// SIMICS Python script interface -#define MAGIC_ALT_0 (0x0004U) -#define MAGIC_ALT_1 (0x0005U) -#define MAGIC_ALT_2 (0x0006U) -#define MAGIC_ALT_3 (0x0007U) -#define MAGIC_ALT_4 (0x0008U) -#define MAGIC_ALT_5 (0x0009U) -#define MAGIC_ALT_6 (0x000aU) -#define MAGIC_ALT_7 (0x000bU) - -/// Invoke the magic instruction defined by SIMICS for the x86-64 architecture -/// (`cpuid`) with a specific value of `n`, after setting register `rdi` to the -/// value of the pointer to the testcase and register `rsi` to the value of the -/// pointer to the testcase size. These registers are accessed by the fuzzer and -/// are defined per-architecture. -#define __cpuid_extended2(value, inout_ptr_0, inout_ptr_1) \ - unsigned int _a __attribute__((unused)) = 0; \ - __asm__ __volatile__("cpuid" \ - : "=a"(_a) \ - : "a"(value), "D"(inout_ptr_0), "S"(inout_ptr_1) \ - : "rbx", "rcx", "rdx"); - -/// Invoke the magic instruction defined by SIMICS for the x86-64 architecture -/// (`cpuid`) with a specific value of `n` -#define __cpuid(value) \ - unsigned int _a __attribute__((unused)) = 0; \ - __asm__ __volatile__("cpuid\n\t" \ - : "=a"(_a) \ - : "a"(value) \ - : "rbx", "rcx", "rdx") - -/// Signal the fuzzer using a specific magic value `start` to start the fuzzing -/// loop at the point this macro is called. A snapshot will be taken when the -/// macro is called, and the maximum testcase size `*size_ptr` will be saved as -/// `max_testcase_size`. Each iteration of the fuzzing loop, the fuzzer input -/// (the "testcase") will be written to `*testcase_ptr` as if running -/// `memcpy(testcase_ptr, current_testcase, max_testcase_size)`, and the actual -/// size of the current testcase will be written to -/// `*size_ptr` as if running `*size_ptr = current_testcase_size`. -#define __arch_harness_start(start, testcase_ptr, size_ptr) \ - do { \ - unsigned int magic = (start << 0x10U) | MAGIC; \ - __cpuid_extended2(magic, testcase_ptr, size_ptr); \ - } while (0) - -/// Signal the fuzzer using the a specific magic value (`stop`) to stop and -/// reset to the beginning of the fuzzing loop with a "normal" stop status, -/// indicating no solution has occurred. -#define __arch_harness_stop(stop) \ - do { \ - unsigned int magic = (stop << 0x10U) | MAGIC; \ - __cpuid(magic); \ - } while (0) - -/// Signal the fuzzer using the default magic value to start the fuzzing loop at -/// the point this macro is called. A snapshot will be taken when the macro is -/// called, and the maximum testcase size `*size_ptr` will be saved as -/// `max_testcase_size`. Each iteration of the fuzzing loop, the fuzzer input -/// (the "testcase") will be written to -/// `*testcase_ptr` as if running `memcpy(testcase_ptr, current_testcase, -/// max_testcase_size)`, and the actual size of the current testcase will be -/// written to -/// `*size_ptr` as if running `*size_ptr = current_testcase_size`. -#define HARNESS_START(testcase_ptr, size_ptr) \ - do { \ - __arch_harness_start(MAGIC_START, testcase_ptr, size_ptr); \ - } while (0) - -/// Signal the fuzzer using the default magic value to stop and reset to the -/// beginning of the fuzzing loop with a "normal" stop status, indicating no -/// solution has occurred. -#define HARNESS_STOP() \ - do { \ - __arch_harness_stop(MAGIC_STOP); \ - } while (0) - -/// Signal the fuzzer using the default magic value to stop and reset to the -/// beginning of the fuzzing loop with a "solution" stop status, indicating some -/// custom error has occurred. -#define HARNESS_ASSERT() \ - do { \ - __arch_harness_stop(MAGIC_ASSERT); \ - } while (0) + +/// The default index number used for magic instructions. All magic instructions +/// support multiple start and stop indices, which defaults to 0 if not +/// specified. +#define DEFAULT_INDEX (0x0000U) + +/// Pseudo-hypercall number to signal the fuzzer to use the first argument to +/// the magic instruction as the pointer to the testcase buffer and the second +/// argument as a pointer to the size of the testcase buffer. +#define N_START_BUFFER_PTR_SIZE_PTR (0x0001U) + +/// HARNESS_START +/// +/// Signal the fuzzer to start the fuzzing loop at the point this macro is +/// called. The default "index" of 0 will be used. If you need multiple start +/// harnesses compiled into the same binary, you can use the +/// `HARNESS_START_INDEX` macro to specify different indices, then enable them +/// at runtime by configuring the fuzzer. +/// +/// When this macro is called: +/// +/// - A snapshot will be taken and saved +/// - The buffer pointed to by `buffer` will be saved and used as the testcase +/// buffer. Each +/// fuzzing iteration, a new test case will be written to this buffer. +/// - The size of the buffer pointed to by `size_ptr` will be saved as the +/// maximum testcase size. Each fuzzing iteration, the actual size of the +/// current testcase will be written to `*size_ptr`. +/// +/// # Arguments +/// +/// - `buffer`: The pointer to the testcase buffer +/// - `size_ptr`: The pointer to the size of the testcase buffer +/// +/// # Example +/// +/// ``` +/// unsigned char buffer[1024]; +/// size_t size; +/// HARNESS_START(buffer, &size); +/// ``` +#define HARNESS_START(buffer, size_ptr) \ + do { \ + unsigned int value = (N_START_BUFFER_PTR_SIZE_PTR << 0x10U) | MAGIC; \ + __cpuid_extended3(value, DEFAULT_INDEX, buffer, size_ptr); \ + } while (0); + +/// HARNESS_START_INDEX +/// +/// Signal the fuzzer to start the fuzzing loop at the point this macro is +/// called. The index specified by `start_index` will be used. If you need +/// multiple start harnesses compiled into the same binary, you can use this +/// macro to specify different indices, then enable them at runtime by +/// configuring the fuzzer. +/// +/// When this macro is called: +/// +/// - A snapshot will be taken and saved +/// - The buffer pointed to by `buffer` will be saved and used as the testcase +/// buffer. Each +/// fuzzing iteration, a new test case will be written to this buffer. +/// - The size of the buffer pointed to by `size_ptr` will be saved as the +/// maximum testcase size. Each fuzzing iteration, the actual size of the +/// current testcase will be written to `*size_ptr`. +/// +/// # Arguments +/// +/// - `start_index`: The index to use for this start harness +/// - `buffer`: The pointer to the testcase buffer +/// - `size_ptr`: The pointer to the size of the testcase buffer +/// +/// # Example +/// +/// ``` +/// unsigned char buffer[1024]; +/// size_t size; +/// HARNESS_START_INDEX(0x0001U, buffer, &size); +/// ``` +#define HARNESS_START_INDEX(start_index, buffer, size_ptr) \ + do { \ + unsigned int value = (N_START_BUFFER_PTR_SIZE_PTR << 0x10U) | MAGIC; \ + __cpuid_extended3(value, start_index, buffer, size_ptr); \ + } while (0); + +/// Pseudo-hypercall number to signal the fuzzer to use the first argument to +/// the magic instruction as the pointer to the testcase buffer and the second +/// argument as the maximum size of the testcase buffer. +#define N_START_BUFFER_PTR_SIZE_VAL (0x0002U) + +/// HARNESS_START_WITH_MAXIMUM_SIZE +/// +/// Signal the fuzzer to start the fuzzing loop at the point this macro is +/// called. The default "index" of 0 will be used. If you need multiple start +/// harnesses compiled into the same binary, you can use the +/// `HARNESS_START_WITH_MAXIMUM_SIZE_INDEX` macro to specify different indices, +/// then enable them at runtime by configuring the fuzzer. +/// +/// When this macro is called: +/// +/// - A snapshot will be taken and saved +/// - The buffer pointed to by `buffer` will be saved and used as the testcase +/// buffer. Each +/// fuzzing iteration, a new test case will be written to this buffer. +/// - The `max_size` value will be saved as the maximum testcase size. Fuzzing +/// test cases will be truncated to this size before being written to the +/// buffer. +/// +/// # Arguments +/// +/// - `buffer`: The pointer to the testcase buffer +/// - `max_size`: The maximum size of the testcase buffer +/// +/// # Example +/// +/// ``` +/// unsigned char buffer[1024]; +/// HARNESS_START_WITH_MAXIMUM_SIZE(buffer, 1024); +/// ``` +#define HARNESS_START_WITH_MAXIMUM_SIZE(buffer, max_size) \ + do { \ + unsigned int value = (N_START_BUFFER_PTR_SIZE_VAL << 0x10U) | MAGIC; \ + __cpuid_extended3(value, DEFAULT_INDEX, buffer, max_size); \ + } while (0); + +/// HARNESS_START_WITH_MAXIMUM_SIZE_INDEX +/// +/// Signal the fuzzer to start the fuzzing loop at the point this macro is +/// called. The index specified by `start_index` will be used. If you need +/// multiple start harnesses compiled into the same binary, you can use this +/// macro to specify different indices, then enable them at runtime by +/// configuring the fuzzer. +/// +/// When this macro is called: +/// +/// - A snapshot will be taken and saved +/// - The buffer pointed to by `buffer` will be saved and used as the testcase +/// buffer. Each +/// fuzzing iteration, a new test case will be written to this buffer. +/// - The `max_size` value will be saved as the maximum testcase size. Fuzzing +/// test cases will be truncated to this size before being written to the +/// buffer. +/// +/// # Arguments +/// +/// - `start_index`: The index to use for this start harness +/// - `buffer`: The pointer to the testcase buffer +/// - `max_size`: The maximum size of the testcase buffer +/// +/// # Example +/// +/// ``` +/// unsigned char buffer[1024]; +/// HARNESS_START_WITH_MAXIMUM_SIZE_INDEX(0x0001U, buffer, 1024); +/// ``` +#define HARNESS_START_WITH_MAXIMUM_SIZE_INDEX(start_index, buffer, max_size) \ + do { \ + unsigned int value = (N_START_BUFFER_PTR_SIZE_VAL << 0x10U) | MAGIC; \ + __cpuid_extended3(value, start_index, buffer, max_size); \ + } while (0); + +/// Pseudo-hypercall number to signal the fuzzer to use the first argument to +/// the magic instruction as the pointer to the testcase buffer, the second +/// argument as a pointer to the size of the testcase buffer, and the third +/// argument as the maximum size of the testcase buffer. +#define N_START_BUFFER_PTR_SIZE_PTR_VAL (0x0003U) + +/// HARNESS_START_WITH_MAXIMUM_SIZE_AND_PTR +/// +/// Signal the fuzzer to start the fuzzing loop at the point this macro is +/// called. The default "index" of 0 will be used. If you need multiple start +/// harnesses compiled into the same binary, you can use the +/// `HARNESS_START_WITH_MAXIMUM_SIZE_AND_PTR_INDEX` macro to specify different +/// indices, then enable them at runtime by configuring the fuzzer. +/// +/// When this macro is called: +/// +/// - A snapshot will be taken and saved +/// - The buffer pointed to by `buffer` will be saved and used as the testcase +/// buffer. Each +/// fuzzing iteration, a new test case will be written to this buffer. +/// - The address `size_ptr` will be saved. Each fuzzing iteration, the actual +/// size of the current testcase will be written to `*size_ptr`. +/// - The `max_size` value will be saved as the maximum testcase size. Fuzzing +/// test cases will be truncated to this size before being written to the +/// buffer. +/// +/// # Arguments +/// +/// - `buffer`: The pointer to the testcase buffer +/// - `size_ptr`: The pointer to the size of the testcase buffer +/// - `max_size`: The maximum size of the testcase buffer +/// +/// # Example +/// +/// ``` +/// unsigned char buffer[1024]; +/// size_t size; +/// HARNESS_START_WITH_MAXIMUM_SIZE_AND_PTR(buffer, &size, 1024); +/// ``` +#define HARNESS_START_WITH_MAXIMUM_SIZE_AND_PTR(buffer, size_ptr, max_size) \ + do { \ + unsigned int value = (N_START_BUFFER_PTR_SIZE_PTR_VAL << 0x10U) | MAGIC; \ + __cpuid_extended4(value, DEFAULT_INDEX, buffer, size_ptr, max_size); \ + } while (0); + +/// HARNESS_START_WITH_MAXIMUM_SIZE_AND_PTR_INDEX +/// +/// Signal the fuzzer to start the fuzzing loop at the point this macro is +/// called. The index specified by `start_index` will be used. If you need +/// multiple start harnesses compiled into the same binary, you can use this +/// macro to specify different indices, then enable them at runtime by +/// configuring the fuzzer. +/// +/// When this macro is called: +/// +/// - A snapshot will be taken and saved +/// - The buffer pointed to by `buffer` will be saved and used as the testcase +/// buffer. Each +/// fuzzing iteration, a new test case will be written to this buffer. +/// - The address `size_ptr` will be saved. Each fuzzing iteration, the actual +/// size of the current testcase will be written to `*size_ptr`. +/// - The `max_size` value will be saved as the maximum testcase size. Fuzzing +/// test cases will be truncated to this size before being written to the +/// buffer. +/// +/// # Arguments +/// +/// - `start_index`: The index to use for this start harness +/// - `buffer`: The pointer to the testcase buffer +/// - `size_ptr`: The pointer to the size of the testcase buffer +/// - `max_size`: The maximum size of the testcase buffer +/// +/// # Example +/// +/// ``` +/// unsigned char buffer[1024]; +/// size_t size; +/// HARNESS_START_WITH_MAXIMUM_SIZE_AND_PTR_INDEX(0x0001U, buffer, &size, 1024); +/// ``` +#define HARNESS_START_WITH_MAXIMUM_SIZE_AND_PTR_INDEX(start_index, buffer, \ + size_ptr, max_size) \ + do { \ + unsigned int value = (N_START_BUFFER_PTR_SIZE_PTR_VAL << 0x10U) | MAGIC; \ + __cpuid_extended4(value, start_index, buffer, size_ptr, max_size); \ + } while (0); + +/// Pseudo-hypercall number to signal the fuzzer to stop the current fuzzing +/// iteration and reset to the beginning of the fuzzing loop with a "normal" +/// stop status, indicating no solution has occurred. +#define N_STOP_NORMAL (0x0004U) + +/// HARNESS_STOP +/// +/// Signal the fuzzer to stop and reset to the beginning of the fuzzing loop +/// with a "normal" stop status, indicating no solution has occurred. The +/// default index of 0 will be used. If you need to differentiate between +/// multiple stop harnesses compiled into the same binary, you can use the +/// `HARNESS_STOP_INDEX` macro to specify different indices, then enable them at +/// runtime by configuring the fuzzer. +/// +/// # Example +/// +/// ``` +/// HARNESS_STOP(); +/// ``` +#define HARNESS_STOP() \ + do { \ + unsigned int value = (N_STOP_NORMAL << 0x10U) | MAGIC; \ + __cpuid_extended1(value, DEFAULT_INDEX); \ + } while (0); + +/// HARNESS_STOP_INDEX +/// +/// Signal the fuzzer to stop and reset to the beginning of the fuzzing loop +/// with a "normal" stop status, indicating no solution has occurred. The index +/// specified by `stop_index` will be used. If you need to differentiate between +/// multiple stop harnesses compiled into the same binary, you can use this +/// macro to specify different indices, then enable them at runtime by +/// configuring the fuzzer. +/// +/// # Arguments +/// +/// - `stop_index`: The index to use for this stop harness +/// +/// # Example +/// +/// ``` +/// HARNESS_STOP_INDEX(0x0001U); +/// ``` +#define HARNESS_STOP_INDEX(stop_index) \ + do { \ + unsigned int value = (N_STOP_NORMAL << 0x10U) | MAGIC; \ + __cpuid_extended1(value, stop_index); \ + } while (0); + +/// Pseudo-hypercall number to signal the fuzzer that a custom assertion has +/// occurred, and the fuzzer should stop the current fuzzing iteration and reset +/// to the beginning of the fuzzing loop with a "solution" stop status. +#define N_STOP_ASSERT (0x0005U) + +/// HARNESS_ASSERT +/// +/// Signal the fuzzer that a custom assertion has occurred, and the fuzzer +/// should stop the current fuzzing iteration and reset to the beginning of the +/// fuzzing loop with a "solution" stop status. The default index of 0 will be +/// used. If you need to differentiate between multiple assertion harnesses +/// compiled into the same binary, you can use the `HARNESS_ASSERT_INDEX` macro +/// to specify different indices, then enable them at runtime by configuring the +/// fuzzer. +/// +/// # Example +/// +/// ``` +/// HARNESS_ASSERT(); +/// ``` +#define HARNESS_ASSERT() \ + do { \ + unsigned int value = (N_STOP_ASSERT << 0x10U) | MAGIC; \ + __cpuid_extended1(value, DEFAULT_INDEX); \ + } while (0); + +/// HARNESS_ASSERT_INDEX +/// +/// Signal the fuzzer that a custom assertion has occurred, and the fuzzer +/// should stop the current fuzzing iteration and reset to the beginning of the +/// fuzzing loop with a "solution" stop status. The index specified by +/// `assert_index` will be used. If you need to differentiate between multiple +/// assertion harnesses compiled into the same binary, you can use this macro to +/// specify different indices, then enable them at runtime by configuring the +/// fuzzer. +/// +/// # Arguments +/// +/// - `assert_index`: The index to use for this assertion harness +/// +/// # Example +/// +/// ``` +/// HARNESS_ASSERT_INDEX(0x0001U); +/// ``` +#define HARNESS_ASSERT_INDEX(assert_index) \ + do { \ + unsigned int value = (N_STOP_ASSERT << 0x10U) | MAGIC; \ + __cpuid_extended1(value, assert_index); \ + } while (0); struct tsffs_fme { struct cpu_user_regs regs; @@ -138,5 +484,4 @@ static size_t tsffs_size; static uint8_t tsffs_vmread_counter; static struct tsffs_fme tsffs_fme; - #endif // TSFFS_H -- 2.39.5