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

[WIP] Fuzz test CKBProtocolHandler and ServiceProtocol #4488

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions db/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ tempfile.workspace = true
default = []
portable = ["rocksdb/portable"]
march-native = ["rocksdb/march-native"]
fuzz = []
12 changes: 12 additions & 0 deletions db/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,18 @@ impl RocksDB {
opts.create_missing_column_families(true);
opts.enable_statistics();

#[cfg(feature = "fuzz")]
{
let mut env = rocksdb::Env::mem_env().unwrap();
env.set_low_priority_background_threads(0);
env.set_high_priority_background_threads(0);
env.set_background_threads(0);
opts.set_env(&env);

opts.set_max_background_jobs(0);
opts.set_max_subcompactions(0);
}

let db = OptimisticTransactionDB::open_cf_descriptors(&opts, &config.path, cf_descriptors)
.map_err(|err| internal_error(format!("failed to open database: {err}")))?;

Expand Down
File renamed without changes.
103 changes: 103 additions & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
[package]
name = "ckb-fuzz"
version = "0.117.0-pre"
publish = false
edition = "2021"
license = "MIT"
description = "ckb network fuzz testing"
homepage = "https://github.com/nervosnetwork/ckb"
repository = "https://github.com/nervosnetwork/ckb"

[package.metadata]
cargo-fuzz = true

[features]
binary_fuzz_service_proto = []

[dependencies]
libfuzzer-sys = "0.4"
ipnetwork = "0.18"
futures = "0.3"
tokio = { version = "1", features = ["sync", "macros"] }
tokio-util = { version = "0.7", features = ["codec"] }

[dependencies.ckb-network]
path = "../network"
features = ["fuzz"]

[dependencies.ckb-chain]
path = "../chain"

[dependencies.ckb-sync]
path = "../sync"
features = ["fuzz"]

[dependencies.ckb-shared]
path = "../shared"
features = ["fuzz"]

[dependencies.ckb-chain-spec]
path = "../spec"

[dependencies.ckb-launcher]
path = "../util/launcher/"
features = ["fuzz"]

[dependencies.ckb-channel]
path = "../util/channel"

[dependencies.ckb-app-config]
path = "../util/app-config"

[dependencies.ckb-build-info]
path = "../util/build-info"

[dependencies.ckb-async-runtime]
path = "../util/runtime"

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[profile.release]
debug = 1
overflow-checks = true

[build]
rustflags = ["-C", "instrument-coverage", "-C", "sanitizer=address"]

[[bin]]
name = "fuzz_compress"
path = "fuzz_targets/fuzz_compress.rs"
test = false
doc = false

[[bin]]
name = "fuzz_decompress"
path = "fuzz_targets/fuzz_decompress.rs"
test = false
doc = false

[[bin]]
name = "fuzz_addr_manager"
path = "fuzz_targets/fuzz_addr_manager.rs"
test = false
doc = false

[[bin]]
name = "fuzz_peer_store"
path = "fuzz_targets/fuzz_peer_store.rs"
test = false
doc = false

[[bin]]
name = "fuzz_ckb_protocol_handler"
path = "fuzz_targets/fuzz_ckb_protocol_handler.rs"
test = false
doc = false

[[bin]]
name = "fuzz_service_proto"
path = "fuzz_targets/fuzz_service_proto.rs"
test = false
doc = false
145 changes: 145 additions & 0 deletions fuzz/fuzz_targets/fuzz_ckb_protocol_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#![no_main]

use libfuzzer_sys::fuzz_target;

use ckb_app_config::NetworkAlertConfig;
use ckb_fuzz::BufManager;
use ckb_network::{bytes::Bytes, SupportProtocols};
use ckb_shared::Shared;
use ckb_sync::SyncShared;
use std::sync::Arc;
use tokio::runtime::Handle;

fn get_proto_type(data: &mut BufManager) -> Result<SupportProtocols, ()> {
if data.is_end() {
return Err(());
}
let id = data.get::<u8>() % 7;

// SupportProtocols::Sync => 100,
// SupportProtocols::RelayV2 => 101,
// SupportProtocols::RelayV3 => 103,
// SupportProtocols::Time => 102,
// SupportProtocols::Alert => 110,
// SupportProtocols::LightClient => 120,
// SupportProtocols::Filter => 121,

match id {
0 => Ok(SupportProtocols::Sync),
1 => Ok(SupportProtocols::RelayV2),
2 => Ok(SupportProtocols::RelayV3),
3 => Ok(SupportProtocols::Time),
4 => Ok(SupportProtocols::Alert),
5 => Ok(SupportProtocols::LightClient),
6 => Ok(SupportProtocols::Filter),

_ => Err(()),
}
}

fn get_shared(data: &mut BufManager, handle: &Handle) -> Result<Shared, ()> {
if data.is_end() {
return Err(());
}
let builder = ckb_shared::shared_builder::SharedBuilder::new_test(
ckb_async_runtime::Handle::new(handle.clone(), None),
);
let r = builder.build();

if r.is_err() {
return Err(());
}

Ok(r.unwrap().0)
}

fn get_sync_shared(data: &mut BufManager, handle: &Handle) -> Result<SyncShared, ()> {
if data.is_end() {
return Err(());
}

let shared = get_shared(data, handle)?;

let sync_config = ckb_app_config::SyncConfig::default();
let (_, relay_tx_receiver) = ckb_channel::bounded(0);

Ok(SyncShared::new(
shared.clone(),
sync_config,
relay_tx_receiver,
))
}

fn get_version(data: &mut BufManager) -> Result<ckb_build_info::Version, ()> {
if data.is_end() {
return Err(());
}

let mut ver = ckb_build_info::Version::default();
ver.major = data.get();
ver.minor = data.get();
ver.patch = data.get();
Ok(ver)
}

fn get_network_alert_config(data: &mut BufManager) -> Result<NetworkAlertConfig, ()> {
if data.is_end() {
return Err(());
}

let cfg = NetworkAlertConfig::default();
Ok(cfg)
}

fn run(data: &[u8]) -> Result<(), ()> {
// let rt = tokio::runtime::Builder::new_current_thread()
// .build()
// .unwrap();

let rt = tokio::runtime::Builder::new_multi_thread()
.worker_threads(1)
.enable_all()
.build()
.unwrap();

let mut data = BufManager::new(data);

let t = get_proto_type(&mut data)?;

let sync_shared = match t {
SupportProtocols::Time => None,
_ => Some(Arc::new(get_sync_shared(&mut data, rt.handle())?)),
};

let (version, alert_cfg) = match t {
SupportProtocols::Alert => (
Some(get_version(&mut data)?),
Some(get_network_alert_config(&mut data)?),
),
_ => (None, None),
};

let proto = ckb_launcher::new_ckb_protocol(t, sync_shared, version, alert_cfg);
if proto.is_none() {
return Err(());
}
let mut proto = proto.unwrap();

rt.block_on(async {
let nc = Arc::new(ckb_fuzz::ckb_protocol_ctx::EmptyProtocolCtx { protocol: 0.into() });

let _r = proto.init(nc.clone()).await;
proto.connected(nc.clone(), 0.into(), "").await;
//
let bufs = data.get_bufs(0xFFFFFFFF, 15, 4000);
for buf in bufs {
proto.received(nc.clone(), 0.into(), Bytes::from(buf)).await;
}
proto.disconnected(nc, 0.into()).await;
});
Ok(())
}

fuzz_target!(|data: &[u8]| {
let _r = run(data);
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use libfuzzer_sys::fuzz_target;
use ckb_network::{
multiaddr::MultiAddr, peer_store::types::BannedAddr, peer_store::PeerStore, Flags, PeerId,
};
use ckb_network_fuzz::BufManager;
use ckb_fuzz::BufManager;

fn new_multi_addr(data: &mut BufManager) -> (MultiAddr, Flags) {
let flags = data.get();
Expand Down
Loading
Loading