This is the repo for CO3: Concolic Co-execution for Firmware from NU Seclab. CO3 features in instrumenting the firmware for a much faster (1000x) workstation-level firmware concolic execution while running directly on the MCU hardware.
- deps: projects that CO3 is dependent upon, except the SymCC folder which is there because that is the comparison target.
- firmware: source code for the firmware images used in the paper.
- fuzzer: fuzzing (i.e., SHiFT) and CO3 coordinator script borrowed from SymCC.
- pass: the LLVM instrumentation pass.
- sym_backend (aka the orchestrator): the symbolic constraint builder and solver that are based on CO3's protocol.
- sym_runtime: the runtime for workstation applications (to interact with the orchestrator).
- utils: helper scripts to visualize the SVFG, communicate with the MCU.
-
all artifacts and projects (including the firmware) are built with cmake, if you see
cmake build
, it means: create an emptybuild
dir, cd to it, typecmake ..
, and typemake
. -
If you want to instrument and build the firmware, the arm-gcc toolchain should be decompressed to the specific (i.e.,
./deps/arm
) folder. In such a case, a physical MCU, and a USB/(usart-to-USB) cable should also be available. -
We also have ports for desktop programs (see sym_runtime); however, this is currently under construction and only supports CGC programs.
-
Workstation:
- Native Ubuntu 22.04 (older version also should work)
-
MCUs:
- STM32H743ZI
- STM32L4R5ZI
- STM32F429ZI
- Microchip SAMD51
- NXP K66F
- Download llvm-14.0x pre-built and unzip to deps/llvm through
tar -xf <llvm-14>.tar.gz -C ./deps/llvm/
.
- Simply select that one fitting your situation from arm-gnu-toolchain. The version that we use is 11.3.rel1.
- Unzip it to
deps/arm
and make sure the arm.cmake under the firmware source code (firmware/STMfirmware/Common) points to it.
sudo apt install autoconf automake libtool
- python3 install with
pyserial
git submodule update --init --recursive
- cd to deps/boost
./bootstrap.sh
./b2 --with-filesystem --with-graph --with-program_options
- cd to deps/libserialport
- ./autogen.sh
- ./configure
- make
- cd to deps/z3
- mkdir build
- cmake -DCMAKE_INSTALL_PREFIX=`pwd`/install ..
- make
- make install
- cd to pass/symbolizer
- Configure the pass to fit your needs:
CO3_MCUS
: enable when instrumenting a MCU, disable when instrumenting a workstation application.CO3_REPLACE
: if this pass will replace the symbolic instructions to a or instruction. (this corresponds to theReport All
mode in the paper)
- cmake build
- Please refer to firmware building doc.
- cd to sym_backend
- Configure the orchestrator to fit your needs:
- Building Types:
- Release Build.
- Debug Build: besides less compile-time optimization, there are more sanity checks, and log prints.
- Profile Build: with google profiler.
CO3_NO_MCU_SHADOW
: consistent with the MCU-side configuration. What it does internally is diabling a few sanity checks.CO3_REPLACE
: consistent with the MCU-side configuration.CO3_SER2NET
: use TCP/UNIX socket instead of the serial port.CO3_32BIT
: enabled when talking with a MCU. disabled when talking with a 64-bit workstation application.
- Building Types:
- cmake build
- Flash the firmware to the board and connect the USB/physical serial port to the workstation.
- run
orchestrator -i <SVFG dir> -p <serial port> -b <baud rate of the serial port>
- SVFG dir is the folder automatically generated in the firmware building process.
- serial port is the USB-CDC/physical serial port (e.g., /dev/ttyACM1).
- This port also accepts number as parameters if the orchestrator is built with
SER2NET
. In this case, the serial port can be a TCP port where the SER2NET is carried through. Furthermore, if you specify0
, the orchestrator will look for UNIX socket directly located in the<SVFG dir>
. UNIX socket is used in workstation mode.
- This port also accepts number as parameters if the orchestrator is built with
- baud rate is the baud rate for the serial port. This only matters when a physical serial port is used. For any other cases, specifying different number makes no difference.
- In order to use this docker file, step in arm cross compiler are still required. llvm-prebuilt will not be necessary, as we will use the one from apt.
- You can use the docker environment to build the firmware. Everything else is prepared.
- Running CO3 requires the serial port to be exposed to the docker container.
- Docker Linux does not have issue with this.
- For MacOS, however, since it does not support serial port bypassing, running on MacOS even inside docker is difficult. SER2NET directs serial port to a TCP port, however, we ran into issue even when we expose the TCP port to docker container on MacOS. For more on running dockerized CO3 on MacOS please refer to #2.
- Due to historical reasons, the whole codebase is filled with name referecens to
SPEAR
, which is the old name forCO3
. If you seeSPEAR
, that means the same thing asCO3
. - This is a research prototype, not intended for production. In the meantime, I am open for all helpful PRs that can make CO3 better.
- If your research prototype is built on top of CO3, I encourage you to open source too.
- There is roadmap for future development, please see #1.
- Feel free to comment in that issue to share your ideas about what could be the next step. You ideas will be considered proactively.
- If you want to take on some of the tasks, feel free to let me know, I might have something done already.
@inproceedings{liu2024co3,
title={CO3: Concolic Co-execution for Firmware},
author={Liu, Changming and Mera, Alejandro and Kirda, Engin and Xu, Meng and Lu, Long},
booktitle={33rd USENIX Security Symposium (USENIX Security 24)},
year={2024}
}