Skip to content

Proving the efficacy of software countermeasures for fault injection | Joshua Beaker | hardwear.io

Joshua BakerMark te Stroet

Engineers explore architecture and security mechanisms for Proving the efficacy of software countermeasures for fault injection | Joshua Beaker | hardwear.io.

Summary

### Overview In this hardwear.io conference presentation, Joshua Baker (also referred to as Joshua Beaker), a security analyst at Riscure, explains how to design, test, and combine software-only countermeasures to protect embedded software against hardware fault injection (FI) attacks. While hardware security research often focuses heavily on offensive attacks, this talk demonstrates practical defensive techniques implemented entirely in software (primarily C and ARM assembly) without requiring dedicated hardware modifications.

### Key Topics - **Fault Injection Mechanics & Fault Model**: Fault injection involves using external disturbances (such as electrical or electromagnetic glitching) to alter a chip's internal electrical state, changing stored data or instruction opcodes. Baker uses a fault model assuming an attacker who can induce a single bit flip or skip an instruction. - **Simulation with `fi_sim`**: To evaluate code resilience, Baker utilizes `fi_sim`, an open-source tool developed by Mark te Stroet (referred to as Mark Time). It simulates every possible fault against a target binary—specifically pineboot, an image verification bootloader—and tracks which injected faults successfully bypass security checks. - **Seven Software Countermeasures**: 1. *Minimal Branches*: Inlining functions using C attributes to eliminate branch instructions, preventing attackers from glitching branch target addresses or skipping function calls. 2. *Flow Control*: Maintaining a rolling tally/counter of unique, non-trivial constants (such as prime values) added across each executed function, and verifying the cumulative tally before critical operations. 3. *Assign Values / Non-arbitrary Values & Trapdoors*: Avoiding naive zero/one or boolean indicators for success/failure in favor of complex values (e.g., specific hex constants) and periodically verifying sensitive stored values via checksums or encryption. 4. *Decision Check*: Performing duplicate checks on critical decisions while using `volatile` variables to prevent the compiler from optimizing out redundant conditional logic. 5. *Aggregate Check*: Avoiding the premature combination of multiple checks into a single boolean state, which otherwise creates a single point of failure for an attacker. 6. *Loop Check*: Verifying that loop iteration counters reached their expected final value or range, protecting against early loop termination or skipped iterations. 7. *Crypto Check*: Mitigating fault-based key recovery attacks by re-encrypting or decrypting immediately after encryption and verifying the outcome against the original value.

### Technical Details & Evaluation Baker emphasizes that isolated countermeasures often add code that inadvertently increases the attack surface. In an evaluation against pineboot: - The baseline code had 327 exploitable fault locations. - Adding initial countermeasures initially increased the fault count (at one point adding 222 possible faults), as newly introduced branch or arithmetic instructions were not yet hardened. - Progressing through the defensive pipeline brought the counts down from 340 to 250, then 268, and finally down to just 8 exploitable faults once all countermeasures were combined. - The 8 remaining faults were entirely bit flips (no instruction skips/NOPs), consisting of 4 load faults in raw assembly (`entry.S`), 3 subfaults related to an un-inlined function call, and 1 branch fault inside encryption routines.

### Takeaways - Software countermeasures must be combined comprehensively; like patching a leaky pipe, securing only one part of the code shifts vulnerability pressure to unprotected areas. - Developers must thoroughly test implementations in simulators like `fi_sim` rather than guessing, because compiler optimizations can strip away redundant defensive code. - Defenses introduce measurable overhead: in the pineboot demonstration, code size roughly doubled and execution time doubled or tripled, meaning teams must carefully evaluate runtime tradeoffs when protecting critical assets.

Related talks