--- /dev/null
+From eb65003ff273a7b0488f534ebe184d3bf9f076c0 Mon Sep 17 00:00:00 2001
+From: Tamas K Lengyel <tamas.lengyel@intel.com>
+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 <xen/iocap.h>
+ #include <xen/paging.h>
+
++#include <xen/tsffs.h>
++#include <xen/kfx.h>
++
+ #include <asm/gdbsx.h>
+ #include <asm/irq.h>
+ #include <asm/hvm/emulate.h>
+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 <xen/ioreq.h>
+ #include <xen/nospec.h>
+
++#include <xen/tsffs.h>
++
+ #include <asm/hvm/emulate.h>
+ #include <asm/hvm/support.h>
+ #include <asm/hvm/viridian.h>
+@@ -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 <xen/spinlock.h>
+ #include <xen/percpu.h>
+
++#include <xen/tsffs.h>
++#include <xen/kfx.h>
++
+ #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 <xen/pv_console.h>
+ #include <asm/setup.h>
+
++#include <xen/tsffs.h>
++#include <xen/kfx.h>
++
+ #ifdef CONFIG_X86
+ #include <xen/consoled.h>
+ #include <asm/guest.h>
+@@ -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 <asm/current.h>
+ #include <xen/vpci.h>
+ #include <xen/wait.h>
++#include <xen/tsffs.h>
+ #include <public/xen.h>
+ #include <public/domctl.h>
+ #include <public/sysctl.h>
+@@ -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
+
#include <xen/domain_page.h>
#include <xen/hypercall.h>
#include <xen/perfc.h>
+#include <xen/tsffs.h>
#include <asm/current.h>
#include <asm/io.h>
#include <asm/iocap.h>
unsigned long len;
__vmread(VM_EXIT_INSTRUCTION_LEN, &len); /* Safe: callers audited */
- BUG_ON((len < 1) || (len > MAX_INST_LEN));
+ //BUG_ON((len < 1) || (len > MAX_INST_LEN));
+ if((len < 1) || (len > MAX_INST_LEN))
+ HARNESS_STOP();
return len;
}
unsigned long vector;
__vmread(VM_EXIT_INTR_INFO, &vector);
- BUG_ON(!(vector & INTR_INFO_VALID_MASK));
+ //BUG_ON(!(vector & INTR_INFO_VALID_MASK));
+ if(!(vector & INTR_INFO_VALID_MASK))
+ HARNESS_STOP();
vector &= INTR_INFO_VECTOR_MASK;
TRACE(TRC_HVM_INTR, vector);
__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);
+
+ regs->r8 = tsffs_fme.regs.r8;
+ regs->r9 = tsffs_fme.regs.r9;
+ regs->r10 = tsffs_fme.regs.r10;
+ regs->r11 = tsffs_fme.regs.r11;
+ regs->r12 = tsffs_fme.regs.r12;
+ regs->r13 = tsffs_fme.regs.r13;
+ regs->r14 = tsffs_fme.regs.r14;
+ regs->r15 = tsffs_fme.regs.r15;
+ regs->rax = tsffs_fme.regs.rax;
+ regs->rbx = tsffs_fme.regs.rbx;
+ regs->rcx = tsffs_fme.regs.rcx;
+ regs->rdx = tsffs_fme.regs.rdx;
+ regs->rsi = tsffs_fme.regs.rsi;
+ regs->rdi = tsffs_fme.regs.rdi;
+ regs->rip = tsffs_fme.regs.rip;
+ regs->rsp = tsffs_fme.regs.rsp;
+ regs->rbp = tsffs_fme.regs.rbp;
+ regs->rflags = tsffs_fme.regs.rflags;
+ regs->cs = tsffs_fme.regs.cs;
+ regs->ss = tsffs_fme.regs.ss;
+ regs->es = tsffs_fme.regs.es;
+ regs->ds = tsffs_fme.regs.ds;
+ regs->fs = tsffs_fme.regs.fs;
+ regs->gs = tsffs_fme.regs.gs;
+
if ( hvm_long_mode_active(v) )
__vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes);
break;
case EXIT_REASON_EXCEPTION_NMI:
__vmread(VM_EXIT_INTR_INFO, &intr_info);
- BUG_ON(!(intr_info & INTR_INFO_VALID_MASK));
+ //BUG_ON(!(intr_info & INTR_INFO_VALID_MASK));
+ if(!(intr_info & INTR_INFO_VALID_MASK))
+ HARNESS_STOP();
+
vector = intr_info & INTR_INFO_VECTOR_MASK;
if ( vector == X86_EXC_MC )
do_machine_check(regs);
}
if ( unlikely(exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) )
+ {
+ HARNESS_STOP();
return vmx_failed_vmentry(exit_reason, regs);
+ }
if ( v->arch.hvm.vmx.vmx_realmode )
{
perfc_incr(realmode_exits);
v->arch.hvm.vmx.vmx_emulate = 1;
TRACE(TRC_HVM_REALMODE_EMULATE);
+ HARNESS_STOP();
return;
}
case EXIT_REASON_EXTERNAL_INTERRUPT:
out:
if ( nestedhvm_vcpu_in_guestmode(v) )
nvmx_idtv_handling();
+ HARNESS_STOP();
}
static void lbr_tsx_fixup(void)