-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Dropped in a few example shell commands in README.md to help with installation * Briefly described the major architectural components of Revizor in docs/architecture.md * Created docs/cli.md to describe the different execution modes and their command-line switches * Created docs/modules.md to briefly describe the various Python modules and some test case generation details Co-authored-by: Connor Shugg <[email protected]>
- Loading branch information
Showing
7 changed files
with
285 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# Command-Line Interface | ||
|
||
Revizor can run in one of multiple "modes": | ||
|
||
* **Fuzzing mode** is revizor's main form of execution. It's what invokes all | ||
components of [revizor's architecture](architecture.md) to enable hardware | ||
fuzzing. | ||
* **Analysis mode** invokes the analyser to compare existing contract traces and | ||
hardware traces. | ||
* **Minimize mode** accepts a test case and attempts to minimize its size. | ||
It acts as a "watered-down" version of **fuzzing mode** that focuses solely on | ||
a single test case. | ||
|
||
To select a mode on the command-line, begin your command with: | ||
|
||
```shell | ||
cli.py MODE # ... arguments go here | ||
|
||
# Where MODE can be: | ||
# fuzz for fuzzing mode | ||
# analyse for analysis mode | ||
# minimize for test case minimization mode | ||
``` | ||
|
||
## Fuzzing Mode | ||
|
||
The following command-line arguments are supported in `fuzz` mode: | ||
|
||
* `-s` / `--instruction-set` - accepts a path to an XML file specifying the | ||
instruction set revizor should use. | ||
* `-c` / `--config` - accepts a path to a YAML configuration file for revizor. | ||
* `-n` / `--num-test-cases` - accepts an integer specifying the number of test | ||
cases to create and test during the fuzzing campaign. | ||
* `-i` / `--num-inputs` - accepts an integer specifying the number of inputs to | ||
generate for each test case (which corresponds to the number of contract | ||
traces to collect). | ||
* `-w` / `--working-directory` - accepts a path to a directory into which | ||
revizor will place its output files during the campaign. | ||
* `-t` / `--testcase` - accepts a path to an existing test case for the fuzzer | ||
to run. (Revizor will *only* run this test case if this is specified.) | ||
* `--timeout` - accepts an integer specifying the number of seconds to run the | ||
fuzzer. Once the timeout has been reached, fuzzing will cease. | ||
* `--nonstop` - if enabled, this keeps the fuzzer running after it encounters a | ||
violation. (Otherwise, if it's not specified, revizor will stop after the | ||
first violation is found.) | ||
|
||
## Analysis Mode | ||
|
||
The following command-line arguments are supported in `analyse` mode: | ||
|
||
* `--ctraces` - accepts a path to a file containing contract traces. | ||
* `--htraces` - accepts a path to a file containing hardware traces. | ||
* `-c` / `--config` - accepts a path to a YAML configuration file for revizor. | ||
|
||
## Minimize Mode | ||
|
||
The following command-line arguments are support in `minimize` mode: | ||
|
||
* `-i` / `--infile` - accepts a path to the test case revizor will attempt to | ||
minimize. | ||
* `-o` / `--outfile` - accepts a path specifying where the minimized version of | ||
the original test case will be written to. | ||
* `-c` / `--config` - accepts a path to a YAML configuration file for revizor. | ||
* `-n` / `--num-inputs` - accepts an integer specifying the number of inputs to | ||
try for the test case. | ||
* `-f` / `--add-fences` - if enabled, revizor will add as many `LFENCE` | ||
instructions as possible to the test case's assembly code while still | ||
preserving the violation-inducing behavior. | ||
* `-s` / `--instruction-set` - accepts a path to an XML file specifying the | ||
instruction set revizor should use. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,4 +21,4 @@ | |
|
||
# Tutorials | ||
|
||
None so far | ||
None so far |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
# Revizor Modules and Interfaces | ||
|
||
Revizor's implementation and [architecture](architecture.md) is separated into | ||
multiple Python files: | ||
|
||
* `cli.py` - implements the command-line interface of revizor. | ||
* `config.py` - implements parsing and managing of revizor's YAML configuration | ||
file. | ||
* `generator.py` - implements the **Test Case Generator** portion of | ||
[revizor's architecture](architecture.md). | ||
* `input_generator.py` - implements the **Input Generator** portion of | ||
[revizor's architecture](architecture.md). | ||
* `model.py` - implements the Unicorn-based **Model** portion of | ||
[revizor's architecture](architecture.md). | ||
* `executor.py` - implements the **Executor** portion of | ||
[revizor's architecture](architecture.md). | ||
* `analyser.py` - implements the **Analyser** portion of | ||
[revizor's architecture](architecture.md). | ||
* `postprocessor.py` - defines the `MinimizerViolation` class, used during | ||
`minimize` mode to reduce a violation-inducing test case down to a smaller | ||
size while still maintaining the violation-inducing behavior. | ||
* `fuzzer.py` - implements `fuzz` mode that utilizes all main components to | ||
perform end-to-end hardware fuzzing. | ||
* `coverage.py` - will collect coverage in the future; currently not in use. | ||
* `factory.py` - used to configure revizor accordingly to the user provided | ||
YAML configuration. Implements a simplified version of the Factory pattern: | ||
Defines a series of dictionaries that allows revizor to choose | ||
between various contract, generation techniques, executors, analysers, etc. | ||
In future, it be also used to implement multiple-ISA support. | ||
* `interfaces.py` - defines abstract classes (i.e., interfaces) of all main | ||
components of revizor (e.g., abstract `Executor`, `Model`, `TestCase`, | ||
`Input`, etc) | ||
* `isa\_loader.py` - defines the `InstructionSet` class, used to load an | ||
ISA's specifications from a JSON file provided via the | ||
[command-line interface](cli.md). | ||
* `service.py` - defines logging, statistical, and other services to all other | ||
modules within revizor. | ||
|
||
## Architecture-specific Implementation | ||
|
||
The modules above are ISA-independent. The architecture-specific implementations | ||
are located in the subdirectories. For example, the implementation of the modules | ||
for the x86-64 architecture is located in `src/x86/`. It's structure largely | ||
mirrors the main modules of revizor (e.g., `x86_model.py` contains x86-specific | ||
parts of the **Model** module). The only unique parts are: | ||
|
||
* `*_target_desc.py` - defines constants describing the ISA (e.g., a list of | ||
available registers) and some helper functions. | ||
* `isa_spec/get_spec.py` - a script for transforming the ISA description provided | ||
by the CPU vendor (different for every vendor) into a unified JSON format | ||
* `executor/` - contains a low-level implementation of the executor. The | ||
implementation will be different for each architecture. For black-box x86 CPUs, | ||
it is a Linux kernel module. | ||
|
||
## Abstract Test Case | ||
|
||
This describes a number of Python classes within revizor that define parts of an | ||
assembly test case. Revizor's TCG uses them to generate syntactically-valid | ||
assembly. The classes are defined in `interfaces.py`. | ||
|
||
#### `OperandSpec` | ||
|
||
The `OperandSpec` class defines a set of valid operands for any given assembly | ||
instruction. Each `InstructionSpec` object (described below) contains a list of | ||
these operand specifications. It contains properties such as: | ||
|
||
* The `type` of operand | ||
* The `width` of the operand | ||
* Whether or not the operand is a `src` or `dest` operand | ||
|
||
#### `InstructionSpec` | ||
|
||
This class represents a single instruction specification. It contains a name | ||
(i.e. the actual instruction mnemonic, such as `ADD`) and a list of | ||
`OperandSpec`s, defining valid operands for the instruction. It also has a | ||
number of boolean flags that indicate unique attributes about the instruction, | ||
such as: | ||
|
||
* If the instruction contains a memory write | ||
* If the instruction is a control-flow instruction | ||
|
||
#### `Operand` | ||
|
||
The `Operand` class defines an actual operand to be used in an instruction | ||
placed into the TCG's generated test case (not to be confused with | ||
`OperandSpec`, which is a set of rules used to define possible operand choices | ||
for an instruction). This is an **abstract base class** that provides a number | ||
of sub-classes: | ||
|
||
* `RegisterOperand` | ||
* `MemoryOperand` | ||
* `ImmediateOperand` | ||
* `LabelOperand` | ||
* `AgenOperand` | ||
* `FlagsOperand` | ||
|
||
#### `Instruction` | ||
|
||
Similar to the relationship between `OperandSpec` and `Operand`, the | ||
`Instruction` class defines an actual instruction, constrained by an | ||
`InstructionSpec`, that is used during test case generation. It contains a list | ||
of `Operand`s and is linked to its neighboring instructions via object | ||
references. | ||
|
||
#### `BasicBlock` | ||
|
||
Thisi class represents a single basic block within the generated test case (a | ||
**basic block** is a straight-line sequence of assembly instructions that has a | ||
single entry and exit point). It contains a list of all instructions contained | ||
within, references to its successor basic block(s), and a list of "terminator" | ||
instructions (instructions that exit the basic block, such as a branch). | ||
|
||
#### `Function` | ||
|
||
This object represents a collection of basic blocks that form a function. It has | ||
an "entry" basic block and an "exit" basic block, along with a list of all basic | ||
blocks that comprise the function. | ||
|
||
#### `TestCaseDAG` | ||
|
||
**DAG** is short for **Directed Acyclic Graph**. This object represents the | ||
*entire* test case's control flow. It contains a list of functions that, within, | ||
define all instructions to be written out to the test case's assembly file. | ||
|