The hardware world is no stranger to lurking bugs that can undermine months—or years—of development. In 2021, security researchers uncovered CVE-2021-41612, a subtle but dangerous flaw in the OpenRISC mor1kx processor’s ALU (Arithmetic Logic Unit) implementation. This bug led to the carry flag not updating properly after SUB instructions. While this might sound technical, the implications are real: critical software relying on the carry flag (CF) for arithmetic, cryptography, or safety checks could yield unpredictable or corrupt results.

In this post, we'll break down the nature of the vulnerability, what code is impacted, how it can be exploited, and what you can do about it. Skip ahead if you want code samples, exploit details, or official reference links.

What Is CVE-2021-41612?

The bug was first reported in the mor1kx GitHub repository and eventually tracked as CVE-2021-41612. In their documentation, the OpenRISC team describes that “the Carry flag is not being updated correctly for the subtract instruction, results in incorrect value of the Carry flag.”

To keep it simple:  
Whenever the processor’s SUB instruction runs, the ALU should set or clear the Carry flag to indicate if an unsigned borrow happened (i.e., did one number underflow when subtracted from another?). mor1kx’s faulty logic in the ALU doesn’t set this flag right. Any code making important decisions based on this flag can go off the rails.

The Carry (C) flag is essential in

- Multi-word arithmetic: Adding or subtracting numbers bigger than a CPU register (like 64 or 128-bit arithmetic on a 32-bit chip) relies on the carry to “spill” over.
- Security and cryptography: Cryptographic computations require exact arithmetic, and a wrong carry can ruin signatures or hashes.
- Trusted execution: Safety-critical embedded code may use the carry flag for bounds checking and error detection.

Failing to update this flag is not just an “edge” bug—it's one that can silently sabotage your computation.

Let’s look at a simplified snippet representing the problem in Verilog (hardware design language)

// Faulty logic in mor1kx ALU, roughly:
case (opcode)
  ALU_OP_SUB: begin
    result = A - B;
    // INCORRECT: carry flag logic is missing or wrong!
    carry_flag = (A >= B) ? 1'b : 1'b1; // Should be the other way around!
  end
endcase

Correct logic (what it should do)

carry_flag = (A < B) ? 1'b1 : 1'b; // Set carry if A < B (unsigned underflow)

In the faulty version, the carry flag could be the opposite, or never set or cleared, meaning *subsequent code could act as if a subtraction succeeded or failed when it did not*.

Let's say you run code like this in C

unsigned int x = 1, y = 2;
unsigned int result;
asm(
    "l.sub %, %1, %2\n\t"
    "l.mfspr %, r, r9\n\t" // Read status register with carry flag
    : "=r"(result)
    : "r"(x), "r"(y)
);

if (carry_flag_set(result)) {
    // Supposed to execute only if underflow occurred
    handle_underflow();
}

On a fixed CPU, handle_underflow() triggers only when x < y. On the buggy mor1kx, the flag is wrong—so your software may skip important checks or execute them at the wrong time.

An attacker with control over device code can subtly influence security-sensitive logic

- Authentication: If a hash, signature, or password check is implemented assuming the carry is set on underflow, authentication bypass is possible.
- Memory Safety: Bounds-checks relying on subtraction and the carry flag may become unreliable, leading to buffer overflows.
- Firmware: Firmware making low-level decisions based on the carry flag may misbehave, even crashing or erroring out unexpectedly.

While this CVE is not a remote code execution flaw, it enables “failure by invisible bug.” The worst part? It’s almost impossible to debug in software—developers may chase non-existent bugs in their own code.

Consider this (contrived) code snippet

// Multi-word subtraction relying on the carry flag
void subtract_128(uint64_t *high, uint64_t *low, uint64_t a, uint64_t b) {
    *low = *low - b;
    if (*low > *low - b) // Should have underflowed! Check via carry
        *high = *high - 1;
}

If the hardware carry flag isn't accurate because of mor1kx’s bug, the check may fail *even when underflow happened*. Now, a cryptographic counter or pointer may be one off, leading to memory corruption or failed integrity checks.

- mor1kx GitHub issue: https://github.com/openrisc/mor1kx/issues/88
- NVD Entry: https://nvd.nist.gov/vuln/detail/CVE-2021-41612
- Docs on OpenRISC status register: OpenRISC 100 Architecture Manual (PDF)

How to Defend Against This Bug

1. Update your RTL/FPGA Bitstream:  
  If you’re using mor1kx, apply the latest patch from the official repository. The issue is fixed in later versions.

Software Workarounds:

If you can’t update the hardware, avoid relying on the carry flag for critical decisions, or double-check subtraction with explicit comparisons in software.

Testing:

Add explicit tests for arithmetic edge cases—verify results on both hardware and in simulation environments.

Conclusion

CVE-2021-41612 is a classic example of a hardware design bug with outsized software effects. Anyone using OpenRISC mor1kx cores must update or workaround this carry flag issue. Remember, a processor bug is one of the trickiest kinds to encounter—it sits invisibly beneath your code, subtly baking in correctness errors. Always test thoroughly, and keep an eye on hardware advisories, even for open-source designs.

For more, check out mor1kx’s GitHub issue tracker and stay up to date with security bulletins for your silicon!


*If you found this helpful, share with your embedded or security-minded friends!*

Timeline

Published on: 04/18/2023 12:15:00 UTC
Last modified on: 04/27/2023 19:46:00 UTC