Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve fuzzer coverage #426

Merged
merged 1 commit into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions crates/chia-consensus/fuzz/fuzz_targets/parse-cond-args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,29 @@ use libfuzzer_sys::fuzz_target;

use chia_consensus::gen::conditions::parse_args;
use clvmr::allocator::Allocator;
use fuzzing_utils::{make_tree, BitCursor};
use fuzzing_utils::{make_list, BitCursor};

use chia_consensus::gen::flags::{COND_ARGS_NIL, STRICT_ARGS_COUNT};
use chia_consensus::gen::flags::{COND_ARGS_NIL, ENABLE_SOFTFORK_CONDITION, STRICT_ARGS_COUNT};

use chia_consensus::gen::opcodes::{
AGG_SIG_ME, AGG_SIG_UNSAFE, ASSERT_COIN_ANNOUNCEMENT, ASSERT_HEIGHT_ABSOLUTE,
ASSERT_HEIGHT_RELATIVE, ASSERT_MY_AMOUNT, ASSERT_MY_COIN_ID, ASSERT_MY_PARENT_ID,
ASSERT_MY_PUZZLEHASH, ASSERT_PUZZLE_ANNOUNCEMENT, ASSERT_SECONDS_ABSOLUTE,
ASSERT_SECONDS_RELATIVE, CREATE_COIN, CREATE_COIN_ANNOUNCEMENT, CREATE_PUZZLE_ANNOUNCEMENT,
REMARK, RESERVE_FEE,
AGG_SIG_AMOUNT, AGG_SIG_ME, AGG_SIG_PARENT, AGG_SIG_PARENT_AMOUNT, AGG_SIG_PARENT_PUZZLE,
AGG_SIG_PUZZLE, AGG_SIG_PUZZLE_AMOUNT, AGG_SIG_UNSAFE, ASSERT_COIN_ANNOUNCEMENT,
ASSERT_EPHEMERAL, ASSERT_HEIGHT_ABSOLUTE, ASSERT_HEIGHT_RELATIVE, ASSERT_MY_AMOUNT,
ASSERT_MY_COIN_ID, ASSERT_MY_PARENT_ID, ASSERT_MY_PUZZLEHASH, ASSERT_PUZZLE_ANNOUNCEMENT,
ASSERT_SECONDS_ABSOLUTE, ASSERT_SECONDS_RELATIVE, CREATE_COIN, CREATE_COIN_ANNOUNCEMENT,
CREATE_PUZZLE_ANNOUNCEMENT, REMARK, RESERVE_FEE,
};

fuzz_target!(|data: &[u8]| {
let mut a = Allocator::new();
let input = make_tree(&mut a, &mut BitCursor::new(data), false);
for flags in &[0, COND_ARGS_NIL, STRICT_ARGS_COUNT] {
let input = make_list(&mut a, &mut BitCursor::new(data));

for flags in &[
0,
COND_ARGS_NIL,
STRICT_ARGS_COUNT,
ENABLE_SOFTFORK_CONDITION,
] {
for op in &[
AGG_SIG_ME,
AGG_SIG_UNSAFE,
Expand All @@ -37,6 +44,13 @@ fuzz_target!(|data: &[u8]| {
CREATE_COIN_ANNOUNCEMENT,
CREATE_PUZZLE_ANNOUNCEMENT,
RESERVE_FEE,
ASSERT_EPHEMERAL,
AGG_SIG_PARENT,
AGG_SIG_PUZZLE,
AGG_SIG_AMOUNT,
AGG_SIG_PUZZLE_AMOUNT,
AGG_SIG_PARENT_AMOUNT,
AGG_SIG_PARENT_PUZZLE,
] {
let _ret = parse_args(&a, input, *op, *flags);
}
Expand Down
14 changes: 9 additions & 5 deletions crates/chia-consensus/fuzz/fuzz_targets/parse-conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use chia_consensus::gen::spend_visitor::SpendVisitor;
use chia_protocol::Bytes32;
use chia_protocol::Coin;
use clvm_utils::tree_hash;
use clvmr::allocator::Allocator;
use fuzzing_utils::{make_tree, BitCursor};
use clvmr::{Allocator, NodePtr};
use fuzzing_utils::{make_list, BitCursor};
use std::collections::HashSet;
use std::sync::Arc;

Expand All @@ -19,7 +19,9 @@ use chia_consensus::gen::flags::{

fuzz_target!(|data: &[u8]| {
let mut a = Allocator::new();
let input = make_tree(&mut a, &mut BitCursor::new(data), false);
let input = make_list(&mut a, &mut BitCursor::new(data));
// conditions are a list of lists
let input = a.new_pair(input, NodePtr::NIL).unwrap();

let mut ret = SpendBundleConditions::default();

Expand All @@ -35,6 +37,8 @@ fuzz_target!(|data: &[u8]| {
.coin_id()
.into(),
);
let parent_id = a.new_atom(&parent_id).expect("atom failed");
let puzzle_hash = a.new_atom(&puzzle_hash).expect("atom failed");

let mut state = ParseState::default();

Expand All @@ -46,9 +50,9 @@ fuzz_target!(|data: &[u8]| {
ENABLE_SOFTFORK_CONDITION,
] {
let mut coin_spend = Spend {
parent_id: a.new_atom(&parent_id).expect("atom failed"),
parent_id,
coin_amount: amount,
puzzle_hash: a.new_atom(&puzzle_hash).expect("atom failed"),
puzzle_hash,
coin_id: coin_id.clone(),
height_relative: None,
seconds_relative: None,
Expand Down
4 changes: 2 additions & 2 deletions crates/chia-consensus/fuzz/fuzz_targets/parse-spend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use libfuzzer_sys::fuzz_target;

use chia_consensus::gen::get_puzzle_and_solution::parse_coin_spend;
use clvmr::allocator::Allocator;
use fuzzing_utils::{make_tree, BitCursor};
use fuzzing_utils::{make_list, BitCursor};

fuzz_target!(|data: &[u8]| {
let mut a = Allocator::new();
let input = make_tree(&mut a, &mut BitCursor::new(data), false);
let input = make_list(&mut a, &mut BitCursor::new(data));

let _ret = parse_coin_spend(&a, input);
});
20 changes: 15 additions & 5 deletions crates/chia-consensus/fuzz/fuzz_targets/parse-spends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,25 @@
use libfuzzer_sys::fuzz_target;

use chia_consensus::gen::conditions::{parse_spends, MempoolVisitor};
use clvmr::allocator::Allocator;
use fuzzing_utils::{make_tree, BitCursor};
use clvmr::{Allocator, NodePtr};
use fuzzing_utils::{make_list, BitCursor};

use chia_consensus::gen::flags::{COND_ARGS_NIL, NO_UNKNOWN_CONDS, STRICT_ARGS_COUNT};
use chia_consensus::gen::flags::{
COND_ARGS_NIL, ENABLE_SOFTFORK_CONDITION, NO_UNKNOWN_CONDS, STRICT_ARGS_COUNT,
};

fuzz_target!(|data: &[u8]| {
let mut a = Allocator::new();
let input = make_tree(&mut a, &mut BitCursor::new(data), false);
for flags in &[0, COND_ARGS_NIL, STRICT_ARGS_COUNT, NO_UNKNOWN_CONDS] {
let input = make_list(&mut a, &mut BitCursor::new(data));
// spends is a list of spends
let input = a.new_pair(input, NodePtr::NIL).unwrap();
for flags in &[
0,
COND_ARGS_NIL,
STRICT_ARGS_COUNT,
NO_UNKNOWN_CONDS,
ENABLE_SOFTFORK_CONDITION,
] {
let _ret = parse_spends::<MempoolVisitor>(&a, input, 33000000000, *flags);
}
});
48 changes: 46 additions & 2 deletions crates/chia-consensus/fuzz/src/fuzzing_utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use clvmr::allocator::Allocator;
use clvmr::allocator::NodePtr;

// TODO: use the arbitrary crate instead
pub struct BitCursor<'a> {
data: &'a [u8],
bit_offset: u8,
Expand Down Expand Up @@ -50,8 +51,9 @@ impl<'a> BitCursor<'a> {
}

const BUFFER: [u8; 63] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0xff, 0x80, 0, 1, 0x55, 0, 0x55, 0, 0x80, 0, 0xff, 0, 2, 0, 0xcc, 0, 0, 0, 0x7f, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x77,
0xee, 0, 0xcc, 0x0f, 0xff, 0x80, 0x7e, 1,
];

enum MakeTreeOp {
Expand Down Expand Up @@ -98,3 +100,45 @@ pub fn make_tree(a: &mut Allocator, cursor: &mut BitCursor, short_atoms: bool) -
assert!(value_stack.len() == 1);
value_stack.pop().unwrap()
}

pub fn make_list(a: &mut Allocator, cursor: &mut BitCursor) -> NodePtr {
let mut ret = NodePtr::NIL;

let mut length = cursor.read_bits(5).unwrap_or(0);
let mut nil_terminated = cursor.read_bits(3).unwrap_or(0) != 0;

while length > 0 {
let atom_kind = cursor.read_bits(3).unwrap_or(0);
let value = match atom_kind {
0 => a
.new_number(cursor.read_bits(7).unwrap_or(0).into())
.unwrap(),
1..=3 => {
let offset = cursor.read_bits(3).unwrap_or(0);
a.new_atom(&BUFFER[offset as usize..(offset + 32) as usize])
.unwrap()
}
4 | 5 => {
let mut num: i64 = ((cursor.read_bits(8).unwrap_or(0) as i64) << 8)
| (cursor.read_bits(8).unwrap_or(0) as i64);
if atom_kind == 4 {
num = -num;
}
a.new_number(num.into()).unwrap()
}
6 => a.new_pair(NodePtr::NIL, NodePtr::NIL).unwrap(),
_ => {
let len = cursor.read_bits(6).unwrap_or(0);
a.new_atom(&BUFFER[..len as usize]).unwrap()
}
};
if !nil_terminated {
ret = value;
nil_terminated = true;
} else {
ret = a.new_pair(value, ret).unwrap();
}
length -= 1;
}
ret
}
Loading