TUM Logo

Compiler-Based Return-Oriented Programming Prevention on RISC-V

Compiler-Based Return-Oriented Programming Prevention on RISC-V

Supervisor(s): Florian Jakobsmeier, Katharina Bogad, Konrad Hohentanner
Status: finished
Topic: Others
Author: Oliver Jacobsen
Submission: 2023-10-16
Type of Thesis: Masterthesis
Thesis topic in co-operation with the Fraunhofer Institute for Applied and Integrated Security AISEC, Garching


Return Oriented Programming (ROP) represents a category of code reuse
attacks targeting binary programs, wherein attackers leverage gadgets
within the program’s code section to gain control of the execution flow.

While the open-source RISC-V architecture presents novel challenges for
executing ROP attacks, recent research has demonstrated the feasibility
of deploying ROP techniques on this architecture.

Two notable distinctions from the x86 architecture include the split of
the function return into two instructions: one for loading the return
address from the stack and another for register-based jumps.

Additionally, RISC-V introduces a clear demarcation between preserved
registers, which are saved and restored during function calls, and
non-preserved registers.

We present two compiler-based transformations that leverage these
architectural features to harden binaries against ROP attacks while
incurring minimal overhead.

Importantly, these approaches do not rely on hardware-specific features
and are designed to ensure compatibility with existing hardening tools.

Early Return Address Load (ERAL) involves extending the minimum lengths
of ROP gadgets within function epilogues by relocating the instruction
responsible for loading the return address to an earlier point in the

Explicit Register Clear (ERC) focuses on instrumenting function
epilogues by inserting instructions to clear non-preserved registers
just before the return jump.

We implemented both designs as an LLVM compiler pass.

Our evaluation, using state-of-the-art benchmarks, indicates negligible
overhead for ERAL, with variable length increases constrained by the
structure of the control flow graph.

For ERC, we observed runtime overhead ranging from an average of 0.66%
to 5.48%.

Notably, this approach significantly reduces or eliminates gadgets
involving non-preserved registers within function epilogues.