mirror of
https://github.com/cloudflare/quiche.git
synced 2026-10-28 08:36:24 +08:00
fuzz: server multiple packets fuzzing
including one target doing the handshake to fuzz after it
This commit is contained in:
1 parent
f9b38dd92a
commit
828e09861d
15 files changed
+329
-1
No files matched your search
@@ -36,6 +36,8 @@ docker-publish:
|
||||
build-fuzz:
|
||||
cargo +nightly fuzz build --release --debug-assertions packet_recv_client
|
||||
cargo +nightly fuzz build --release --debug-assertions packet_recv_server
|
||||
cargo +nightly fuzz build --release --debug-assertions packets_recv_server
|
||||
cargo +nightly fuzz build --release --debug-assertions packets_posths_server
|
||||
cargo +nightly fuzz build --release --debug-assertions qpack_decode
|
||||
|
||||
# build fuzzing image
|
||||
|
||||
@@ -28,6 +28,14 @@ path = "src/packet_recv_client.rs"
|
||||
name = "packet_recv_server"
|
||||
path = "src/packet_recv_server.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "packets_recv_server"
|
||||
path = "src/packets_recv_server.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "packets_posths_server"
|
||||
path = "src/packets_posths_server.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "qpack_decode"
|
||||
path = "src/qpack_decode.rs"
|
||||
|
||||
@@ -32,5 +32,7 @@ COPY fuzz/cert.key ./
|
||||
COPY --from=fuzz \
|
||||
/build/fuzz/target/x86_64-unknown-linux-gnu/release/packet_recv_client \
|
||||
/build/fuzz/target/x86_64-unknown-linux-gnu/release/packet_recv_server \
|
||||
/build/fuzz/target/x86_64-unknown-linux-gnu/release/packets_recv_server \
|
||||
/build/fuzz/target/x86_64-unknown-linux-gnu/release/packets_posths_server \
|
||||
/build/fuzz/target/x86_64-unknown-linux-gnu/release/qpack_decode \
|
||||
./
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
+14
@@ -0,0 +1,14 @@
|
||||
project: protocols/quiche
|
||||
|
||||
target: packets-posths-server-libfuzzer
|
||||
|
||||
image: ${MAYHEM_DOCKER_REGISTRY}/protocols/quiche-libfuzzer:latest
|
||||
|
||||
advanced_triage: false
|
||||
|
||||
cmds:
|
||||
- cmd: /home/mayhem/packets_posths_server
|
||||
libfuzzer: true
|
||||
sanitizer: true
|
||||
timeout: 5
|
||||
env: {QUICHE_FUZZ_CRT: /home/mayhem/cert.crt, QUICHE_FUZZ_KEY: /home/mayhem/cert.key}
|
||||
@@ -0,0 +1 @@
|
||||
../../corpus/packets_posths_server
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
project: protocols/quiche
|
||||
|
||||
target: packets-recv-server-libfuzzer
|
||||
|
||||
image: ${MAYHEM_DOCKER_REGISTRY}/protocols/quiche-libfuzzer:latest
|
||||
|
||||
advanced_triage: false
|
||||
|
||||
cmds:
|
||||
- cmd: /home/mayhem/packets_recv_server
|
||||
libfuzzer: true
|
||||
sanitizer: true
|
||||
timeout: 5
|
||||
env: {QUICHE_FUZZ_CRT: /home/mayhem/cert.crt, QUICHE_FUZZ_KEY: /home/mayhem/cert.key}
|
||||
@@ -0,0 +1 @@
|
||||
../../corpus/packets_recv_server
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
use quiche::h3::NameValue;
|
||||
|
||||
pub struct PktsData<'a> {
|
||||
pub data: &'a [u8],
|
||||
}
|
||||
|
||||
pub struct PktIterator<'a> {
|
||||
data: &'a [u8],
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for PktIterator<'a> {
|
||||
type Item = &'a [u8];
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.index < self.data.len() {
|
||||
let start = self.index;
|
||||
if self.index + 4 <= self.data.len() {
|
||||
for i in self.index..self.data.len() - 4 {
|
||||
if &self.data[i..i + 4] == b"fuzz" {
|
||||
self.index = i + 4;
|
||||
return Some(&self.data[start..i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.index = self.data.len();
|
||||
Some(&self.data[start..])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PktsData<'a> {
|
||||
pub fn iter(&self) -> PktIterator<'_> {
|
||||
PktIterator {
|
||||
data: self.data,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn server_process(
|
||||
pkt: &[u8], conn: &mut quiche::Connection,
|
||||
h3_conn: &mut Option<quiche::h3::Connection>, info: quiche::RecvInfo,
|
||||
) {
|
||||
let mut buf = pkt.to_vec();
|
||||
conn.recv(&mut buf, info).ok();
|
||||
|
||||
if (conn.is_in_early_data() || conn.is_established()) && h3_conn.is_none() {
|
||||
let h3_config = quiche::h3::Config::new().unwrap();
|
||||
|
||||
if let Ok(c) = quiche::h3::Connection::with_transport(conn, &h3_config) {
|
||||
*h3_conn = Some(c);
|
||||
}
|
||||
}
|
||||
|
||||
if h3_conn.is_some() {
|
||||
let h3c = h3_conn.as_mut().unwrap();
|
||||
loop {
|
||||
let r = h3c.poll(conn);
|
||||
|
||||
match r {
|
||||
Ok((
|
||||
_stream_id,
|
||||
quiche::h3::Event::Headers {
|
||||
list,
|
||||
more_frames: _,
|
||||
},
|
||||
)) => {
|
||||
let mut headers = list.into_iter();
|
||||
|
||||
// Look for the request's method.
|
||||
let method = headers.find(|h| h.name() == b":method");
|
||||
if method.is_none() {
|
||||
break;
|
||||
}
|
||||
let method = method.unwrap();
|
||||
|
||||
// Look for the request's path.
|
||||
let path = headers.find(|h| h.name() == b":path");
|
||||
if path.is_none() {
|
||||
break;
|
||||
}
|
||||
let path = path.unwrap();
|
||||
|
||||
if method.value() == b"GET" && path.value() == b"/" {
|
||||
let _resp = vec![
|
||||
quiche::h3::Header::new(
|
||||
b":status",
|
||||
200.to_string().as_bytes(),
|
||||
),
|
||||
quiche::h3::Header::new(b"server", b"quiche"),
|
||||
];
|
||||
}
|
||||
},
|
||||
|
||||
Ok((_stream_id, quiche::h3::Event::Data)) => {},
|
||||
|
||||
Ok((_stream_id, quiche::h3::Event::Finished)) => {},
|
||||
|
||||
Ok((_stream_id, quiche::h3::Event::Reset(_err))) => {},
|
||||
|
||||
Ok((_flow_id, quiche::h3::Event::PriorityUpdate)) => {},
|
||||
|
||||
Ok((_goaway_id, quiche::h3::Event::GoAway)) => {
|
||||
// Peer signalled it is going away, handle it.
|
||||
},
|
||||
|
||||
Err(quiche::h3::Error::Done) => {
|
||||
// Done reading.
|
||||
break;
|
||||
},
|
||||
|
||||
Err(_e) => {
|
||||
// An error occurred, handle it.
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut out_buf = [0; 1500];
|
||||
while conn.send(&mut out_buf).is_ok() {}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate libfuzzer_sys;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use std::sync::Mutex;
|
||||
use std::sync::Once;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
static CONFIG: OnceLock<Mutex<quiche::Config>> = OnceLock::new();
|
||||
|
||||
static SCID: quiche::ConnectionId<'static> =
|
||||
quiche::ConnectionId::from_ref(&[0; quiche::MAX_CONN_ID_LEN]);
|
||||
|
||||
static LOG_INIT: Once = Once::new();
|
||||
|
||||
extern "C" {
|
||||
fn RAND_reset_for_fuzzing();
|
||||
}
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
unsafe {
|
||||
RAND_reset_for_fuzzing();
|
||||
}
|
||||
let from: SocketAddr = "127.0.0.1:1234".parse().unwrap();
|
||||
let to: SocketAddr = "127.0.0.1:4321".parse().unwrap();
|
||||
|
||||
LOG_INIT.call_once(|| env_logger::builder().format_timestamp_nanos().init());
|
||||
|
||||
let packets = quiche_fuzz::PktsData { data };
|
||||
|
||||
let config = CONFIG.get_or_init(|| {
|
||||
let crt_path = std::env::var("QUICHE_FUZZ_CRT")
|
||||
.unwrap_or_else(|_| "fuzz/cert.crt".to_string());
|
||||
let key_path = std::env::var("QUICHE_FUZZ_KEY")
|
||||
.unwrap_or_else(|_| "fuzz/cert.key".to_string());
|
||||
|
||||
let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
|
||||
config.load_cert_chain_from_pem_file(&crt_path).unwrap();
|
||||
config.load_priv_key_from_pem_file(&key_path).unwrap();
|
||||
config
|
||||
.set_application_protos(quiche::h3::APPLICATION_PROTOCOL)
|
||||
.unwrap();
|
||||
config.set_initial_max_data(30);
|
||||
config.set_initial_max_stream_data_bidi_local(15);
|
||||
config.set_initial_max_stream_data_bidi_remote(15);
|
||||
config.set_initial_max_stream_data_uni(10);
|
||||
config.set_initial_max_streams_bidi(3);
|
||||
config.set_initial_max_streams_uni(3);
|
||||
|
||||
config.discover_pmtu(true);
|
||||
config.enable_early_data();
|
||||
config.enable_hystart(true);
|
||||
|
||||
Mutex::new(config)
|
||||
});
|
||||
|
||||
let mut conn =
|
||||
quiche::accept(&SCID, None, to, from, &mut config.lock().unwrap())
|
||||
.unwrap();
|
||||
|
||||
let mut connc = quiche::connect(
|
||||
Some("quic.tech"),
|
||||
&SCID,
|
||||
from,
|
||||
to,
|
||||
&mut config.lock().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let info = quiche::RecvInfo { from, to };
|
||||
|
||||
while !conn.is_established() || !connc.is_established() {
|
||||
let flight = quiche::test_utils::emit_flight(&mut connc).unwrap();
|
||||
quiche::test_utils::process_flight(&mut conn, flight).unwrap();
|
||||
|
||||
let flight = quiche::test_utils::emit_flight(&mut conn).unwrap();
|
||||
quiche::test_utils::process_flight(&mut connc, flight).unwrap();
|
||||
}
|
||||
|
||||
let mut h3_conn = None;
|
||||
for pkt in packets.iter() {
|
||||
quiche_fuzz::server_process(pkt, &mut conn, &mut h3_conn, info);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,70 @@
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate libfuzzer_sys;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use std::sync::Mutex;
|
||||
use std::sync::Once;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
static CONFIG: OnceLock<Mutex<quiche::Config>> = OnceLock::new();
|
||||
|
||||
static SCID: quiche::ConnectionId<'static> =
|
||||
quiche::ConnectionId::from_ref(&[0; quiche::MAX_CONN_ID_LEN]);
|
||||
|
||||
static LOG_INIT: Once = Once::new();
|
||||
|
||||
extern "C" {
|
||||
fn RAND_reset_for_fuzzing();
|
||||
}
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
unsafe {
|
||||
RAND_reset_for_fuzzing();
|
||||
}
|
||||
let from: SocketAddr = "127.0.0.1:1234".parse().unwrap();
|
||||
let to: SocketAddr = "127.0.0.1:4321".parse().unwrap();
|
||||
|
||||
LOG_INIT.call_once(|| env_logger::builder().format_timestamp_nanos().init());
|
||||
|
||||
let packets = quiche_fuzz::PktsData { data };
|
||||
|
||||
let config = CONFIG.get_or_init(|| {
|
||||
let crt_path = std::env::var("QUICHE_FUZZ_CRT")
|
||||
.unwrap_or_else(|_| "fuzz/cert.crt".to_string());
|
||||
let key_path = std::env::var("QUICHE_FUZZ_KEY")
|
||||
.unwrap_or_else(|_| "fuzz/cert.key".to_string());
|
||||
|
||||
let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
|
||||
config.load_cert_chain_from_pem_file(&crt_path).unwrap();
|
||||
config.load_priv_key_from_pem_file(&key_path).unwrap();
|
||||
config
|
||||
.set_application_protos(quiche::h3::APPLICATION_PROTOCOL)
|
||||
.unwrap();
|
||||
config.set_initial_max_data(30);
|
||||
config.set_initial_max_stream_data_bidi_local(15);
|
||||
config.set_initial_max_stream_data_bidi_remote(15);
|
||||
config.set_initial_max_stream_data_uni(10);
|
||||
config.set_initial_max_streams_bidi(3);
|
||||
config.set_initial_max_streams_uni(3);
|
||||
|
||||
config.discover_pmtu(true);
|
||||
config.enable_early_data();
|
||||
config.enable_hystart(true);
|
||||
|
||||
Mutex::new(config)
|
||||
});
|
||||
|
||||
let mut conn =
|
||||
quiche::accept(&SCID, None, to, from, &mut config.lock().unwrap())
|
||||
.unwrap();
|
||||
|
||||
let info = quiche::RecvInfo { from, to };
|
||||
|
||||
let mut h3_conn = None;
|
||||
for pkt in packets.iter() {
|
||||
quiche_fuzz::server_process(pkt, &mut conn, &mut h3_conn, info);
|
||||
}
|
||||
});
|
||||
@@ -28,9 +28,13 @@ RUST_LOG=trace target/debug/quiche-client --no-verify https://127.0.0.1:4433 --d
|
||||
# Combine client-received packets into client's seed.
|
||||
cat $CLIENT_DIR/*.pkt > fuzz/corpus/packet_recv_client/seed
|
||||
|
||||
# Combine server-received packets into client's seed.
|
||||
# Combine server-received packets into server's seed.
|
||||
cat $SERVER_DIR/*.pkt > fuzz/corpus/packet_recv_server/seed
|
||||
|
||||
# Combine server-received packets with "fuzz" delimit into server's seed for multiple packets.
|
||||
ls $SERVER_DIR/*.pkt | while read i; do cat $i; echo -n fuzz; done > fuzz/corpus/packets_recv_server/seed
|
||||
|
||||
# Minimize fuzz corpora.
|
||||
cargo +nightly fuzz cmin -Oa packet_recv_client
|
||||
cargo +nightly fuzz cmin -Oa packet_recv_server
|
||||
cargo +nightly fuzz cmin -Oa packets_recv_server
|
||||
Reference in new issue
Block a user