RISCVuzz: Discovering Architectural CPU
Vulnerabilities via Differential Hardware Fuzzing
Fabian Thomas∗ , Lorenz Hetterich∗ , Ruiyi Zhang∗ , Daniel Weber∗ , Lukas Gerlach∗ , Michael Schwarz∗∗ CISPA Helmholtz Center for Information Security{fabian.thomas, lorenz.hetterich, ruiyi.zhang, daniel.weber, lukas.gerlach, michael.schwarz}@cispa.de
Abstract—The open and extensible RISC-V instruction set
architecture marks a significant advancement in the CPU industry by enabling new vendors to enter the CPU market.
RISC-V is quickly gaining popularity, as demonstrated by its
support in the Linux kernel and its presence in consumer devices
and even cloud platforms. However, the flexibility of RISC-V
has resulted in a diverse range of hardware implementations,which differ in features and security measures. Additionally, no
automated approach exists currently to assess the security of these
implementations.
In this paper, we introduce a novel framework, RISCVuzz,
that leverages this diversity of RISC-V implementations toautomatically detect vulnerabilities in hardware CPUs without the need for source code or emulators. RISCVuzz uses
a differential CPU fuzzing approach to compare architectural
behaviors across different vendors and CPU models. We evaluate
RISCVuzz using all 5 currently available consumer-grade RISCV CPUs and identify 3 severe security vulnerabilities along withnumerous bugs. Notably, RISCVuzz identifies GhostWrite, an
unprivileged instruction sequence to write attacker-controlledbytes to attacker-chosen physical memory locations, including
attached devices. In 3 end-to-end attacks, we demonstrate how
GhostWrite can be transformed to read physical memory andlead to arbitrary machine-mode code execution, even in cloudenvironments. Additionally, RISCVuzz exposes 2 unprivileged“halt-and-catch-fire” instruction sequences that result in an
irrecoverable CPU halt.

I.

I NTRODUCTION

RISC-V is still a young instruction set architecture (ISA).
Nevertheless, there is considerable support for this ISA: The
Linux kernel supports RISC-V CPUs in the upstream code,and major compilers, such as GCC and Clang, support RISCV [39]. Furthermore, mainstream Linux distributions support
the RISC-V architecture, e.g., Ubuntu and Debian [41]. Besides software support, there is a steadily rising number of
RISC-V CPUs. While the first CPUs were mainly softcoresdesigned for emulators and FPGAs [1], [8], there are already asmall number of hardware cores available on the market [47],[54], [55]. These cores are used in single-board computers(SBCs) similar to the Raspberry Pi, as well as laptops [50],[63], mobile phones [49], servers [42], [46], and gaming
consoles [50].

The available RISC-V CPUs implement the base ISA andtypically an additional selection of finalized ISA extensions,such as compressed instructions or instructions for handling
floating-point numbers [16]–[18], [61]. Ongoing work also
focuses on thoroughly testing the implementation of the finalized ISA extensions to ensure that CPUs implement themcorrectly [20]. However, RISC-V also supports vendor-specificcustom ISA extensions that are already used, e.g., to implement cache-maintenance instructions in the T-Head XuanTie
C906 [22]. Worse, for most available high-end cores, no sourcecode is available. Thus, previous approaches that focus onfinding vulnerabilities in RISC-V cores on an RTL level [23],[26], [51] cannot be applied by researchers or other third
parties. Consequently, while crucial, it remains challenging toanalyze the security of high-end RISC-V cores due to missing
documentation and source code.
In this paper, we ask the following research question:
Can we leverage the inhomogeneity of RISC-V implementations to automatically find architectural CPU vulnerabilities
without requiring the source code of the CPU?
To answer this question, we build RISCVuzz, a differential CPU fuzzing framework for analyzing RISC-V CPUs.
RISCVuzz relies on the assumption that the architectural resultof every instruction has to be the same across different CPUs if
the instruction is supported. Additionally, ISA extensions canbe detected using the same approach, independent of whether
they are standardized or vendor-specific. An instruction froman extension manifests itself by showing different architectural
behavior across different CPUs. RISCVuzz executes instruction sequences with different parameters on different RISCV CPUs, including emulators. These instruction sequences
can be as simple as single instructions to complex instruction
chains consisting of multiple thousands instructions as shownin prior work [51]. Any deviation from the majority voteconcerning the output or side effect, i.e., system crash, isreported as a potentially misbehaving instruction sequence.
These instruction sequences require further manual inspection.
We evaluate RISCVuzz on 5 RISC-V hardware CPUs: THead XuanTie C906/C908/C910, and SiFive U54/U74. These
are all currently consumer-available hardware RISC-V CPUs
running a 64-bit Linux operating system, and are used invarious devices. For the evaluation, we use 10 different devices
featuring these CPUs. Additionally, we evaluate RISCVuzz on
4 emulators. In total, RISCVuzz discovers 3 architectural CPU
vulnerabilities and numerous bugs. On the T-Head XuanTie
C910 CPU, RISCVuzz discovers a successfully-executing instruction that leads to a segmentation fault on other CPUs.

with previous work on software fuzzing [33]. We emphasizethat our approach is orthogonal to RTL fuzzing, covering
scenarios RTL fuzzing cannot. However, even if the sourcecode is available, RISCVuzz might find bugs introduced by
the synthesis that are invisible in the RTL. Hence, we argue
that post-silicon fuzzing is a valuable extension of existingpre-silicon fuzzers [23], [26], [43], [51]. Another insight isthat the simplicity of RISC-V does not prevent bugs, butprevents mitigating them as done in x86 CPUs using microcode
updates [5], [34], [35], [38], [66].

Further manual analysis reveals a CPU vulnerability thatfully breaks integrity by providing a write-anything-anywhere
primitive for physical memory to unprivileged users. We dub
this vulnerability GhostWrite for easy reference, as it fully
circumvents virtual memory and caches, making it also invisible in performance counters. GhostWrite is in the noncompliant implementation of the high-order strided vectorstore instructions (vse128.v to vse1024.v). The other2 vulnerabilities belong to the class of “halt-and-catch-fire”
CPU vulnerabilities [10] that can be used for unprivileged
denial-of-service attacks on the CPU, one on each of THead XuanTie C906 and C908. One of these vulnerabilities
is in the vendor-specific XTheadMemIdx extension, which
provides additional memory operations such as incrementaddress-before-load (th.lbib). The other is a range ofbroken vector instructions that halt the CPU core. RISCVuzz
discovers these vulnerabilities fully automated by observing
hangs of these CPUs while the instruction sequence succeeds
on other CPUs. Additionally, we discover numerous architectural bugs in CPUs and emulators, most of them within seconds
of fuzzing. These include address-handling bugs, decoder bugs,
ISA incompatibilities, and fault-reporting issues, as well as
segmentation faults in the two latest major versions of QEMU.

Contributions. We summarize our contributions as follows.
• We present RISCVuzz, a differential CPU-fuzzing framework for finding CPU vulnerabilities on hardware RISC-V
CPUs that does not require access to the CPU source oran emulator, enabling vulnerability discovery on high-end
cores.
• We automatically test 5 different off-the-shelf RISC-V
CPUs and 4 emulators and discover 3 severe CPU vulnerabilities on real-world-deployed CPUs: an unprivileged
arbitrary physical write primitive we dub GhostWrite and2 unprivileged “halt-and-catch-fire instructions”.
• In 4 end-to-end attacks, we demonstrate the impact of thevulnerabilities by reading and writing arbitrary memory
and executing code with kernel- and machine-mode privileges, fully breaking the confidentiality and integrity ofthese systems, including cloud setups.
• We discover numerous additional architectural bugs in thetested CPUs as well as in emulators within seconds offuzzing.

We demonstrate the security impact of our findings in
4 case studies. On the T-Head XuanTie C910, we build an
end-to-end attack with GhostWrite that allows unprivileged
users to read and write arbitrary memory, including machinemode code and devices mapped via MMIO. Additionally, webuild two end-to-end attacks escalating privileges to root andmachine mode by using GhostWrite to inject and executecode in supervisor- and machine mode. As a third end-to-end
attack, we show how GhostWrite can be used on cryptographic
keys to mount an ineffective fault attack [9], [11], [65], fully
recovering a 2048-bit RSA key within 30 min. We demonstratethat this vulnerability can also be exploited by unprivileged
users in the cloud by successfully testing it on the Scaleway
TH1520 instances. For the instructions that halt the CPU,
we demonstrate that they can be used by any unprivileged
application and also work from inside Docker containers.

Responsible Disclosure. We reported all the security-criticalvulnerabilities on the C906, C908, and C910 to T-Head.
They acknowledged and reproduced GhostWrite and the C906
CPU-halting instruction sequence. We have no answer yet for
the C908 CPU-halting instructions. Further, we also reported
GhostWrite to Scaleway since they offer C910-based baremetal machines in the cloud. Scaleway reproduced our findings
and is currently in the process of giving out instructions tocustomers for manually rolling out kernel patches that disable
the vector extension, mitigating GhostWrite. Additionally, we
reported a segmentation fault that is present in the latest
version of QEMU.

The only mitigation we identify for the bugs in the vector extension, e.g., GhostWrite, is disabling the extension,
which breaks applications using it. In a benchmark using
rvv-bench, we measure an overhead of up to 77 % when
this mitigation is active. Thus, in spite of preventing exploitation, it is not a practical solution for entities relying on thevector extension. For the C906 CPU-halting bug, we find no
mitigation since the responsible vendor extension cannot bedisabled.

Availability. We will open source the RISCVuzz frameworkand our reproducers with acceptance of the paper. We provide apreliminary version of these artifacts at the following address:
https://anonymous.4open.science/r/riscvuzz-artifacts-116DII.

Our results provide interesting insights into the current stateof hardware RISC-V CPUs. Vendor extensions and “rushed”
implementations of non-finalized extensions do not only leadto bugs but also to exploitable security vulnerabilities thatare difficult to mitigate. Our results indicate that the baseinstruction set is tested significantly better than complex
extensions, such as vector extensions. An additional insightis that even for open-source cores, such as the C910, thehardware implementation differs from the released source.
RISCVuzz discovers most bugs and vulnerabilities within seconds, showing the efficacy of our approach. This is even true
for rather simple instruction-sequence generation, which aligns

BACKGROUNDThis section covers the relevant background required forthe remainder of the paper.
A. RISC-V
RISC-V is an open instruction set architecture (ISA) developed by the RISC-V foundation. The RISC-V ISA consistsof a core instruction set that must be implemented by all
RISC-V CPUs and extensions that can be implemented asneeded [59], [60]. An example of such an extension is thevector extension [17], which is implemented in the XuanTie
C908. In addition, multiple vendor-specific extensions, some2

to recover confidential information. In contrast to transientexecution attacks, architectural bugs are mismatches between
the CPU specification and implementation. For example, thePentium F00F bug allows an unprivileged attacker to lock up
an affected system by executing a specific instruction eventhough the instruction encoding is invalid and should raise an
exception according to the specification [10]. More recently,
these architectural bugs gained traction, with multiple CPUbugs causing architectural data leakage [6], [35], [36], [66].

only vaguely documented, are added to RISC-V cores to equipthem with additional functionality [16], [22], [56]. ISA variantsfor 32 bit, 64 bit, and plans for 128 bit addressing [59] areavailable, making RISC-V suitable for a wide range of devices.
Nowadays, RISC-V CPUs are not only available as soft coresfor FPGAs but are already used in embedded devices [40],
SBCs [29], laptops [50], [63], and cloud computing [42].
RISC-V devices are supported by upstream Linux [15] andcan run a variety of distributions, e.g., Ubuntu or Debian.
a) Privilege Levels: RISC-V has three privilege levels: User (U) for unprivileged applications, Supervisor (S)for operating systems, and Machine (M) to manage trusted
execution environments [60]. While only M is required to be
implemented, most non-embedded RISC-V CPUs implement
all three privilege levels. Access to Control and Status Registers (CSRs) and privileged instructions is limited dependingon the current privilege level.

III.

M ETHODOLOGYThis section describes the methodology of our work. We
introduce the main idea in Section III-A and outline challenges
in Section III-B. In Section III-C, we introduce the fuzzing
targets used in the remainder of the paper. We provide implementation details in Section IV.
A. Ideab) Paging: RISC-V supports virtual memory throughpaging. With virtual memory, the single physical address spacefor DRAM and memory-mapped I/O is isolated through virtual
address spaces. The mapping between virtual and physicaladdresses is defined in per-process page tables. A page table
is a sparse tree-like data structure mapping virtual memory
blocks of fixed size called memory pages to physical memory
pages. The size of such memory pages is typically 4 kB [60]. In
addition to the physical address, page tables can store metadata
for each memory page, for instance, whether a memory pageis present as opposed to swapped to disk, whether it can beaccessed from userspace, or whether it is writable.

We rely on the basic assumption that the architectural
result of every instruction has to be the same across different
CPUs. This assumption ensures that different CPUs have toadhere to the ISA specification. However, this assumption is
only valid for instructions supported on all the tested CPUs.
Thus, we consider any architectural effect that differs between
CPUs an instruction anomaly that has to be investigatedfurther, excluding instructions only supported on one CPU.
These instruction anomalies are likely due to a bug, or worse,a security vulnerability in the CPU.
The main advantage of this approach compared to previous
CPU fuzzers searching for architectural bugs [23], [26], [51] isthat we require neither source code nor golden models. Thus,
this is the first approach that can automatically find vulnerabilities on closed-source CPUs, such as the T-Head C908.
Moreover, running code on hardware CPUs is significantly
faster than emulating them.

B. Fuzzing
Fuzzing is a soft- and hardware testing technique thatprovides randomly generated inputs to hardware or software
targets and checks that they behave in an expected way. Whilefuzzing cannot prove the absence of bugs, it has been shown
to be effective in finding bugs in soft- and hardware [23], [26],[43], [51]. A special case is differential fuzzing [32], wheremultiple targets implementing the same specification are tested
against each other. Each difference resulting from the executionof identical inputs by different targets is considered a violationof the specification by one of the targets. Differential fuzzing
has the benefit that no golden reference model, which correctly
implements the specification, is required, as bugs manifest
through differing behavior.

In addition to instruction differences, ISA extensions can bedetected using our approach. This is true for both documented
and undocumented extensions if two CPUs implement differing extensions. An instruction from an extension manifests itself by showing different architectural behavior across different
CPUs, e.g., by throwing an illegal-instruction exception on asubset of CPUs.
Finally, this approach can be extended from single instructions to instruction sequences. Although many previous
CPU bugs do not require the interaction between multiple
instructions [6], [35], [66], some do [36], [51]. Thus, we
also compare the architectural effects of instruction sequences.
As our differential approach is generic, this addition does
not result in conceptual changes but only in additional engineering effort. However, unlike single instructions, we cannot
exhaustively test all instruction sequences. Thus we have toselect instructions pseudo-randomly, i.e., we rely on fuzzing
techniques for generating instruction sequences.

C. CPU Vulnerabilities
While software-based side-channel attacks have been
known for decades [28], recent years have proven that morecritical CPU vulnerabilities exist [27], [31], [35], [36]. A
prominent class of attacks are transient-execution attacks [7],[27], [31], which abuse performance optimizations of modern CPUs, such as out-of-order and speculative execution.
While transient-execution attacks allow for leaking data fromvarious security boundaries [27], [58], they are restricted toread primitives. Transient-execution attacks do not violate
the specification of a CPU but allow an attacker to execute
security-boundary-crossing instructions that are never committed to the architectural state of a CPU. However, those
instructions leave microarchitectural traces that attackers use

B. Challenges
While the idea of differential CPU testing (or fuzzing) is
quite intuitive, we identify multiple challenges in both design
and implementation. Conceptually, there are the following 3
challenges:3a) C1: Sequence Generation: Executing every possible
instruction encoding in the 32-bit encoding space alreadyresults in a large search space. This search space grows exponentially with the length of the instruction sequence. Hence,
randomly executing bitstreams is inefficient for exploring “interesting” effects. Additionally, if there is a difference between
two CPUs in one instruction, such an instruction is reported
multiple times if it encodes an immediate. As the differenceis likely independent of the immediate, testing all possible
immediates wastes resources and inflates the result set, which
has to be checked manually. Hence, the challenge is findinga trade-off between coverage of the encoding space and thenumber of tested instructions. In Section IV-C1, we describe
how our proof-of-concept implementation RISCVuzz solves
that challenge by using a bottom-up approach to gradually
increase the search space using instruction types inferred from
instruction encodings.

TABLE I: Overview of tested RISC-V boards and emulators.
We test 5 CPUs and 4 emulators. The CPUs come from 2
different vendors.
Board

CPU

CPU Vendor

A
B

U54
U74

SiFive-C, D, EF
G, H, I

C906
C908
C910

T-Head

v0p7, zfh, XTheadMemIdxv, zfh, XTheadMemIdx
v0p7, zfh, XTheadMemIdx

Emulator

VersionRelevant Extensions

QEMU 6.2.0
QEMU 7.2.0
QEMU 8.2.2
QEMU 9.0.0

v
v
v

A
B
C
D

Relevant Extensions

C908 supports the ratified RISC-V vector extension (v), while
C906 and C910 use a pre-ratified draft version 0.7.1 (v0p7)
supported by vendor-provided kernels and toolchains. Further,
we test on different QEMU versions from version 6 (default
on Ubuntu 22.04) to 9 (newest) (cf. Table I).

b) C2: Non-deterministic Effects: Comparing the architectural effects of instructions requires that these effects only
depend on factors we can control, e.g., memory and register
content. Unfortunately, this is not the case for all instructions.
Some instructions provide internal values of the CPU, suchas performance counters. These values often depend on the
CPU state and previous instructions executed on the core andcan thus not be controlled. Finally, memory reads from certain
addresses, such as Linux vDSO [21] return values that are outof the control of the testing framework. All these cases have to
be considered to avoid false positives, i.e., reporting different
behavior across CPUs even though the instructions have thesame behavior. In Section IV-B1, we describe how we preventthe reporting of non-deterministic effects by minimizing thesources of non-determinism and ignoring the results of theremaining non-deterministic instructions.

IV.

RISCV UZZ F RAMEWORKIn this section, we describe RISCVuzz, our proof-ofconcept implementation of the methodology described in Section III. Specifically, Section IV-A describes the design of
RISCVuzz. Section IV-B and Section IV-C discuss relevant
design and implementation details of the client and server
components of RISCVuzz, respectively.
A. Design Overview
RISCVuzz uses a centralized design: A server orchestrating
the testing, and the clients, i.e., RISC-V CPUs, are connectedto the server. We reduce the task of the clients to a minimum
due to resource constraints on the clients. A client receives test
cases, i.e., instruction sequences plus input, over the network,runs them, and reports back the resulting state e.g., registervalues and changed memory contents. The server is responsible
for generating the test cases, distributing the cases to theclients, collecting the results, and analyzing the results.

c) C3: Test-framework Integrity: The test frameworkhas to record the architectural effects of instruction sequences.
Thus, from a high-level perspective, architectural states, suchas register and memory content, must be saved before and after
executing the sequence. While this is relatively easy for many
instructions, some instructions need special care to ensure theintegrity of the test framework. These instructions include
those that change the control flow, e.g., calls and (conditional)
jumps, those that change the CPU behavior, e.g., CSR writes,
and those that change the stack pointer or stack content.
Hence, the test framework implementation has to handle all
corner cases that would change the saved architectural statesor the internal state of the test framework. We describe theimplementation details of this approach in Section IV-B2.

The server-based approach has different advantages over adecentralized approach. First, the clients typically have limited
storage, making storing the architectural effects of all tested
instructions difficult. With a 32-bit search space for single
instructions, the resulting states require multiple gigabytes ofstorage. Second, the CPU processing power of the clientsis also constrained, leading to non-negligible overhead forgenerating the test cases in addition to executing them. As
we aim to test instructions as fast as possible, we delegate all
resource-intensive tasks to more powerful CPUs. Finally, witha central server-based solution, we can compare the results ofthe tests in parallel and do not have to wait for the completionof the test runs on all machines.

C. Fuzzing Targets
While the number of silicon RISC-V cores is still limited,
we test all widespread commercially available 64-bit RISC-V
cores that support booting a Linux distribution. At the time ofwriting, there are 2 manufacturers of silicon RISC-V CPUs—
SiFive and T-Head Semiconductors. We test on 2 SiFive and3 T-Head CPU models as listed in Table I. All tested CPUs
are mounted on single-board computers. We also use the C910
in the Scaleway cloud [42]. The targets run various operating
systems such as Ubuntu or Debian (cf. Table III in Section A).

B. Client
The client is a runner of server-provided test cases. It is
implemented in a mixture of C and RISC-V assembly. To
execute test cases, the client sets the registers as specified,

All tested cores support at least the base ISA, the standard
extensions, and compressed instructions, i.e., RV64GC. The
4

C906: SIGSEGV
C910: NOSIG
C908, U54, U74: SIGILL

C906
user input
ext=rv64gcv0p7
seq len=3

vsetvli x0, x0, ...
vse128.v t0, 0(t0)li t0, 2

vsetvli x0, x0, ...
vse128.v t0, 0(t0)li t0, 2

distributecollect

t0: 0x4000
generate instruction
sequence

generate register
inputs

C910

SIGSEGV
t0: 0x4000
NOSIG
t0: 2

instr seq:
...
regs:
t0: 0x4000
if diff,
generate repro

run on othermachinesinit
C reproducer:
load regs from repro
run sequence
print register diffs

Fig. 1: Overview of RISCVuzz. The user selects the enabled extensions and sequence length. The server generates an instruction
sequence and register inputs for the clients and compares the results. Differences are logged as a reproducer file.

runs the provided instruction sequence, and reports the results
to the server. In case of instructions that access arbitrary
unmapped memory, execution is interrupted by a segmentation
fault. Since RISCVuzz should compare memory differences
too, RISCVuzz incorporates a routine for mapping these unavailable pages. When the client detects a segmentation fault,
it tries to map two pages, the page causing the fault and thesubsequent page to handle corner cases where accesses mightspan two pages. This lazy mapping of pages has the advantagethat only a small amount of memory has to be scanned formodifications caused by the instruction sequence. The mapped
pages are filled once with all ‘0’s and once with all ‘1’s. This
is to detect writes of only ‘0’s or only ‘1’s respectively too.
This procedure is repeated until a threshold is reached1 or until
no segmentation fault is triggered anymore by the instruction
sequence. After mapping the pages, the testcase is restarted.
The differences on all memory pages are recorded and includedin the results.

RISCVuzz has to ensure the integrity of its internally usedregisters, memory regions, and control flow. Figure 2 illustrates
the design of the integrity-providing sandbox we discuss in thefollowing.
a) Registers: For the integrity of registers, we employ
two routines that ensure the register state is saved and restoredcorrectly. When a target instruction triggers a signal, such as
an illegal instruction, the kernel saves the architectural state of
the CPU. We simply copy this state and return to the execution
loop with a longjmp, which restores the register state. Whenno signal is triggered, we use an instruction sequence similar
to the one used by the kernel when handling an interrupt. Thissequence saves/restores every register to/from memory before
and after executing the instruction sequence.
b) Memory: Memory state is the second dimension toprotect. While single instructions can only access memory
close to the current register contents defined by the inputs, instruction sequences, and non-RISC instructions can arbitrarily
shift these inputs and access any memory. Further, we want tobe able to provide various inputs, such as ‘-1’, via the registers.
Shifting the value ‘-1’, which results in the register value
0xffff..., results in addresses potentially pointing to theprogram stack. We leverage the large virtual address space to“hide” the internal data in a region that is difficult to overwrite
accidentally. The kernels we run on our CPUs all use the Sv39
paging mode [60], i.e., 512 GB of virtual space is available for“hiding”. Consequently, we move the data section to a “safe”
region of memory that we experimentally determined. Further,we switch to a new stack that we set to this region as well.
While this approach is heuristic, it works well in practice.

As discussed in Section III-B, RISCVuzz faces two challenges: non-deterministic instruction effects (C2) and the integrity of the client (C3). In the following, we discuss how wetackle these challenges in the design of RISCVuzz.
1) C2: Noise Removal: Since we assume every difference
in register values to be a bug, we must ensure this does not
happen randomly. The first step in this direction is using staticcompilation. Static compilation removes noise from differencesthat occur in shared libraries and ensures that we can run thesame binary on all machines. We use Nix [13] for the staticbuilding to ensure that our builds stay reproducible acrossdifferent machines employed for compilation. Reproducibility
is essential since any change in the binary layout of theclient implementation could introduce new noise or breakframework integrity (C3). Additionally, we unmap the vdso,
vdso_data, and vvar sections since loading from them
results in differing values between kernels. Another noise
source are instructions that naturally introduce noise, such as
the rdcycle instruction. To remove these noise sources automatically, we execute each instruction in the space of selected
extensions twice and exclude those that do not produce thesame result.

c) Control Flow: The third dimension is control flow.
No instruction sequence must jump out of RISCVuzz’s logic or
infinitely lock up the client. We embed placeholder instructions
into a padding of ebreak instructions to ensure that control
flow is restricted to our path. These placeholder instructions are
replaced in memory by the runner code. The ebreak padding
ensures that the generated signal data is accurate. Padding withnops would hide the target of relative jumps and branches
since the runner would fall through to the last instruction after
the nop-sled. We again rely on the size of the virtual address
space to “hide” the client logic. We move the sandbox to its
own memory range and use absolute jumps to get into and outof the runner sandbox. Two instructions in the sandbox load
the last two registers, which are needed for the absolute jump
and as the base for loading the registers.

2) C3: State Protection: As RISCVuzz executes arbitrarycode sequences, these code sequences can modify its internal
state. Thus, RISCVuzz has to protect its internal state toensure a correct reporting of instruction effects. Specifically,
1 For our tests, we use 10 as a threshold which we experimentally found toyield good results.

5

break chain

sandboxabs. jump
patch code
prime alarmsave registers
save perf countersload registers

TABLE II: Distribution of 4-byte RISC-V instruction spaceas documented by RISC-V Opcodes. All ratified (official)
parts of the ISA cover 84.03 % of the instruction space. The
vector extensions and T-Head extension cover only small partsof the instruction space. Overall, 85.51 % of instructions are
specified, the rest (14.49 %) are unknown or not specified.

load regs<nop>
seq len...
<nop>
break chain

on signal
abs. jump
save registers
save perf counters
restore registers
unprime alarm

unprime alarm
copy registers
store signal meta

return results

Fig. 2: The runner sandbox includes nop placeholders surrounded by ebreak instructions. The runner patches theplaceholder instructions, primes the alarm, saves registers,
loads the supplied fuzzing registers, and jumps into the sandbox. The executed instruction sequence either returns via therunner, or a signal, and returns the results.

RISC-V Opcodes

Vendor2

unratified
documented
ext. VC906 halting
instructions

1

Percentage

Ratified + unratified
Ratified
Vector extension (v)Vector extension (v0p7)
T-Head vendor extension

85.02 %
84.03 %
1.05 %
0.81 %
0.39 %Overall known

85.51 %

first fuzz only the undocumented space ( 3 ). This drasticallyshrinks the search space by 85.51 % (Table II). Note that we
do not have to separate ISA extensions exactly. The encodingbased filtering is only a rough but deterministic guidancetechnique to prevent the fuzzer from wasting resources on
instruction encodings that mainly consist of instructions withlarge immediate encodings. We still strive to cover the entire
4-byte instruction space of RISC-V but want to focus on more
promising parts first. In the following, we describe in moredetail how this bottom-up approach works.

Instruction Space3

ISA part

ext. Cext. Zfh

GhostWrite
C908 halting instructions

Fig. 3: Overview of the RISC-V instruction space. RISC-V
Opcodes ( 1 ) covers most parts of the RISC-V ISA specification. The specification reserves parts of the address space forcustom vendor extensions ( 2 ). Other parts are either reserved
for future use or unclaimed ( 3 ). The dots describe where our
discovered bugs are in the instruction space.

a) Instruction Classification: We use the official RISCV Opcodes repository [19] for building our filters since it encodes all standard RISC-V instructions in a machine-parsableformat. Further, it clusters the instructions into their respective extension. Moreover, it includes some of the unratified
extensions.

We handle infinite loops by priming an alarm before
jumping into the sandbox. This alarm interrupts the client
after a configurable timeout, breaking out of any loop. The
ebreak padding further minimizes the chance of infinite
loops compared to padding with nops.

b) Instruction Exclusion: Encoding-based filtering also
allows for excluding instructions or entire instruction classes,
such as CSR-based instructions. As these instructions canchange the behavior of instructions on the current core, theyrequire extra handling to avoid introducing false positives inthe differences. We leave the coverage of these CSR-based
instructions to future work.
c) Instruction Selection: The server randomly chooses
instructions from the instructions used for fuzzing and assembles them based on the documented encoding. We generally
initialize immediate parts of the instruction with values thatmight lead to corner cases, e.g., ‘-1’ or ‘0’. To ensure that
any instruction encoding can be achieved, though, we mix ina random immediate in 1 out of 8 cases. For the rest of the
fields, including register fields, we provide the required numberof random bits.

C. Server
The server is the pivot of our setup. Figure 1 illustrates thelogic of the server. It generates instruction sequences and input
registers and sends these to the clients (Section IV-C1). The
clients run the test cases and report the resulting architecturalstates to the server (Section IV-C2). The server compares thesestates and logs differences as simple reproducer files, which
can be used for further analysis in a simple C program or byrunning the reproducer on other machines (Section IV-C3).

Not defined or missing instructions in RISC-V Opcodes
are chosen by generating a random 4-byte value that cannot
be decoded to a valid instruction. For any non-documented
instruction, RISCVuzz does not have to fill any bitfields, asa full instruction encoding with all bits set is already chosen.
Thus, RISCVuzz covers the entire instruction space with thisapproach.

1) C1: Sequence Generation: Instead of generating random
4-byte sequences, we use a bottom-up approach based on the
instruction encoding to gradually increase the covered instruction space. Based on specific bits in the instruction encoding,
RISC-V allows to classify the type of instruction and whether
an instruction is a standard instruction ( 1 ) or a vendor-specificinstruction ( 2 ), leading to groups as illustrated in Figure 3.
This approach allows selectively including and excluding ISA
extensions in our tests. Consequently, this makes it easy to2) Input Distribution: The server distributes the generated
fuzzing inputs and collects the results (cf. Figure 1). Since
we want to achieve high throughput fuzzing on the clients (cf.
6Section V), we implement 3 optimizations for the transfer.
First, we only send back registers and memory contents thatchanged during the execution of the instruction sequence.
Second, we restrict ourselves to a list of values of register
contents. This list of values is shared between client and server.
The server then transmits one byte to select the respective valueon the client side. This reduces data consumption from 4 to
1 byte per register for general-purpose registers and saves 15
bytes per register for vector registers. Third, we send batches offuzzing inputs and ensure enough fuzzing inputs are bufferedin the client. These optimizations ensure that the clients arenever idle and the network is efficiently used.

U54
CPU

U74
C910
C908
0

10

20

30

40

50

60 1000s

Fig. 4: Relative performance of each tested CPU. The C908 is
by far the fastest CPU in our test. The C910 and U74 perform
similarly. C906 and U54 are the slowest CPUs.

3) Logging Differences: In the next step, the server compares the collected architectural states. If it finds a difference,
it logs a reproducer file for the fuzzing input. This reproducer
can then rerun the fuzzing input on selected machines or
automatically create a simple C-based program consisting of
the instruction sequence and the register inputs (cf. Figure 1).
This reproducer file can then be compiled and executed asa standalone binary on any RISC-V CPU for further manual
analysis.

FPU, or reset performance counters to a shared state. Runningthese binaries on a Linux host is not possible by design
and requires significant modifications to the design of ELF
generation, e.g., adapting the exception handling approach touserspace logic. Further, running these bare-metal ELF binaries
one by one on a CPU is an entirely new problem. For example,
on some boards this would require removing the microSD card,
copying the new ELF binary onto it, inserting it, and poweringon the board again for every testcase.

While RISCVuzz only adds the necessary code to thereproducer, i.e., the instruction sequence and architectural state
initialization, the reproducer is not necessarily minimal. However, in practice, the reproducer is typically small enough foran analysis. Still, if necessary, program reduction techniques,
such as those discussed by Solt et al. [51], can be used toreduce the reproducer further.
V.

C906

Takeaway Testing on hardware cores is orders of magnitude
faster than on emulated cores.
2) Multi-Core Scaling: Fuzzing throughput can be improved by deploying fuzzing clients to more than one CPU
core. Such parallelization relies on the fact that each fuzzing
corpus should not impact the others. Thus, they can bearbitrarily distributed to cores. Switching to 2 cores on the
C910 nearly doubles performance from 39 994 to 71 825 instr.
s ,while employing one more core again improves performancebut only by half of the increase we see when going from 1
to 2 cores (92 943 instr.
s ). Adding the last core only marginally
improves performance because the server tops at 97 207 instr.
s .
As the C906 is a single-core CPU, we can instead use multiple
CPUs, which comes close to a linear increase in throughput.
nearly resembling a linear increase in throughput.

E VALUATIONIn this section, we evaluate RISCVuzz. We evaluate thegeneral performance of testing instruction sequences (Section V-A), summarize the findings of RISCVuzz (Section V-B),
including the most severe finding, GhostWrite, and evaluate
how long it takes RISCVuzz to discover our findings (Section V-C).
A. Fuzzing Performance

Takeaway Multiple cores can be used to increase fuzzing
throughput. For single-core machines, multiple machines canbe joined to achieve the same effect.

This section focuses on different performance metrics of
RISCVuzz. All experiments use 1 core of an Intel Core i913900K as the server.

3) Sequence-Length Scaling: We evaluate the impact of thesequence length on the performance. If there is no exception,
we rely on the retired instructions counter to collect the numberof executed instructions. Otherwise, we infer the number fromthe program counter at which the signal is triggered. When thetrapped program counter is not in bounds of the sandbox, we
assume that only 1 instruction was executed. This can happen
when a jump or branch instruction is executed.

1) General Throughput: To assess the general throughput
of RISCVuzz, we benchmark a fuzzing run with only thebase ISA with 1 client instance on each of the target CPUs
(cf. Section III-C). We test 18 194 (C906) to 59 205 (C908)
instructions per second on average. Figure 4 provides theresults for all CPUs. Comparing the results to the fastest stateof-the-art RISC-V RTL fuzzer Cascade [51] shows that fuzzing
on hardware cores is orders of magnitude faster. Cascadeachieves 2181
256 = 9 instructions per second. We divide thereported throughput by 256 since the Cascade evaluation uses
a 512-core machine while we only use 2 cores (client andserver). However, Cascade already uses a sequence length of
10 000 to achieve this throughput, while we use a sequencelength of 1.

Figure 5 shows the result of increasing the sequence length
on the C906. The performance increases up to a sequencelength of 5 and then gradually decreases with further increasing
sequence length. The results are as expected since, at somepoint, increasing the sequence length only rarely leads to more
instructions executed per iteration, as some earlier instruction
might already raise an exception (cf. Section C). The added
network overhead of sending one more instruction absorbs
this slight increase and decreases performance overall. A
sequence length of 3 is a good tradeoff since adding more

Note that we cannot evaluate the bare-metal performance ofCascade. RTL fuzzers such as Cascade [51] or DifuzzRTL [23]generate bare-metal ELF binaries, i.e., binaries that use privileged instructions to setup the interrupt vector table, enable the7a hard reset. On the C906, C908, and C910, a load to a
non-canonical address is stuck until an interrupt arrives if thecanonical part of the address is a valid address. RISCVuzz
generates such addresses if any upper bits of a valid virtual
address are modified by an instruction, e.g., by an xor, before
the load happens.

30
1000
s

20
10
0
1

2

3

4

5

6

7

8

9 seq. len

Fig. 5: The fuzzing performance on the C906 increases up to
sequences of 5 instructions, then falls gradually with increasing
sequence length.

b) Decoder Bugs: RISCVuzz discovers decoding bugs
on different hardware CPUs and in emulators. We find CPUhalting instruction sequences on the C906 and C908 that
we suspect to be decoder issues (cf. Section VII). On theC906 and C910, RISCVuzz discovers fence and fence.i
instructions that raise an illegal-instruction exception, although
they are valid according to the ISA specification. The RISCV standard reserves these instructions for “finer-grain fencesin future extensions” and dictates that “implementations shall
ignore these fields” [59]. Conversely, RISCVuzz discovers
instructions that do not raise such an exception although
they are invalid. For example, the C906 and C910 executethe half-precision floating-point instructions fsqrt.h andfmv.x.h even when the rs2 field is ̸= 0 [18]. Finally, forthe latest versions QEMU 9.0.0 and QEMU 8.2.2 (Emulator
D and C), RISCVuzz discovers that cache-block management
instructions such as cbo.inval crash QEMU with a segmentation fault. For QEMU 7.2.0 (Emulator B), RISCVuzz
discovers that truncating vector conversion instructions such asvfncvt.rtz.x.f.w crash QEMU. However, as the crashis due to an assertion, we do not expect that this is further
exploitable.

instructions only slightly improves performance while causing
more congestion on the network, potentially hindering otherclients from receiving data.
Note that Cascade uses advanced techniques for generating
longer valid instruction sequences [51]. Although we suspectsuch techniques would improve the throughput of RISCVuzz,
we leave improving the sequence generation for future work.
B. Findings
In this section, we summarize the findings of RISCVuzz.
We categorize the findings into address-handling bugs, decoder
bugs, ISA incompatibilities, and fault-reporting issues. We
discuss the findings with the highest security impact, i.e.,
GhostWrite and the C906 and C908 CPU-halting vulnerabilities, in more detail in Section VI and Section VII, respectively.
Figure 3 visualizes where RISCVuzz finds the most severe
bugs. GhostWrite is in the vector extension. The C908 halting
instructions are illegally encoded vector instructions close to
but outside the vector extension. The C906 halting instructions
are on the edge of the documented vendor extension since they
use an edge case in the instruction encoding.

c) ISA Incompatibility: The C906 and C910 are notfully compatible with the ISA specifications. These CPUs do
not ignore writes to bits 8 to 10 of the fcsr register. Both theC910 and the C908 support a subset of the vector extension.
This manifests itself in some of the instructions doing nothing,others doing unexpected things (cf. Section VI), and somenot being implemented at all. Interestingly, the subset of
instructions also differs between the two CPUs.

Note that RISCVuzz automatically finds architectural differences that are in most cases bugs. The analysis whether
these differences are security vulnerabilities still requires amanual analysis. However, due to the small reproducers created
by RISCVuzz, the manual analysis is in many cases relatively
quick. GhostWrite produces differences when fuzzing the 0.7.1
vector extension between C906 and C910. While the illegallyencoded vector-store instructions generate a segmentation fault
on illegal memory addresses, the C910 generates no exception.
We provide an example of such a difference logged into
a reproducer file in Section D. During manual inspectionof the instruction behavior, by varying register values, weobserve kernel crashes when passing addresses in the physicalkernel range which motivates further analysis of these faulty
instructions (cf. Section VI). The C906 and C908 CPU-halting
instruction sequences directly crash the fuzzing client, therefore no further analysis of such reproducers is needed as such adenial of service can always be considered a security problem.
The other bugs we summarize below generate similar patterns,
i.e., either hangs or differences, which motivate further manual
inspection.

d) Fault-reporting Issues: On all tested CPUs,
RISCVuzz discovers bugs during fault reporting. Overall,there are various inconsistencies in the raised signal for
exceptions. SiFive CPUs tend to raise bus faults, whereas
T-Head CPUs raise segmentation faults. Additionally, thereported program counter of the fault and the faulting address
are not always correct. On the C910, the reported address for
faults is rounded up to the next multiple of 16 if the address
modulo 16 is larger than 8. The C908 reports segmentation
faults for valid non-aligned addresses, where the correct
behavior is to raise a bus error.
C. Time to Bug
In line with other papers on fuzzing [43], [51], we provide
the fuzzing time to find the bugs. We use all extensions, i.e.,
all ratified and unratified extensions, during fuzzing. This is
the worst case for finding the bugs, since the only restriction
we pose on the fuzzing space is to use only documented
instructions. We further test on a single core. Thus, thenumbers from Section V-A1 apply.

a) Address-handling: RISCVuzz finds different bugs
around virtual address handling. The vse128.v instruction
on the C910 does not translate the provided virtual address
to a physical address but instead interprets it directly as aphysical address, giving attackers a physical write primitive(cf. Section VI). Additionally, on the C910, reading fromphysically-backed virtual address ‘0’ locks the CPU, requiring

We find GhostWrite within the first second of fuzzing as no
special encoding in the broken instruction is needed to makethe bug visible. Thus, the fuzzer only needs to select one of the8

; t0 = physical address, a0 = byte to be written
vsetvli zero, zero, e8, m1
3 vmv.v.x v0, a0
4 ; encoded: 0x10028027
5 vse128.v v0, 0(t0)yet, but it is “expected to be used to encode expanded memory
sizes” [17]. The encoded effective element width contrasts what
we observe in practice, i.e., only one-byte stores. We further
test the 256-, 512- and 1024-bit encodings of the instruction
and find that they behave the same, i.e., write only one byte.

Listing 1: Code of GhostWrite. vsetvli and vmv.v.x set
up the vector engine’s internal state and the byte to be written.
The non-standardized vse128.v instruction (provided asmachine code 0x10028027) performs the physical write.

We further test the nf (number of fields) encoding of
the instruction, which controls how many fields are stored tomemory. Increasing nf shifts the used source vector registerfor the written byte by that exact amount. Thus, we only see
the value of the last vector register in the group of fields.
We suspect that the buggy instruction always writes to thesame physical address, thereby dropping intermediate writesof other field values that should normally be continuously
visible in memory. To further test this hypothesis, we measure
the cycles the instruction takes to execute while varying thenf field and find that the instruction takes linearly more time
to execute. This observation strengthens the hypothesis thatmultiple writes are scheduled, one for each field, but only thelast one is visible since every write goes to the same address.

1
2

8 broken instructions out of 1283 possible instructions whenenabling all extensions as outlined above.
We find the C906 halting instruction sequence bug within
the first 10 s. The slightly longer time to bug can be explainedby lower fuzzing throughput on the C906 (cf. Section V-A1)
and by slightly more involved conditions that the broken
instruction needs to satisfy, e.g., using the same registers in
the encoding of the instruction. On the C908, RISCVuzz finds
the undocumented CPU-halting instruction in under 15 min of
iterating over the undocumented space.

2) Memory Interaction: Based on the observed effects,
we hypothesize that the instruction entirely circumvents thecache, directly writing to memory. We back this hypothesis
using a series of experiments. We set up a base experimentin which we initialize a memory address V, backed by thephysical memory address P, with a known value x1 . Next, we
perform operations to ensure that the target memory address,
i.e., V, is in a specific state before overwriting P with value
x2 using GhostWrite. Afterward, we check whether a memory
read from V returns the original value x1 or whether it was
overwritten by the write gadget returning x2 . Our experimentshows that if V is flushed or evicted from the CPU cache before
the write gadget is executed, the primitive works in 100 % of
the test cases (n = 10 000). We observe that if the memory
at V is cached in a non-dirty cache line before we use thewrite gadget, we need to evict or flush it from memory to
make x2 visible. Once the memory is no longer cached, we
successfully read x2 in 100 % of the tests. If the memory at
V is cached in a dirty cache line, after flushing or evicting thecache line, the previous value x1 remains in memory. Theseobservations lead to the hypothesis that GhostWrite does notwrite through the cache hierarchy but directly to the physicalmemory without interfering with the cache state at all. Thishypothesis explains why dirty cache lines can reset the state
to x1 , as their value is written back to main memory. To
further strengthen this hypothesis, we investigate the hardware
performance monitor counters available on the C910. First, thecounter that keeps track of dTLB misses (mhpmcounter6)
does not count any event during the execution of the write
primitive. Thus, we conclude that no virtual mapping is being
resolved upon execution of the write primitive. Second, even
if V is uncached, the counter keeping track of memory writes
that miss the L1d cache (mhpmcounter17) and the L2dcache (mhpmcounter21) do not count events for our write
primitive. This further strengthens our hypothesis that the write
primitive does not interact with the cache hierarchy.

For the other documented instruction findings, the time to
bug is typically below 1 s. However, for some findings, fuzzing
times of up to 30 s are required to reveal them.
VI.

G HOST W RITE : W RITING A RBITRARY P HYSICALM EMORY

In this section, we analyze GhostWrite, the arbitrary physical write primitive RISCVuzz finds on the C910. In Section VI-A, we reverse-engineer the prerequisites and microarchitectural properties, showing that GhostWrite can deterministically write attacker-chosen values to attacker-chosen physical addresses with byte granularity. Sections VI-B to VI-D
demonstrate 3 end-to-end attacks as case studies, using
GhostWrite for reading and writing arbitrary physical memory
and executing arbitrary code with kernel- and machine-mode
privileges, fully circumventing virtual memory.
A. Analysis
Listing 1 shows the assembly code of GhostWrite.
A vsetvli instruction sets up the vector engine state.
vmv.v.x moves the byte to be written to a vector register.
The vse128.v instruction performs the actual write with atarget address in a general-purpose register.
1) Instruction Encoding: The instruction disassembles toa vector unit-stride store instruction from the unsupported
vector extension 1.0. This instruction should operate on virtual
memory and store vector registers continuously to target virtual
addresses stored in a general purpose register. We reduce theinstruction’s encoding to its minimal form and perform tests
on each component of the instruction encoding.
The source registers encoded in the instruction work as
intended, though only 1 byte is written. The destination
register encoding also works as intended, besides interpretingthe address as a physical instead of a virtual address. The
encoding of the effective element width is 128-bit. Thus, thevector registers should be handled as 16-byte registers. Notethat this encoding of 128-bit and higher is not standardized

3) MMIO: GhostWrite can write values to any address inthe physical address space, including memory-mapped inputoutput (MMIO). We use GhostWrite to write values of ‘0’ and‘0xff’ to the first 8 bytes of the MMIO range on Board I [48].
With a voltmeter, we verify that this changes the state of the9GPIO pins. This demonstrates that the instruction bypasses any
virtual memory mechanics and has full privileges.

C. Kernel and Machine Mode Attacks: From Write to Execute
Our second case study demonstrates how an attacker canuse GhostWrite to gain arbitrary code execution in the kerneland machine mode, thus elevating privileges.

4) Simulation: Although the C910 sources are released as
openC910 [54], the vector extension cannot be enabled, as it is
not part of the source. Any attempt to execute GhostWrite in
the simulator fails. This aligns with discussions in the GitHub
repository mentioning that the “openC910 didn’t include theV extension because it wasn’t officially final yet” [54].

a) Threat Model: We assume that the attacker has
unprivileged native code execution on the target. We assume
the attacker knows the physical memory layout of the kernel.
This assumption is viable in practice, as the physical memory
layout is highly predictable. Alternatively, an attacker canemploy an arbitrary read gadget (e.g., Section VI-B) to scanfor the kernel. For escalating privileges to root, our end-toend exploit assumes the presence of a setuid binary suchas sudo or su that uses the getuid syscall to determine
whether a user is already root and, therefore, does not need
to authenticate. To gain code execution in machine mode, we
assume the presence of OpenSBI with a known version andphysical memory location.

Takeaway Even for open-source cores, the published source
is not necessarily the code used for synthesizing the hardware. Thus, opaque-box testing techniques are needed evenwhen the sources are public.
B. Page-Table Attack: From Write to ReadOur first case study turns GhostWrite into an arbitrary readgadget by rewriting page-table entries.
a) Threat Model: We assume that the physical memory
and kernel configuration is unknown to the attacker. We only
assume unprivileged native code execution on the target.

b) Attack: To gain code execution in the kernel, theattacker uses GhostWrite to overwrite the code of a systemcall handler. Then, the attacker triggers the corresponding
syscall to execute the injected payload. Since virtual memory
is completely bypassed by GhostWrite, the same principle
can be used from containers or virtualized environments to
attack a known host. In our proof-of-concept implementation,
the attacker overwrites the getuid syscall to always return‘0’. On Linux systems, the user ID ‘0’ is reserved for theprivileged root user. Then, the exploit executes the su setuid
binary. If getuid returns ‘0’, su assumes a user is alreadyroot and skips authentication, leading to privilege escalation to
the root user. Once a privileged shell is obtained, the exploit
uses GhostWrite to restore the original getuid to not break
any legitimate functionality of other applications and to purge
any traces of the attack.

b) Attack: Our attack is inspired by the first privilege
escalation using Rowhammer [44]. We fill the entire available
physical memory with page tables by allocating large amountsof virtual memory. Specifically, we map the same file numerous times until the physical memory is exhausted. We needto spawn multiple processes to exhaust physical memory withpage tables, as current RISC-V kernels use the Sv39 virtual
addressing mode, where virtual addresses only use 39 bit.
Filling the entire
2 512 GB of virtual address space only spawns
1 + 29 + 29 = 262 657 page tables, which is only around
1 GB of physical memory. We use GhostWrite to overwrite oneof the two least significant bytes of the page frame number ofa potential page-table entry (PTE). Given that the memory isfilled with page tables, we choose a random address in thesecond half of physical memory, in line with our analysis of
the distribution of page tables in physical memory (Section E).
If, after the modification, one of our page mappings does not
map to the initially mapped file anymore, we know that we
successfully overwrote a PTE. We verify that by reading fromevery mapping and comparing the read value to a fixed marker
value. Note that we need to evict the TLB before employing
this scan since the TLB might shadow our PTE modification.
When no such virtual address is found, we write the PFN byte
on a different physical page.

For code execution in machine mode, ourproof-of-concept overwrites parts of the function
sbi_ecall_base_handler, which handles ecalls in
OpenSBI. Since our previous attack enables code execution
in the kernel, we assume an attacker can trigger arbitrary
SBI ecalls. In our proof of concept, we patch the ecall
handler for SBI_EXT_BASE_GET_MVENDORID to return
42 and verify the return value using a kernel module. In a
real-world scenario, an attacker could place arbitrary code atany physical address and patch a jump to their payload into
the ecall handler.

Once such a virtual page is found, we know that we havefull control over a PTE and its corresponding virtual address.
Thus, we can rewrite the PFN to any physical address to readthe content of the address. We can also change the permission
bits in the PTE to provide write access if required.

c) Evaluation: We evaluate all attacks successfully on
the 3 C910 boards (G, H, and I). The attacks take less than
1 s, since the addresses are known and only a physical writewith GhostWrite is needed. The OpenSBI binaries, implementing the machine-mode functionality for RISC-V systems, aremapped at physical address ‘0’ on the C910-based systems.
The kernel code and data follow at 0x200000. We verify
that this layout is stable across reboots. As GhostWrite always
works (Section VI-A), and the physical layouts of kernel and
OpenSBI do not change, the exploit’s success rate is 100 %.

c) Evaluation: We run the attack successfully on 3
different CPUs, Board G, Board H, and Board I, with 3
different DRAM configurations, 4 GB, 8 GB, and 16 GB. The
attack also works from within a Docker container. We evaluate
the attack on Board H with 8 GB of memory. We reboot
the machine between each run of the attack. Our attack is
successful in all 20 tries, resulting in a success rate of 100 %.
The attack takes 32 to 94 s. 14 out of 20 times, overwriting thefirst randomly-selected address leads to a successful attack. In
the other cases, up to 3 addresses have to be tried.

D. Ineffective Faults: From Write to Indirect ReadIn our third case study, we demonstrate how GhostWrite
can be combined with ineffective fault attacks [9], [11], [65]10

to read secrets such as cryptographic keys indirectly. We
demonstrate this by recovering TLS signing keys via an oracle
that only exposes whether a signature was successful.

th.lbib t0, (t0), 0, 0
frcsr t0
3 li t0, 0
12a) Threat Model: We assume the victim runs a serverusing OpenSSL with TLS 1.3 on the same machine as theattacker. The attacker acts as a malicious client, repeatedly
connecting to the TLS server and triggering the handshakeprocess. This scenario is practical when the attacker runs
inside virtual machines or containers. The attacker can easily
exhaust the physical memory, as described in Section VI-B.
Consequently, we assume that the attacker can influence thephysical address of the private key and one of the RSA-CRT
parameters using memory massaging [30].

Listing 2: The interaction of the th.lbib instruction withthe same register as source and destination, a CSR read, andan unrelated operation on the register halts the C906.

A. Analysisa) C906: Listing 2 shows the instruction sequencehalting the C906. The core of the sequence is the th.lbib
instruction from the custom XTheadMemIdx extension. This
vendor extension provides additional memory operations suchas increment-address-before-load (th.lbib). The halt occurs
in combination with using the same register for source and destination operand, a subsequent CSR read, and any subsequentinteraction with the register provided to the instruction. In theexample code, we read a CSR using the unprivileged frcsr
instruction. However, any other instruction reading a CSR,
such as rdcycle, can also be used. While the example uses
the load immediate instruction (li), the last instruction canbe any instruction interacting with the used register. Unrelated
instructions can be part of the sequence if they do not readfrom or write to the used register (t0 in the example).

b) Attack: We target the TLS signing step in the
OpenSSL library, explicitly focusing on scenarios where theserver selects the RSA algorithm for digital signatures. In
TLS 1.3, the server must sign a hash that encapsulates thehandshake messages exchanged with the client before thehandshake is finished. With such a signature, the client canverify the server’s authenticity. OpenSSL’s TLS implementation employs the RSA-CRT (Chinese Remainder Theorem) optimizations for efficiency. If faults happen during the signing,leading to a wrong signature, the server attempts to re-signusing the traditional textbook RSA method. This additionalverification step effectively mitigates Bellcore attacks [2], [4].
To introduce a faulty signature, an attacker has to corrupt
both of the two signing algorithms. The attacker first corrupts
the parameters used for RSA-CRT employing GhostWrite.
That forces the server to start using the textbook RSA algorithm. Then, the attacker corrupts the private key byte-by-byte
in physical memory. For each byte, the attacker attempts toestablish an SSL connection 256 times, each with a different
possible value written to that specific byte. Only if the written value is correct, the attacker observes a successful SSL
connection. The attacker uses this feedback as a side channel
to recover the private key. Similarly, the attacker can recover
the parameters used for RSA-CRT by switching to iteratively
modifying the content of the parameters.

The T-Head vendor extension docs [56] mention that using
the same register as source and destination is not a valid
encoding. Compilers that support the vendor extension do
not support compiling assembly code with this faulty encoding. However, without the subsequent operations involving
a CSR and another operation on the register, no CPU halt
occurs. We further discover that 13 other instructions from the
XTheadMemIdx extension are vulnerable (cf. Listing 3 inSection B) in the same way. Surprisingly, the variants with 3
source registers are not vulnerable.

Using statistical ineffective fault attacks to recover theprivate key typically involves a prolonged correlation analysis [11], due to the difficulty of analyzing the biased distribution of each fault. In contrast, our attack uses a physical writethat allows the attacker to modify the private key byte by byte.
This capability significantly simplifies the attack by reducing
the complexity of determining the correct bits of the key.

b) C908: The instructions discovered by RISCVuzz on
the C908 correspond to the vector mask store/load instructions
vsm.v and vlm.v. Setting any of the bits 29 to 31 in theencoding of these instructions crashes the machine. Note thatthese bits should be all unset, i.e., zero, when the instruction
is assembled correctly. Other bits seem unaffected.

Takeaway CPU vulnerabilities exist for both single instructions and instruction sequences.

Takeaway Testing the entire possible encoding space isnecessary, as vulnerabilities are in the documented andundocumented range.

c) Evaluation: We successfully mount the attack on
Board H. The victim uses an unmodified OpenSSL version
3.0.9. We observe a leakage rate of 1.10 bit/s over 10 trials.
On average, it takes the attacker 30 minutes to fully recover
the private 2048-bit RSA key or half of the time to recover
the 1024-bit parameters of RSA-CRT.
VII.

B. Bug Reproduction in Simulator
In contrast to the other tested CPUs, the source code of
the C906 is available, and the source contains the same vulnerability as the hardware CPU. Thus, we can also reproduce
the vulnerability in the simulation of the Verilog source. We
run the source from the official T-Head repository of theC906 [53] using the ICARUS Verilog compilation system [62].
The simulation machine is an Intel Core i9-13900K with
16 GB RAM running Ubuntu 22.04.

CPU-H ALTING I NSTRUCTION S EQUENCES

In this section, we analyze the instruction sequences
RISCVuzz finds for halting the C906 and C908, requiring a
hard reset. We analyze the sequences on hardware, reproduce
the findings in the simulation of the C906, and present an
end-to-end denial-of-service attack from within Docker.
11Takeaway Optional hardware features should have the capability to be deactivated.

We reduce the instruction sequence to a minimal 24 B
bare-metal binary containing only 6 instructions. Running thissequence reliably stops the simulator with the error message
that the CPU is stuck and no instructions are retiring anymore.
This happens after 11.5 µs CPU time. It takes the simulation
2.5 min to reach this point.

C908 Halting Instructions. The C908 halting instructions
are in the vector-extension range. Disabling the vector extension fortunately prevents exploitation. Recompiling the Linuxkernel without vector support leads to an illegal-instruction
exception when executing the instruction, mitigating the DoSof these instructions.

C. Case Study
To assess the impact of the vulnerability, we evaluate
in which contexts it can be executed to halt the CPU. The
straightforward scenario is an unrestricted native environment
as has been used by RISCVuzz. Executing the instruction
sequence as a privileged or unprivileged user immediately
results in the CPU being halted. We verify the C906 behavior
on two different boards, Board D and E, using two different
operating systems, Debian 11 and Debian 12. Additionally,
we verify the C908 behavior on Board F with Debian 13.
While executing the instruction in machine mode also halts theCPU, there is no realistic threat model where this is relevant.
However, attackers can also use the instruction sequence inmore restricted environments. We verify that executing the
instruction in an unprivileged Docker container also halts
the CPU. Thus, sandboxing mechanisms that work on theoperating-system level cannot prevent an attacker from halting
the CPU. Furthermore, given that all involved instructions are
unprivileged instructions, we also expect that sequence to workfrom a virtual machine. Unfortunately, we cannot verify that,as no current hypervisor supports the C906 or C908.
VIII.

We perform the same benchmark as in Section VIII since
the mitigation is the same. We run rvv-bench on Board
F and find that the performance of memcpy and memset
decreases by up to 77 % and 2 %, respectively.
IX.

R ELATED W ORK

Undocumented Instructions. Armshaker [52] is an approachthat iterates over the entire 32-bit ARM instruction space tofind undocumented instructions. Similarly, Dofferhoff et al.
[12] propose a tool to find undocumented instructions for RISC
architectures like ARMv8 and RISC-V using disassemblers
as a ground truth. Both works discovered multiple emulatorbugs and inconsistencies in the respective ISA standards.
DifuzzRTL [23] and Morfuzz [64] also fuzz undocumented
instructions on RISC-V. However, in contrast to RISCVuzz,
DifuzzRTL and Morfuzz require a perfect simulator to detectmisbehaviors in the executed code. Sandsifter [14] shows that
it is feasible to search for undocumented x86 instructions
by exploiting a side channel to infer up to which byte an
instruction was successfully decoded, dealing with the 15-byte
instruction space. In contrast to previous work, RISCVuzz does
not require any ground truth and can exhaustively test the entire
instruction space.

M ITIGATIONSIn this section, we discuss mitigations for GhostWrite(Section VI) and the CPU-halting sequences (Section VII).

Differential CPU Fuzzing. Differential fuzzing is a wellknown software fuzzing technique that was recently applied to
CPU fuzzing. Tavis Ormandy found critical security vulnerabilities by comparing code generated by their fuzzer against a
serialized variant of the code [35], [36]. For this so-called Oracle Serialization, the initial code is modified by adding memory
fences between the individual instructions. Such techniques
make it possible to find differences that depend on speculativeor out-of-order execution. Bugs that do not depend on such
optimizations are invisible to this technique. For example,
GhostWrite behaves the same when fences are added andhence cannot be detected by this approach. Further, crossvendor or cross-generation bugs cannot be discovered with thistechnique, since results are only compared to other cores on
the same CPU. RISCVuzz finds these classes of bugs too, as itcompares the behavior against different CPUs from potentiallydifferent vendors. SiliFuzz [45] targets x86 CPUs with the goalof finding electrical defects on single cores instead of bugs. As
SiliFuzz does not compare different CPUs but different coreson one CPU, the found bugs of SiliFuzz and RISCVuzz are
different. For our tested CPUs, all cores on the same CPU
behave the same, as the differences are due to implementation
errors of the CPU and not due to electrical defects of single
cores. Qin et al. [37] and Jiang et al. [24] compare CPUs
with emulators and disassemblers to build stealthy malware by
exploiting different runtime behaviors. In contrast to our paper,
they discover and exploit bugs in software, not in CPUs.

GhostWrite. Disabling the vector extension is a viable mitigation for GhostWrite. We use a kernel module to verify thismitigation on the C910. The CPU throws an illegal instruction
exception when executing the instruction [60], making thegadget unusable for an attacker.
We benchmark the impact of this mitigation on standard
memory operations such as memcpy and memset. We use the
RISC-V vector benchmarking suite rvv-bench [3] on Board
H. We compare the fastest vector implementation of memcpy
and memset to the fastest of glibc and musl libc. We observea performance hit of up to 33 % for memcpy and 8 % formemset. Benchmarking the mitigation on a full-system levelis currently not possible, since no distribution uses the vector
extension in the kernel and standard libraries.
C906 Halting Sequence. There is no mitigation for theC906 halting instruction sequence that can be used for DoS
from an unprivileged process. Since no special condition isneeded to execute the C906 halting instruction sequence, we
argue that the only option for mitigating the vulnerability is
to disable one of the instructions. Unfortunately, the T-Head
vendor extension that includes the broken instructions cannot
be disabled: “The th.sxstatus.THEADISAEE bit is notexpected to be cleared. The behavior of clearing this bit isundefined” [56]. We verify that we cannot clear this bit froma kernel module.
12Model Fuzzing. TheHuzz [26] and DifuzzRTL [23] arefuzzers that target the register-transfer level (RTL) model ofCPUs. The benefit of targeting the CPU’s RTL is that thesefuzzers can be used during development and that emulationof the cores can provide coverage information to guide thefuzzer’s search. Solt et al. [51] improve upon that approachby generating more complex instruction sequences to improve
fuzzing throughput and discover bugs with more complex
conditions. The major drawback of all RTL-based fuzzers
is that they require a complete RTL to work in the firstplace. In contrast, RISCVuzz targets the orthogonal problemof finding bugs in opaque-box hardware CPUs with the advantage of faster fuzzing throughput and testing the actual
deployed CPUs. Due to its speed, RISCVuzz fully explores
all undocumented instructions with a bottom-up approach(Section IV-C1) rather than a mutaion approach. Guidance [25]or fuzzing by proxy [45] could also be used for RISCVuzz.
However, even without this guidance, RISCVuzz produces
many results, leaving this guidance for future work.
X.

feedback channel. Similarly, evaluating diversity graphs of oursequences is not possible, as we have no coverage information.
However, the results of MorFuzz [64] suggest that more
complex sequence generation approaches might be beneficial.
Note that these problems are inherent to opaque-box fuzzing
and not a particular weakness of our approach. However, evenwith our simple sequence generation, we uncover most of thebugs in seconds due to the high throughput of running themon hardware. Recent work on software fuzzing also suggeststhat even simple input generation can be efficient [33]. We
leave improving upon our simple sequence generation or using
hardware side channels for coverage for future work.
d) Compliance: The findings from RISCVuzz demonstrate numerous architectural differences in instructions across
CPU vendors and even across CPUs of the same vendor. Thesefindings also suggest that several of these differences violate
the ISA specification, making it difficult to write applications
that run correctly on all RISC-V CPUs. Thus, we advocate
an extensive compliance-testing framework for RISC-V. While
there is an architectural test suite [20], many parts are notcovered, including the vector extensions we exploited.

D ISCUSSION

In this section, we discuss the impact of our findings,
coverage and ground truth, an outlook on future problems,
and the need for compliance testing.

e) Outlook: At the time of writing, only T-Head and
SiFive have commercially available off-the-shelf machineswith general-purpose 64-bit RISC-V CPUs. Still, even withthis limited selection of vendors and CPUs, RISCVuzz finds
a large number of bugs and inconsistencies. In the future,
we expect to see more vendors building CPUs based on
custom designs. Combined with the unregulated use of the ISA
and the possibility of creating custom vendor extensions, we
expect this state to worsen. Architectural inconsistencies will
become especially relevant for trusted-execution environments
and virtualization, as current vendor extensions might notconsider the future-proofness of their extensions concerningpotentially different privilege levels. Similarly, with RISC-V
support in Linux and Android, vendor customizations mightundermine security guarantees or lead to unstable systems.

a) Impact: While there are still not many 64-bit RISCV boards on the market, they already gain traction. Scaleway
provides cloud instances with the TH1520 SoC [42], whichcontains a C910 CPU. We verified that the used CPU isindeed vulnerable, and we reported our findings to Scaleway.
The Shandong University in China also has a RISC-V cluster
using a variant of the C910 CPU [46]. Unfortunately, we do
not have access to this system to test if this C910 variant isalso vulnerable. Mitigating GhostWrite is only possible by disabling the entire vector extension, resulting in a reduced feature
set and lower performance for specific workloads. Worse, theCPU halting sequence on the C906 has no mitigation, making
these CPUs essentially unsuitable for running untrusted codeor deployment in multi-user systems.
We assume that with a microcode layer, as on x86,
GhostWrite could be mitigated. An x86 microcode update canhook and patch instructions [5], which could have been used tohook the broken vector instruction and simply raise an illegalinstruction exception. Given the increasing complexity of
RISC-V CPUs, we advocate such a microcode layer on RISCV to have the possibility of mitigating CPU vulnerabilities.

XI.

C ONCLUSION

In this paper, we introduced RISCVuzz, a differential CPU
fuzzing framework for RISC-V hardware CPUs for automatically discovering architectural CPU bugs. RISCVuzz compares the architectural results of instruction sequences without
relying on CPU source code or any emulator. RISCVuzz
discovered 3 severe security vulnerabilities and numerous otherbugs on 5 different CPUs. On the T-Head C910, RISCVuzz
discovered GhostWrite, an instruction sequence that allows
unprivileged attackers to write arbitrary values directly tophysical memory, entirely circumventing virtual memory andits protection. We demonstrate that GhostWrite can also be
used to read memory and to inject attacker code into kernel andmachine mode. Further, we investigated two “halt-and-catchfire instructions” on two different CPUs, the T-Head XuanTie
C906 and T-Head XuanTie C908, and showed how they leadto unprivileged denial of service. RISCVuzz discovered mostbugs and vulnerabilities within seconds, showing the efficacyof our post-silicon fuzzing approach. We outperform state-ofthe-art RTL-based fuzzers in instruction execution by ordersof magnitude, making it a valuable extension to these fuzzers.

b) Ground Truth: RISCVuzz can be used in scenarios
where no ground truth, i.e., an emulator or another reference
implementation, is available because it does not require agolden model. Cases where no ground truth is available include(custom) ISA extensions like T-Head’s custom draft vector
extension [57], CPUs where the source code is not (fully)
available like with GhostWrite, or where no source codenor documentation about a feature is available at all as with
the CPU-halting instructions on the C908. Even if emulators
are available, they might be inconsistent [24] or based on adifferent code base, as we see for the C910.
c) Coverage & Sequence Complexity: Generating complex instruction sequences that increase coverage over time isdifficult for opaque-box fuzzing since we have no adequate
13

ACKNOWLEDGMENT
This work was supported in part by Semiconductor Research Corporation (SRC) Hardware Security Program (HWS)
and by a Google Research Scholar award. Any opinions,findings, conclusions, or recommendations expressed in thispaper are those of the authors and do not necessarily reflect
the views of the funding parties.
R EFERENCES
[1]

[2]

[3]
[4]
[5]

[6]

[7]

[8]

[9]
[10]
[11]

[12]

[13]
[14]
[15]
[16]
[17]
[18]

[19]
[20]
[21]
[22]
[23]

K. Asanovic, R. Avizienis, J. Bachrach, S. Beamer, D. Biancolin,
C. Celio, H. Cook, D. Dabbelt, J. Hauser, A. Izraelevitz et al., “Therocket chip generator,” EECS Berkley, 2016.
C. Aumüller, P. Bier, W. Fischer, P. Hofreiter, and J.-P. Seifert, “Fault
attacks on RSA with CRT: Concrete results and practical countermeasures,” in CHES, 2002.
O. Bernstein, “rvv-bench: Risc-v vector benchmark,” 2023. [Online].
Available: https://github.com/camel-cdr/rvv-bench
D. Boneh, R. A. DeMillo, and R. J. Lipton, “On the importance ofeliminating errors in cryptographic computations,” 2001.
P. Borrello, C. Easdon, M. Schwarzl, R. Czerny, and M. Schwarz,“CustomProcessingUnit: Reverse Engineering and Customization ofIntel Microcode,” in WOOT, 2023.
P. Borrello, A. Kogler, M. Schwarzl, M. Lipp, D. Gruss, and
M. Schwarz, “ÆPIC Leak: Architecturally Leaking Uninitialized Data
from the Microarchitecture,” in USENIX Security, 2022.
C. Canella, J. Van Bulck, M. Schwarz, M. Lipp, B. von Berg, P. Ortner,
F. Piessens, D. Evtyushkin, and D. Gruss, “A Systematic Evaluation ofTransient Execution Attacks and Defenses,” in USENIX Security, 2019,
extended classification tree and PoCs at https://transient.fail/.
C. Celio, D. A. Patterson, and K. Asanović, “The Berkeley Outof-Order Machine (BOOM): An Industry-Competitive, Synthesizable,
Parameterized RISC-V Processor,” Tech. Rep., 2015.
C. Clavier, “Secret external encodings do not prevent transient fault
analysis,” in CHES, 2007.
R. R. Collins, “The Pentium F00F Bug,” 1998. [Online]. Available:
http://www.rcollins.org/ddj/May98/F00FBug.html
C. Dobraunig, M. Eichlseder, T. Korak, S. Mangard, F. Mendel, and
R. Primas, “SIFA: Exploiting Ineffective Fault Inductions on Symmetric
Cryptography,” in IACR Transactions on Cryptographic Hardware andEmbedded Systems, 2018.
R. Dofferhoff, M. Göebel, K. Rietveld, and E. Van Der Kouwe,“IScanU: A portable scanner for undocumented instructions on risc
processors,” in International Conference on Dependable Systems andNetworks, 2020.
E. Dolstra, A. Löh, and N. Pierron, “Nixos: A purely functional linux
distribution,” in Journal of Functional Programming, 2010.
C. Domas, “Hardware Backdoors in x86 CPUs,” Black Hat US, 2018.
L. Foundation. (2023). [Online]. Available: https://git.kernel.org/pub/
scm/linux/kernel/git/next/linux-next.git/tree/arch/riscv/boot/dts/thead
R.-V. Foundation. (2019) Risc-v ”v” vector extension 0.7.1. [Online].
Available: https://github.com/riscv/riscv-v-spec/releases/tag/0.7.1——. (2021) Risc-v ”v” vector extension 1.0. [Online]. Available:
https://wiki.riscv.org/display/HOME/Ratified+Extensions——. (2021) Risc-v “zfh” and “zfhmin” standard extensions
for half-precision floating-point, version 1.0. [Online]. Available:
https://wiki.riscv.org/display/HOME/Recently+Ratified+Extensions——, “riscv-opcodes,” 2022. [Online]. Available: https://github.com/
riscv/riscv-opcodes——, “RISC-V Architecture Test SIG,” 2023. [Online]. Available:
https://github.com/riscv-non-isa/riscv-arch-test
M. Frysinger, “vdso(7) — linux manual page,” 2024.
L. Gerlach, D. Weber, R. Zhang, and M. Schwarz, “A Security RISC:
Microarchitectural Attacks on Hardware RISC-V CPUs,” in S&P, 2023.
J. Hur, S. Song, D. Kwon, E. Baek, J. Kim, and B. Lee, “Difuzzrtl:
Differential fuzz testing to find cpu bugs,” in S&P, 2021.

14

[24]

M. Jiang, T. Xu, Y. Zhou, Y. Hu, M. Zhong, L. Wu, X. Luo, and
K. Ren, “Examiner: Automatically locating inconsistent instructions
between real devices and cpu emulators for arm,” in ASPLOS, 2022.

[25]

N. Kabylkas, T. Thorn, S. Srinath, P. Xekalakis, and J. Renau, “Effective
processor verification with logic fuzzer enhanced co-simulation,” in
MICRO, 2021.

[26]

R. Kande, A. Crump, G. Persyn, P. Jauernig, A.-R. Sadeghi, A. Tyagi,
and J. Rajendran, “TheHuzz: Instruction Fuzzing of Processors Using
Golden-Reference Models for Finding Software-Exploitable Vulnerabilities,” in USENIX Security Symposium, 2022.

[27]

P. Kocher, J. Horn, A. Fogh, D. Genkin, D. Gruss, W. Haas, M. Hamburg, M. Lipp, S. Mangard, T. Prescher, M. Schwarz, and Y. Yarom,“Spectre Attacks: Exploiting Speculative Execution,” in S&P, 2019.

[28]

P. C. Kocher, “Timing Attacks on Implementations of Diffe-Hellman,
RSA, DSS, and Other Systems,” in CRYPTO, 1996.

[29]

Krimsky, “RISC-V Single Board Computers,” 2023. [Online].
Available: http://krimsky.net/articles/riscvsbc.html[30]

A. Kwong, D. Genkin, D. Gruss, and Y. Yarom, “RAMBleed: Reading
Bits in Memory Without Accessing Them,” in S&P, 2020.

[31]

M. Lipp, M. Schwarz, D. Gruss, T. Prescher, W. Haas, A. Fogh,
J. Horn, S. Mangard, P. Kocher, D. Genkin, Y. Yarom, and M. Hamburg,“Meltdown: Reading Kernel Memory from User Space,” in USENIX
Security Symposium, 2018.

[32]

W. M. McKeeman, “Differential testing for software,” 1998.

[33]

B. P. Miller, M. Zhang, and E. R. Heymann, “The relevance of classic
fuzz testing: Have we solved this one?” IEEE Transactions on Software
Engineering, vol. 48, 2022.

[34]

K. Murdock, D. Oswald, F. D. Garcia, J. Van Bulck, D. Gruss,and F. Piessens, “Plundervolt: Software-based Fault Injection Attacks
against Intel SGX,” in S&P, 2020.

[35]

T. Ormandy, “Reptar,” 2023.
//lock.cmpxchg8b.com/reptar.html[36]——, “Zenbleed,” 2023. [Online]. Available: https://lock.cmpxchg8b.
com/zenbleed.html[37]

S. Qin, C. Zhang, K. Chen, and Z. Li, “iDEV: Exploring and exploiting
semantic deviations in arm instruction processing,” in ISSTA, 2021.

[38]

P. Qiu, D. Wang, Y. Lyu, and G. Qu, “VoltJockey: Breaking SGX by
Software-Controlled Voltage-Induced Hardware Faults,” in AsianHOST,
2019.

[39]

RISC-V Collaboration, “riscv-gnu-toolchain,” 2024. [Online].
Available: https://github.com/riscv-collab/riscv-gnu-toolchain[40]

RISC-V Foundation, “RISC-V Exchange,” 2023. [Online]. Available:
https://riscv.org/exchange/[41]

RISC-V International, “Operating Systems,” 2024. [Online]. Available:
https://wiki.riscv.org/display/HOME/Operating+Systems[42]

Scaleway. (2024) The world’s first RISC-V servers available in thecloud. [Online]. Available: https://labs.scaleway.com/en/em-rv1/[43]

T. Scharnowski, N. Bars, M. Schloegel, E. Gustafson, M. Muench,
G. Vigna, C. Kruegel, T. Holz, and A. Abbasi, “Fuzzware: Using precise
MMIO modeling for effective firmware fuzzing,” in USENIX Security,
2022.

[44]

M. Seaborn, “Exploiting the DRAM rowhammer bug to gain
kernel privileges,” March 2015, retrieved on June 26, 2015.
[Online]. Available: http://googleprojectzero.blogspot.com/2015/03/
exploiting-dram-rowhammer-bug-to-gain.html[45]

K. Serebryany, M. Lifantsev, K. Shtoyk, D. Kwan, and P. Hochschild,“Silifuzz: Fuzzing cpus by proxy,” arXiv:2110.11519, 2021.

[46]

A. Shah. (2023) China deploys massive risc-v server incommercial cloud. [Online]. Available: https://www.hpcwire.com/
2023/11/08/china-deploys-massive-risc-v-server-in-commercial-cloud/[47]

SiFive, “HF105 Datasheet,” 2022. [Online]. Available: https://
sifive.cdn.prismic.io/sifive/d0556df9-55c6-47a8-b0f2-4b1521546543
hifive-unmatched-datasheet.pdf[48]

Sipeed, “Sipeed wiki,” 2021. [Online]. Available: https://wiki.sipeed.
com/en/index.html[49]——, “RISC-V 64bit chip (C910) run Android 10,” 2022. [Online].
Available: https://twitter.com/SipeedIO/status/1457529282134089734[Online].

Available:

https:

[50]
[51]
[52]

[53]
[54]
[55]
[56]
[57]

[58]

[59]
[60]

[61]

[62]
[63]
[64]

[65]

[66]

ISA throw a signal when run in RISCVuzz. Consequently, every further instruction in the sequence decreases the probabilityof a longer sequence by ∼ 40 %. This means the percentageof actually executed sequence lengths is roughly given by thefunction prob exec(n) = 0.4n . That further points out why
increasing the sequence length leads to diminishing returns.

——. (2023) Lichee Console 4A. [Online]. Available: https://sipeed.com/licheepi4aF. Solt, K. Ceesay-Seitz, and K. Razavi, “Cascade: Cpu fuzzing via
intricate program generation,” 2024.
F. Strupe and R. Kumar, “Uncovering hidden instructions in Armv8-A
implementations,” in Hardware and Architectural Support for Security
and Privacy, 2020.
T-Head, “openC906,” 2021. [Online]. Available: https://github.com/
T-head-Semi/openc906——, “openC910,” 2021. [Online]. Available: https://github.com/
T-head-Semi/openc910——, “C906,” 2022. [Online]. Available: https://www.t-head.cn/
product/c906——, “T-Head Extension Spec,” 2022. [Online]. Available: https://github.com/T-head-Semi/thead-extension-spec
T-Head,“Xtheadvector,”
2022.
[Online].
Available:
https://github.com/XUANTIE-RV/thead-extension-spec/blob/master/xtheadvector/intrinsics.adoc
J. Van Bulck, M. Minkin, O. Weisse, D. Genkin, B. Kasikci, F. Piessens,
M. Silberstein, T. F. Wenisch, Y. Yarom, and R. Strackx, “Foreshadow:
Extracting the Keys to the Intel SGX Kingdom with Transient Out-ofOrder Execution,” in USENIX Security Symposium, 2018.
A. Waterman and K. Asanović, “The RISC-V Instruction Set Manual,Vol. I: Unprivileged ISA, Version 20191213,” 2019.
A. Waterman, K. Asanović, and J. Hauser, “The RISC-V Instruction
Set Manual Volume II: Privileged Architecture, Document Version
20211203,” 2021.
A. Waterman, Y. Lee, D. A. Patterson, and K. Asanović, “The riscv compressed instruction set manual, version 1.7,” EECS Department,
University of California, Berkeley, 2015.
S. Williams, “Icarus verilog,” 2024. [Online]. Available: https://steveicarus.github.io/iverilog/
Xcalibyte, “Roma Laptop Pre-order,” 2022. [Online]. Available:
https://xcalibyte.com.cn/en/roma-preorder/
J. Xu, Y. Liu, S. He, H. Lin, Y. Zhou, and C. Wang, “{MorFuzz}:
Fuzzing processor via runtime instruction morphing enhanced synchronizable co-simulation,” in USENIX Security, 2023.
S.-M. Yen and M. Joye, “Checking before output may not be enoughagainst fault-based cryptanalysis,” IEEE Transactions on computers,
vol. 49, 2000.
R. Zhang, L. Gerlach, D. Weber, L. Hetterich, Y. Lü, A. Kogler,and M. Schwarz, “CacheWarp: Software-based Fault Injection using
Selective State Reset,” in USENIX Security, 2024.

th.lbibth.lwiath.lhuia
th.lwuia

th.lbiath.ldiath.lhiath.lhuibth.lwuibth.lwibth.ldibth.lbuibth.lbuia
th.lhib

Listing 3: List of instructions from the XTheadMemIdx
extension that can be used in Listing 2 to halt the C906 CPU.
A PPENDIX DG HOST W RITE S AMPLE R EPRODUCER
Listing 4 shows an example of a reproducer file generated
by RISCVuzz when comparing the results of vector instructions between C906 and C910, which both implement the
0.7.1 draft vector extension. The C906 generates a fault, while
the instruction executes just fine on the C910. This hints at
GhostWrite.
# signum differs# si_addr differs# si_pc differs# si_code differs## base: C910 (lab46)# signum:OK# -------------------------------# other: C906 (lab50)# signum:
SIGSEGV# si_addr:
0x8000000000000000# si_pc:
0xe100178# si_code:
0x1
instr_seq:- 0x5201f0a7
dis: ’’
dis_opcodes:- vse1024.v
regs:
gp:
gp: 0x8000000000000000
flags:- "-DVECTOR"A PPENDIX AD ETAILS ON U SED B OARDS
Table III extends Table I by the board models, memory
configuration, kernel, and OS version.
A PPENDIX B
C906 CPU- HALTING I NSTRUCTIONS

Listing 4: Example of a reproducer that hints at GhostWrite.
The C910 executes the vector-store instruction just fine, while
the C906 generates a fault.

Listing 3 lists the other broken instructions from the
XTheadMemIdx vendor extension on the C906. Any of these
instructions can be used instead of the th.lbib instructionin Listing 2 to halt the CPU.

A PPENDIX E
P HYSICAL PAGE TABLE D ISTRIBUTION
In Section VI-B, we use GhostWrite to overwrite pageframe numbers in physical memory to transform it into anarbitrary physical read primitive. We fill the entire physicalmemory with page tables so that the probability of hitting sucha page table when writing at a random address in memory ishigh. In this section, we experimentally verify this.

A PPENDIX CD ISTRIBUTION OF E XECUTED I NSTRUCTIONS INS EQUENCE
To further reason about the scaling of increasing the sequence length (cf. Figure 5), we collect the distribution of thenumber of executed instructions per sequence length. ∼ 40 %of the executed sequences stop right at the first instruction.
Equivalently, this means that ∼ 40 % of instructions in the base

We create 1 500 000 last-level page tables, filling up theentire 8 GB of memory on Board H by mapping a file
repetitively to memory in multiple processes. We then record
15TABLE III: Overview of tested RISC-V boards. We use CPUs from 2 vendors with varying extensions.
ID

Board ModelCPU

CPU Vendor

Relevant Extensions

MemoryOS

KernelA

BeagleV Fire

U54

SiFive-1.5 GB

Ubuntu 23.04

6.1.33

B

StarFive VisionFive2

U74

C
D
E

Sipeed Nezha
Lichee RV Dock
Lichee RV Dock

SiFive-8 GB

Ubuntu 22.04.1

6.5.0

T-Head

v0p7, zfh, XTheadMemIdx

1 GB
512 MB
512 MB

Debian 13
Debian 11
Debian 12

5.14.05.4.61
5.14.0

C906

F

CanMV Kendryte K230

C908

T-Headv, zfh, XTheadMemIdx

512 MB

Debian 13

5.10.4G
H
I
J

BeagleV Ahead
LicheePi4A
LicheePi4A
Milk-V Meles

C910

T-Head

v0p7, zfh, XTheadMemIdx

4 GB
8 GB
16 GB
8 GB

Ubuntu 23.04
Debian 12
NixOS
Debian 12

5.10.113
5.10.113
5.10.113
5.10.113
6
4

Run 1

2

Run 2

0

00

0
01 0000 0
02 000 00
0 0
03 000 00
0 0
04 000 00
0 0
05 000 00
0 0
06 000 00
0 0
07 000 00
0 0
08 000 00
0 0
09 000 00
0 0
0a 000 00
0 0
0b 000 00
00 00
0c 00 00 0
0d 000 00
00 00
0e 00 00 0
0f 000 00
00 00
10 00 00 0
11 000 00
0 0
12 000 00
0 0
13 000 00
0 0
14 000 00
0 0
15 000 00
0 0
16 000 00
0 0
17 000 00
0 0
18 000 00
0 0
19 000 00
0 0
1a 000 00
0 0
1b 000 00
00 00
1c 00 00 0
1d 000 00
00 00
1e 00 00 0
1f 000 00
00 00
00 0
00
0

Run index

·104
Run 0

Bucket adresses

Fig. 6: Physical distribution of page tables when filling 8 GB of memory with page tables over 3 runs. Accumulated into 32
buckets of 256 MB.

the physical addresses of these last-level page tables in 3 runs.
Figure 6 visualizes the distribution of the collected addresses.
Page tables are nearly uniformly distributed over the entire
physical memory, with a gap in the middle of memory and at
the start, where kernel and OpenSBI reside.

16