Space RadSim is a deterministic, binary-agnostic fault injection tool designed to simulate the effects of cosmic radiation (bitflips) on satellite firmware hardened with various exploit mitigation techniques. This repository supports our research on evaluating the trade-offs between radiation resilience and exploit defenses in space systems.
Target binaries must be organized in the following structure, where satelliteA is the name of the satellite, and flavorA represents the mitigation flavor (e.g., plain, canary-strong, cfi, etc.):
$HOME/satellites-targets/arm/
└── satelliteA-flavor-flavorA/
├── satelliteA.elf
└── config.ymlEach flavor directory must contain:
-
A config.yml file to configure fuzzing for that satellite-flavor combination. See the Hoedur documentation for configuration details.
-
A .elf file containing the compiled firmware binary.
To use run-radsim.py, you must manually set the following constants within the script:
TARGET_BINARY_NAME: Name of the ELF file.TARGET_SKIP_GOAL: The skip function indicating firmware initialization completion.
The run-radsim.py script should be invoked from the repository root using:
scripts/run-radsim.py ...The script assumes the $HOME/satellites-targets directory exists. It offers multiple subcommands, documented below.
| Argument | Description |
|---|---|
| --target | Name of the satellite (satelliteA) |
| --flavor | Target flavor, e.g., plain, canary-strong, or cfi |
| --campaing-id | An arbitrary campaign number that identifies multiple campaign of the same satellite and flavor |
You can run the fuzzer where --runs describes the number of parallel instances, i.e., the number of cores on the CPU.
scripts/run-radsim.py fuzz-flavor --target satelliteA --flavor plain --campaign-id 1 --duration 24h --runs 52After fuzzing, compute basic block coverage:
scripts/run-radsim.py cov --target satelliteA --flavor plain --campaign-id 1If the coverage shows that the fuzzing campaign covered all areas of interest, we continue to the corpus selection. First, we aggregate the independent fuzzing runs indicated through --runs earlier
scripts/run-radsim.py agg-runs --target satelliteA --flavors plain --campaign-id 1Then, select the top 50 inputs by combined coverage:
scripts/select-inputs.py corpus/SAT_satelliteA_FLAVORS_1_plain-hoedur --max-inputs 50Generate single-trace executions for bitflip injection:
scripts/run-radsim.py gen-traces --target satelliteA --flavor plain --campaign-id 1 --aggregate-only --single-tracesGenerate cross-flavor traces for comparison:
scripts/run-radsim.py gen-cross-traces --target satelliteA --flavor plain --campaign-id 1 --cross-flavors canary,canary-strong,cfi-icall,san-funcExhaustively inject single-bit flips into RAM:
scripts/run-radsim.py exhaust-bitflips --target satelliteA --flavors plain --campaign-id 1 --cores 48 --aggregate-only --only-aggregate-existing --target-regions ramIf you use this project in your research, please cite our paper:
@inproceedings{willbold2025radsim,
title = {{SPACE RADSIM: Binary-Agnostic Fault Injection to Evaluate Cosmic Radiation Impact on Exploit Mitigation Techniques in Space}},
author = {Willbold, Johannes and Cloosters, Tobias and W{\"o}rner, Simon and Buchmann, Felix and Schloegel, Moritz and Davi, Lucas and Holz, Thorsten},
booktitle = {2025 IEEE Symposium on Security and Privacy (SP)},
year = {2025},
organization = {IEEE}
}