A fuzzer to search for microarchitectural leaks in CPUs
Project description
Revizor
Revizor is a security-oriented fuzzer for detecting information leaks in CPUs, such as Spectre and Meltdown. It tests CPUs against Leakage Contracts and searches for unexpected leaks.
For more details, see our Paper (open access here), and the follow-up papers (1, 2).
Installation
Warning: Revizor runs randomly-generated code in kernel space. This means that a misconfiguration (or a bug) can crash the system and potentially lead to data loss. Make sure you're not running Revizor on a production machine, and that you have a backup of your data.
1. Requirements
-
Architecture: Revizor supports Intel and AMD x86-64 CPUs. We have experimental support for ARM CPUs (see
arm-port
branch) but it is at very early stages, so use it on your own peril. -
No virtualization: You will need a bare-metal OS installation. Testing from inside a VM is not supported.
-
OS: The target machine has to be running Linux v4.15 or later.
2. Python Package
The preferred installation method is using pip
within a virtual environment.
The python version must be 3.9 or later.
sudo apt install python3.9 python3.9-venv
/usr/bin/python3.9 -m pip install virtualenv
/usr/bin/python3.9 -m virtualenv ~/venv-revizor
source ~/venv-revizor/bin/activate
pip install revizor-fuzzer
3. Executor
In addition to the Python package, you will need to build and install the executor, which is a kernel module.
# building a kernel module require kernel headers
sudo apt-get install linux-headers-$(uname -r) linux-headers-generic
# get the source code
git clone https://github.com/microsoft/sca-fuzzer.git
# build executor
cd sca-fuzzer/src/x86/executor
make uninstall # the command will give an error message, but it's ok!
make clean
make
make install
4. Download ISA spec
rvzr download_spec -a x86-64 --extensions ALL_SUPPORTED --outfile base.json
# Alternatively, use the following command to include system instructions;
# however, mind that testing these instructions may crash the system if misconfigured!
# rvzr download_spec -a x86-64 --extensions ALL_AND_UNSAFE --outfile base.json
5. (Optional) System Configuration
External processes can interfere with Revizor's measurements. To minimize this interference, we recommend the following system configuration:
- Disable Hyperthreading (BIOS option);
- Disable Turbo Boost (BIOS option);
- Boot the kernel on a single core (add
-maxcpus=1
to Linux boot parameters).
If you skip these steps, Revizor may produce false positives, especially if you use a low (sample size)[./docs/config.md) for measurements. However, a large sample size (> 300-400) usually mitigates this issue.
6. (Optional) Test the Installation
To make sure that the installation was successful, run the following command:
./test
Command Line Interface
The fuzzer is controlled via a single command line interface rvzr
(or revizor.py
if you're running directly from the source directory).
It accepts the following arguments:
-s, --instruction-set PATH
- path to the ISA description file-c, --config PATH
- path to the fuzzing configuration file-n , --num-test-cases N
- number of test cases to be tested-i , --num-inputs N
- number of input classes per test case. The number of actual inputs = input classes * inputs_per_class, which is a configuration option-t , --testcase PATH
- use an existing test case instead of generating random test cases--timeout TIMEOUT
- run fuzzing with a time limit [seconds]-w
- working directory where the detected violations will be stored
For example, this command
rvzr fuzz -s base.json -n 100 -i 10 -c config.yaml -w ./violations
will run the fuzzer for 100 iterations (i.e., 100 test cases), with 10 inputs per test case.
The fuzzer will use the ISA spec stored in the base.json
file, and will read the configuration from config.yaml
. If the fuzzer finds a violation, it will be stored in the ./violations
directory.
See docs for more details.
Quick Start
The following is an example of a simple fuzzing session with Revizor that will detect Spectre V1-like violations.
Create a configuration file config.yaml
with the following content:
# config.yaml
instruction_categories:
- BASE-BINARY # arithmetic instructions
- BASE-COND_BR # conditional branches
max_bb_per_function: 5 # up to 5 branches per test case
min_bb_per_function: 1
max_successors_per_bb: 2 # enable basic blocks with conditional branches
contract_observation_clause: loads+stores+pc # aka CT
contract_execution_clause:
- no_speculation # aka SEQ
How To Fuzz With Revizor
The fuzzing process is controlled by a configuration file in the YAML format, passed via --config
option. At the very minimum, this file should contain the following fields:
contract_observation_clause
andcontract_execution_clause
describe the contract that the CPU-under-test is tested against. See this page for a list of available contracts. If you don't know what a contract is, Sec. 3 of this paper will give you a high-level introduction to contracts, and this paper will provide a deep dive into contracts.instruction_categories
is a list of instruction types that will be tested. Effectively, Revizor uses this list to filter out instructions frombase.json
(the file you downloaded viarvzr download_spec
).
For a full list of configuration options, see docs.
Baseline Experiment
After a fresh installation, it is normally a good idea to do a quick test run to check that everything works ok.
For example, we can create a configuration file config.yaml
with only simple arithmetic instructions. As this instruction set does not include any instructions that would trigger speculation on Intel or AMD CPUs (at least that we know of), the expected contract would be CT-SEQ
:
# config.yaml
instruction_categories:
- BASE-BINARY # arithmetic instructions
max_bb_per_function: 1 # no branches!
min_bb_per_function: 1
contract_observation_clause: loads+stores+pc # aka CT
contract_execution_clause:
- no_speculation # aka SEQ
Start the fuzzer:
rvzr fuzz -s base.json -i 50 -n 100 -c config.yaml -w .
This command should terminate with no violations.
Detection of a Simple Contract Violation
Next, we could intentionally make a mistake in a contract to check that Revizor can detect it. To this end, we can modify the config file from the previous example to include instructions that trigger speculation (e.g., conditional branches) but keep the contract the same:
# config.yaml
instruction_categories:
- BASE-BINARY # arithmetic instructions
- BASE-COND_BR # conditional branches
max_bb_per_function: 5 # up to 5 branches per test case
min_bb_per_function: 1
max_successors_per_bb: 2 # enable basic blocks with conditional branches
contract_observation_clause: loads+stores+pc # aka CT
contract_execution_clause:
- no_speculation # aka SEQ
Start the fuzzer:
rvzr fuzz -s base.json -i 50 -n 1000 -c config.yaml -w .
As your CPU-under-test almost definitely implements branch prediction, Revizor should detect a violation within a few minutes, with a message similar to this:
================================ Violations detected ==========================
Contract trace (hash):
0111010000011100111000001010010011110101110011110100000111010110
Hardware traces:
Inputs [907599882]:
.....^......^......^...........................................^
Inputs [2282448906]:
...................^.....^...................................^.^
You can find the violating test case as well as the violation report in the directory named ./violation-*/
.
It will contain an assembly file program.asm
that surfaced a violation, a sequence of inputs input_*.bin
to this program, and some details about the violation in report.txt
.
Full-Scale Fuzzing Campaign
To start a full-scale test, write your own configuration file (see description here and an example config here), and launch the fuzzer.
Below is a example launch command, which will start a 24-hour fuzzing session, with 100 input classes per test case, and which uses big-fuzz.yaml configuration:
rvzr fuzz -s base.json -c demo/big-fuzz.yaml -i 100 -n 100000000 --timeout 86400 -w `pwd` --nonstop
If there is a violation, you can try to reproduce it with the following command:
rvzr reproduce -s base.json -c violation-<timestamp>/reproduce.yaml -t violation-<timestamp>/program.asm -i violation-<timestamp>/input_*.bin
If the violation is reproducible, it is useful to minimize it, so that it is easier to understand the root cause (note that minimization uses a different config file):
rvzr minimize -s base.json -c violation-<timestamp>/minimize.yaml -g violation-<timestamp>/program.asm -o violation-<timestamp>/minimized.asm -i 100 --simplify --enable-multipass --find-sources
The result of minimization will be stored in violation-<timestamp>/minimized.asm
. The further analysis is manual; you can find an example in this guide.
Need Help with Revizor?
If you find a bug in Revizor, don't hesitate to open an issue.
If something is confusing or you need help in using Revizor, we have a discussion page.
Documentation
For more details, see the website.
Citing Revizor
To cite this project, you can use the following references:
-
The original paper that introduced the concepts of Model-based Relation Testing, and which describes the main ideas behind Revizor.
Oleksii Oleksenko, Christof Fetzer, Boris Köpf, Mark Silberstein. "Revizor: Testing Black-box CPUs against Speculation Contracts" in Proceedings of the 27th ACM International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS), 2022.
-
The paper that introduced the idea of Leakage Contracts, as well as its theoretical foundations.
Marco Guarnieri, Boris Köpf, Jan Reineke, and Pepe Vila. "Hardware-software contracts for secure speculation" in Proceedings of the 2021 IEEE Symposium on Security and Privacy (SP), 2021.
-
A more accessible summary of the two papers above, in a journal format.
Oleksii Oleksenko, Christof Fetzer, Boris Köpf, Mark Silberstein. "Revizor: Testing Black-box CPUs against Speculation Contracts". In IEEE Micro, 2023.
-
The paper that introduced taint-based input generation, speculation filtering, and observation filtering:
Oleksii Oleksenko, Marco Guarnieri, Boris Köpf, and Mark Silberstein. "Hide and Seek with Spectres: Efficient discovery of speculative information leaks with random testing" in Proceedings of the 2023 IEEE Symposium on Security and Privacy (SP), 2022.
Contributing
See CONTRIBUTING.md.
Trademarks
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for revizor_fuzzer-1.3.0-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | dfbc05534272f062f4e77b8e3cbe04e4da524478d92298c9463c5b33ff942358 |
|
MD5 | 95c5d14749a0e78b5a3ee64af63dd1f9 |
|
BLAKE2b-256 | d0a3324adc7b99078e22597281ade312daf2aaa5a26898a0f084e91bf3e3b051 |