# p2im
**Repository Path**: onceshy/p2im
## Basic Information
- **Project Name**: p2im
- **Description**: This is the source code for P2IM paper (accepted to Usenix Security'20)
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-11-25
- **Last Updated**: 2024-06-22
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# P2IM
This is the repo for *P2IM: Scalable and Hardware-independent Firmware Testing via Automatic Peripheral Interface Modeling*, a USENIX Security'20 paper. **Paper, slides, and presentation video** are available [here](https://www.usenix.org/conference/usenixsecurity20/presentation/feng).
P2IM conducts firmware testing in a generic processor emulator (QEMU). P2IM automatically models the processor-peripheral interface (i.e., peripheral register and interrupt) to handle the peripherals that are not supported by the emulator. Our follow-up work of P2IM, *DICE: Automatic Emulation of DMA Input Channels for Dynamic Firmware Analysis*, is accepted to IEEE S&P'21. Similar to P2IM, DICE tests firmware in QEMU. However, DICE supports firmware that uses DMA (Direct Memory Access) by automatically modeling the DMA input channels. DICE is open sourced [here](https://github.com/RiS3-Lab/DICE-DMA-Emulation).
## Directory structure of the repo
```
.
├── afl # fuzzer source code
├── docs # more documentation
├── externals # git submodules referencing external git repos for unit tests, real firmware, and ground truth
├── fuzzing
│ └── templates # "random" seeds and configuration file template to bootstrap fuzzing
├── LICENSE
├── model_instantiation # scripts for instantiating processor-peripheral interface model and fuzzing the firmware
├── qemu
│ ├── build_scripts # scripts for building QEMU from source code
│ ├── precompiled_bin # pre-compiled QEMU binary for a quick start
│ └── src # QEMU source code. AFL and QEMU system mode emulation integration is based on TriforceAFL.
├── README.md
└── utilities
├── coverage # scripts for counting fuzzing coverage
└── model_stat # scripts for calculating statistics of the processor-peripheral interface model instantiated
```
## Setup
All steps have been tested on 64-bit Ubuntu 16.04.
### Cloning all git submodules
```bash
# submodules are cloned into externals/
git submodule update --init
```
git submodules are binded to a specific commit. Updates in submodules can be fetched by
```bash
git submodule update --remote
```
### GNU Arm Embedded Toolchain
1. Download the toolchain from [here](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads).
2. Untar the downloaded file by `tar xjf *.tar.bz2`.
3. Add `bin/` directory extracted into your `$PATH` environment variable.
4. Test if the toolchain is added to `$PATH` successfully by `which arm-none-eabi-gcc`.
### AFL
```bash
# Compile AFL
make -C afl/
```
### QEMU
You can either use the [pre-compiled QEMU binary](qemu/precompiled_bin/), or build QEMU from source code following this [instruction](docs/build_qemu.md).
## Fuzzing
During fuzzing, P2IM instantiates processor-peripheral interface model on-demand (i.e., multiple rounds of model instantiation). The fuzzer-generated test cases are fed into the firmware when a DR is read.
The steps to fuzz a firmware by P2IM are as follows.
### Firmware preparation
You can fuzz one of the [10 real-world firmware](externals/) fuzz-tested in the P2IM paper,
or prepare your own firmware for fuzzing following this [instruction](docs/prep_fw_for_fuzzing.md).
### Creating working directory
All data related to fuzzing is stored in the working directory.
```bash
WORKING_DIR=/fuzzing///
mkdir -p ${WORKING_DIR}
cd ${WORKING_DIR}
```
Then copy the firmware ELF file (instead of the .bin file) to the working directory.
### Preparing seed files
AFL requires a seed file to start. P2IM does not require any specific seed file (such as well-formated seeds).
We used a ["random" seed](fuzzing/templates/seeds/) when fuzz-tested the real-world firmware.
```bash
# Copy the "random" seed to the working directory
cp -r /fuzzing/templates/seeds/ ${WORKING_DIR}/inputs
```
### Preparing the configuration file
A template for the configuration file is available [here](fuzzing/templates/fuzz.cfg.template)
```bash
# Copy the template to the working directory
cp /fuzzing/templates/fuzz.cfg.template fuzz.cfg
```
Please edit the configuration file following the instructions in the template.
You can find which mcu/board the [10 real-world firmware](externals/) are based on in Table 7 of our [paper](https://www.usenix.org/conference/usenixsecurity20/presentation/feng).
### Launching fuzzer
Please make sure there is no previously instantiated model in `${WORKING_DIR}` before launching fuzzer.
```bash
/model_instantiation/fuzz.py -c fuzz.cfg
```
## Analyzing fuzzing results
### Result organization
```
. # working directory
├── ...
├── 0 # round 0 of model instantiation. This is the first round, in which all-zero input is provided
│ ├── peripheral_model.json # the model instantiated after this round
│ └── ...
├── 0.. # rounds of on-demand model instantiation triggered by seed inputs
│ ├── aflFile # input that triggers this round of model instantiation (here is the seed input)
│ ├── peripheral_model.json # the model instantiated after this round
│ └── ...
├── # Rounds of on-demand model instantiation triggered by fuzzer-generated inputs. is any integer larger than 0.
│ ├── aflFile # fuzzer-generated input that triggers this round of model instantiation
│ ├── peripheral_model.json # the model instantiated after this round
│ └── ...
├── ...
├──
├── fuzz.cfg
├── inputs # seeds required by AFL
├── me.log # log of on-demand model instantiation
└── outputs # AFL-generated test cases (they are inputs to the firmware fed by P2IM at DR read)
├── crashes # crashing test cases
├── fuzz_bitmap # AFL coverage map
├── fuzzer_stats # AFL statistics
├── hangs # hanging test cases
├── ...
├── queue # all test cases that lead to distinctive execution path
└── run_fw.py # helper script for running firmware in QEMU, with the instantiated model
```
Order of model instantiation round: `0, 0.seed1.1, 0.seed1.2, ..., 0.seed1.m1, 0.seed2.1, ..., 0.seed2.m2, 1, 2, ..., n`. Round `n` is the `last_round_of_model_instantiation`.
### Calculating fuzzing coverage
```bash
cd ${WORKING_DIR}
/utilities/coverage/cov.py -c fuzz.cfg --model-if /peripheral_model.json
```
Coverage is output to `${WORKING_DIR}/coverage`, organized as follows:
```
coverage/
├── bbl_cnt # number of unique QEMU translation blocks executed
├── bbl_cov # execution frequency of each QEMU translation block. This is counted on all fuzzer-generated test cases
├── func_cov_merge_w_boot # execution frequency of each instruction, grouped by functions. This is counted on all fuzzer-generated test cases
├── func_cov_w_boot # function coverage
└── inst_cov_w_boot # execution frequency of each instruction. This is counted on all fuzzer-generated test cases
```
### Calculating statistics of the instantiated processor-peripheral interface model
```bash
# statFp3.py prints some statistics to stdout, some to stat.csv
/utilities/model_stat/statFp3.py /peripheral_model.json externals/p2im-ground_truth/ stat.csv
```
Documentation for `statFp3.py` can be found [here](utilities/model_stat/statFp3.py#L24).
Ground truth can be found [here](externals).
### Analyzing crashing/hanging input
`fuzz.py` automatically generates a helper script, `${WORKING_DIR}/run_fw.py`, for running test cases. The script runs firmware in QEMU using the instantiated model.
```bash
Usage: ./run_fw.py last_round_of_model_instantiation test_case [--debug]
--debug argument is optional. It halts QEMU and wait for a debugger to be attached
```
To debug the firmware, do
```bash
# Run QEMU in debug mode
./run_fw.py last_round_of_model_instantiation test_case --debug
# Attach gdb
arm-none-eabi-gdb -ex 'target remote localhost:9000'
```
## Running unit tests
Please refer to the documentation in `externals/p2im-unit_tests/README.md`
## More documentation
Please see [docs/](docs/) for more documentation.
Please refer to our [paper](https://www.usenix.org/conference/usenixsecurity20/presentation/feng) for more technical details of P2IM.
## Issues
If you encounter any problem while using our tool, please open an issue.
For other communications, you can email feng.bo [at] northeastern.edu.
## Citing our [paper](https://www.usenix.org/conference/usenixsecurity20/presentation/feng)
```bibtex
@inproceedings {p2im,
title = {P2IM: Scalable and Hardware-independent Firmware Testing via Automatic Peripheral Interface Modeling},
author={Feng, Bo and Mera, Alejandro and Lu, Long},
booktitle = {29th {USENIX} Security Symposium ({USENIX} Security 20)},
year = {2020},
url = {https://www.usenix.org/conference/usenixsecurity20/presentation/feng},
}
```