CVE-2021-40506 - Breaking Down the OR120 ALU Overflow Flag Bug
In late 2021, a critical vulnerability was publicly disclosed under the identifier CVE-2021-40506. This vulnerability impacts the OR120 processor, specifically its Arithmetic Logic Unit (ALU). The OR120 is the reference design for the OpenRISC 120—a free and open-source CPU core used in research, academic, and some commercial projects. The issue affects versions of OR120 released between September 10, 2011 and November 11, 2015.
This long-read will explain the background, reveal the technical details (with code/Verilog snips), review how exploitation is possible, and what the real risks are for hardware and software relying on this processor.
Summary of the Vulnerability
The vulnerability centers on the ALU’s incorrect handling of the overflow flag (commonly known as the “V” flag or “OVF”). In particular, two critical instructions—msb (Multiply and Subtract) and mac (Multiply and Accumulate)—failed to update this overflow flag in hardware. The direct impact is that any software (e.g., operating systems, embedded firmware, realtime control systems) relying on correct overflow detection may behave unpredictably or insecurely as a result of this bug.
Original Advisory
The formal announcement of this bug is here:
CVE Details: https://nvd.nist.gov/vuln/detail/CVE-2021-40506
OpenCores discussion & patch: https://github.com/openrisc/or120/pull/85
What Does the OR120 Do?
The OR120 is a 32-bit open-source CPU written in Verilog, featuring a classic RISC structure. Like many CPUs, its ALU sets status flags (Zero, Carry, Overflow, Sign) after computation so software can react to special conditions (like integer overflow).
The Overflow Flag
The overflow flag indicates when an arithmetic operation produces a result too large for the destination register to represent (for signed numbers).
Example (in C-like pseudocode)
int32_t a = 100000000;
int32_t b = 200000000;
int32_t c = a + b; // This overflows a signed 32-bit int
if (overflow_flag) {
printf("Overflow detected!\n");
}
On hardware, most ALUs set or clear this flag as part of every “add,” “subtract,” or similar instruction. Software can then use exception handlers, control flow, secure boundary checks, or just error messages to handle overflows safely.
How Does OR120 Handle Overflow?
In Verilog, typical ALU operations involve creating a combinational circuit for the data path, plus logic for the status flags.
A simplified (non-buggy) status flag update might look like this
reg ovf_flag;
wire signed [31:] result, opA, opB;
always @* begin
result = opA + opB;
ovf_flag = ((opA[31] == opB[31]) && (result[31] != opA[31]));
end
But in the OR120, special instructions like msb and mac take a different path through the processor.
The Bug
Between the affected versions, the msb and mac instructions did not update the overflow flag at all. This means even if the result clearly overflowed, the flag wasn’t set—leaving downstream software “blind.”
Here is a snippet illustrating the flaw in the actual ALU implementation
// In or120_alu.v (NOTE: this is before the fix)
always @(/*ALU opcodes, operands*/) begin
case (alu_op)
//...
ALUOP_MS_B:
result = opA * opB - opC; // critical bug: overflow not set!
ALUOP_MA_C:
result = opA * opB + opC; // critical bug: overflow not set!
// Other opcodes where overflow *is* checked
default:
// ...
endcase
end
// ovf_flag never gets updated for msb, mac!
The Fix
A contributed fix (thanks to PenTest Partners) patched the ALU to update the overflow flag as expected for these instructions.
Reference Pull Request:
https://github.com/openrisc/or120/pull/85/files
Operating systems or real-time schedulers
…the wrong overflow flag might silently allow a buffer overrun, integer wrap, or improper error handling, often with disastrous results.
Imagine an embedded firmware using the MAC instruction
int32_t acc = ;
for (int i = ; i < len; ++i) {
acc = mac(acc, inputs[i], coeffs[i]);
if (overflow_flag) {
error_handler();
}
}
Due to CVE-2021-40506, if acc becomes too large, the software will not detect overflow, so the process continues with corrupted values. This opens the door to:
Bypassing controls (security boundaries ignored)
- Silent system hazards (industrial/military/medical risks)
Here’s a simple testcase you could run in a Verilog testbench to see the bug
module tb_alu_bug;
reg [31:] A, B;
wire [31:] result;
wire overflow;
// Instantiate buggy ALU
or120_alu DUT(.opA(A), .opB(B), .opcode(ALUOP_MAC), .result(result), .ovf_flag(overflow));
initial begin
A = 32'h7FFFFFFF;
B = 2;
#1;
$display("Result = %h, Overflow = %b", result, overflow); // Overflow is ! Should be 1.
$finish;
end
endmodule
Any engineer, researcher, hobbyist, or company that
- Uses the OpenRISC 120 (OR120) CPU RTL, especially from OpenCores
Download and apply the patch from GitHub:
https://github.com/openrisc/or120/pull/85/files
Recompile your hardware design with the fixed Verilog
- Verify downstream software does not workaround the overflow by software means (if so, remove those workarounds for code clarity)
References
- CVE-2021-40506 - NVD
- OpenCores OR120 project
- GitHub Patch Discussion
- PenTest Partners Blog *(Original research and discovery)*
Conclusion
CVE-2021-40506 may seem obscure (who attacks processor status flags?)—but for developers writing or maintaining low-level firmware, compilers, or high-assurance systems that trust the hardware to set its flags correctly, this bug can have massive impact. Luckily, because the OpenRISC/OR120 is open-source, the fix is publicly available and straightforward to deploy. Always keep platform IP (even “reference” designs!) up-to-date, and verify critical status logic for subtle bugs.
Stay safe, and keep checking those status flags!
*If you found this guide helpful, please consider sharing it or submitting patches upstream you believe would help the open hardware and open-source community.*
Timeline
Published on: 04/18/2023 12:15:00 UTC
Last modified on: 04/27/2023 15:41:00 UTC