Skip to content

Commit

Permalink
Cairo fuzzer (lambdaclass#1227)
Browse files Browse the repository at this point in the history
* Create fuzzer

* Remove cli

* Update fuzzer

* Change fuzzer name

* Update Cargo.toml

* Update Cargo.toml

* Add fuzzer workflow (lambdaclass#1240)

* add workflow to run fuzzers

* delete extra changes

* add pulling inputs folder from outside repo

* fix paths

* change test workflow to use cache and store the report

* actualice workflow

* Update fuzzer.yml

* delete extra files

* Delete Cargo.toml

* Delete main.rs

---------

Co-authored-by: dafifynn <[email protected]>

* Update Cargo.toml

---------

Co-authored-by: Juanma <[email protected]>
Co-authored-by: daphneherlambda <[email protected]>
Co-authored-by: dafifynn <[email protected]>
  • Loading branch information
4 people authored and kariy committed Jul 25, 2023
1 parent d2d241b commit 83fa85d
Show file tree
Hide file tree
Showing 5 changed files with 316 additions and 0 deletions.
57 changes: 57 additions & 0 deletions .github/workflows/fuzzer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: "Fuzzer Workflow"
on:
schedule:
# At the end of every day
- cron: "0 0 * * *"
jobs:
changelog:
runs-on: ubuntu-latest
steps:

- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ github.head_ref }}


- name: Cache Inputs
id: cache-inputs
uses: actions/cache@v3
with:
# Path where the inputs for the fuzzer are stored
path: fuzzer/hfuzz_workspace/fuzz_json/input
key: ${{ runner.os }}-inputs


- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential
sudo apt-get install binutils-dev
sudo apt-get install libunwind-dev
sudo curl https://sh.rustup.rs -sSf | bash -s -- -y --default-toolchain nightly
- name: Set Environment Variable
run: echo "PATH="/root/.cargo/bin:${PATH}"" >> $GITHUB_ENV

- name: Install Honggfuzz
run: cargo install honggfuzz

- if: ${{ steps.cache-inputs.outputs.cache-hit != 'true' }}
# If didn´t have any inputs starts from 0
name: Initializing fuzzer from 0
run: |
cd fuzzer
HFUZZ_RUN_ARGS="--dict=json.dict --run_time 10800 --timeout 60 -T" cargo hfuzz run fuzz_json
# If has cached inputs starts with them and run with minimize
- if: ${{ steps.cache-inputs.outputs.cache-hit != 'false' }}
name: Initializing fuzzer with previous inputs
run: |
cd fuzzer
HFUZZ_RUN_ARGS="--dict=json.dict --run_time 10800 --minimize --timeout 60 -T" cargo hfuzz run fuzz_json
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: changing report
file_pattern: '*/hfuzz_workspace/fuzzer/fuzz_json/HONGGFUZZ* */hfuzz_workspace/fuzzer/fuzz_json/SIG*'
30 changes: 30 additions & 0 deletions fuzzer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "fuzzer"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
arbitrary = { version = "1.3.0", features = ["derive"] }
honggfuzz = "0.5.55"
bincode = { version = "2.0.0-rc.2", tag = "v2.0.0-rc.2", git = "https://github.com/bincode-org/bincode.git" }
cairo-vm = { path = "../vm" }
mimalloc = { version = "0.1.29", default-features = false, optional = true }
nom = "7"
thiserror = { version = "1.0.32" }

[dev-dependencies]
assert_matches = "1.5.0"
rstest = "0.17.0"

[workspace]
members = ["."]

[features]
default = ["with_mimalloc"]
with_mimalloc = ["cairo-vm/with_mimalloc", "mimalloc"]

[[bin]]
name = "fuzz_json"
path = "src/fuzz_json.rs"
3 changes: 3 additions & 0 deletions fuzzer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## fuzz_json
This fuzzer creates a json file directly from bytes.
`HFUZZ_RUN_ARGS="--dict=json.dict" cargo hfuzz run fuzz_json`
61 changes: 61 additions & 0 deletions fuzzer/json.dict
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#
# AFL dictionary for JSON
# -----------------------
#
# Just the very basics.
#
# Inspired by a dictionary by Jakub Wilk <[email protected]>
#

"0"
",0"
":0"
"0:"
"-1.2e+3"

"true"
"false"
"null"

"\"\""
",\"\""
":\"\""
"\"\":"

"{}"
",{}"
":{}"
"{\"\":0}"
"{{}}"

"[]"
",[]"
":[]"
"[0]"
"[[]]"

"''"
"\\"
"\\b"
"\\f"
"\\n"
"\\r"
"\\t"
"\\u0000"
"\\x00"
"\\0"
"\\uD800\\uDC00"
"\\uDBFF\\uDFFF"

"\"\":0"
"//"
"/**/"

"$ref"
"type"
"coordinates"
"@context"
"@id"

","
":"
165 changes: 165 additions & 0 deletions fuzzer/src/fuzz_json.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
use arbitrary::Arbitrary;
use bincode::enc::write::Writer;
use cairo_vm::cairo_run::{self, EncodeTraceError};
use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor;
use cairo_vm::vm::errors::cairo_run_errors::CairoRunError;
use cairo_vm::vm::errors::trace_errors::TraceError;
use cairo_vm::vm::errors::vm_errors::VirtualMachineError;
use honggfuzz::fuzz;
use std::fmt;
use std::io::{self, Write};
use std::path::PathBuf;
use thiserror::Error;

#[cfg(feature = "with_mimalloc")]
use mimalloc::MiMalloc;

#[cfg(feature = "with_mimalloc")]
#[global_allocator]
static ALLOC: MiMalloc = MiMalloc;

#[derive(Debug, Arbitrary)]
struct Args {
program_content: Vec<u8>,
trace_file: Option<PathBuf>,
print_output: bool,
entrypoint: String,
memory_file: Option<PathBuf>,
layout: Layout,
proof_mode: bool,
secure_run: Option<bool>,
}

#[derive(Debug, Arbitrary)]
enum Layout {
Plain,
Small,
Dex,
Starknet,
StarknetWithKeccak,
RecursiveLargeOutput,
AllCairo,
AllSolidity,
Dynamic,
}

impl fmt::Display for Layout {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Layout::Plain => write!(f, "plain"),
Layout::Small => write!(f, "small"),
Layout::Dex => write!(f, "dex"),
Layout::Starknet => write!(f, "starknet"),
Layout::StarknetWithKeccak => write!(f, "starknet_with_keccak"),
Layout::RecursiveLargeOutput => write!(f, "recursive_large_output"),
Layout::AllCairo => write!(f, "all_cairo"),
Layout::AllSolidity => write!(f, "all_solidity"),
Layout::Dynamic => write!(f, "dynamic"),
}
}
}

#[derive(Debug, Error)]
enum Error {
#[error("Failed to interact with the file system")]
IO(#[from] std::io::Error),
#[error("The cairo program execution failed")]
Runner(#[from] CairoRunError),
#[error(transparent)]
EncodeTrace(#[from] EncodeTraceError),
#[error(transparent)]
VirtualMachine(#[from] VirtualMachineError),
#[error(transparent)]
Trace(#[from] TraceError),
}

struct FileWriter {
buf_writer: io::BufWriter<std::fs::File>,
bytes_written: usize,
}

impl Writer for FileWriter {
fn write(&mut self, bytes: &[u8]) -> Result<(), bincode::error::EncodeError> {
self.buf_writer
.write_all(bytes)
.map_err(|e| bincode::error::EncodeError::Io {
inner: e,
index: self.bytes_written,
})?;

self.bytes_written += bytes.len();

Ok(())
}
}

impl FileWriter {
fn new(buf_writer: io::BufWriter<std::fs::File>) -> Self {
Self {
buf_writer,
bytes_written: 0,
}
}

fn flush(&mut self) -> io::Result<()> {
self.buf_writer.flush()
}
}

fn run(args: Args) -> Result<(), Error> {
let trace_enabled = args.trace_file.is_some();
let mut hint_executor = BuiltinHintProcessor::new_empty();
let cairo_run_config = cairo_run::CairoRunConfig {
entrypoint: &args.entrypoint,
trace_enabled,
relocate_mem: args.memory_file.is_some(),
layout: &args.layout.to_string(),
proof_mode: args.proof_mode,
secure_run: args.secure_run,
};

let (cairo_runner, mut vm) =
match cairo_run::cairo_run(&args.program_content, &cairo_run_config, &mut hint_executor) {
Ok(runner) => runner,
Err(error) => {
eprintln!("{error}");
return Err(Error::Runner(error));
}
};

if args.print_output {
let mut output_buffer = "Program Output:\n".to_string();
vm.write_output(&mut output_buffer)?;
print!("{output_buffer}");
}

if let Some(trace_path) = args.trace_file {
let relocated_trace = vm.get_relocated_trace()?;

let trace_file = std::fs::File::create(trace_path)?;
let mut trace_writer =
FileWriter::new(io::BufWriter::with_capacity(3 * 1024 * 1024, trace_file));

cairo_run::write_encoded_trace(relocated_trace, &mut trace_writer)?;
trace_writer.flush()?;
}

if let Some(memory_path) = args.memory_file {
let memory_file = std::fs::File::create(memory_path)?;
let mut memory_writer =
FileWriter::new(io::BufWriter::with_capacity(5 * 1024 * 1024, memory_file));

cairo_run::write_encoded_memory(&cairo_runner.relocated_memory, &mut memory_writer)?;
memory_writer.flush()?;
}

Ok(())
}

fn main() {
loop {
fuzz!(|args: Args| {
let _ = run(args);
});
}
}

0 comments on commit 83fa85d

Please sign in to comment.