From acdb4a537b515f8397f30f77b69a038874660df6 Mon Sep 17 00:00:00 2001 From: davkor Date: Fri, 16 Apr 2021 15:35:10 +0100 Subject: [PATCH 1/4] app: inbound: fuzzer: generalise fuzzer to send more packets. Signed-off-by: davkor --- linkerd/app/inbound/Cargo.toml | 2 + .../fuzz/fuzz_targets/fuzz_target_1.rs | 28 ++-------- linkerd/app/inbound/src/http/mod.rs | 55 +++++++++++-------- 3 files changed, 40 insertions(+), 45 deletions(-) diff --git a/linkerd/app/inbound/Cargo.toml b/linkerd/app/inbound/Cargo.toml index cbf85e72bc..2b14683ba7 100644 --- a/linkerd/app/inbound/Cargo.toml +++ b/linkerd/app/inbound/Cargo.toml @@ -21,6 +21,8 @@ tracing = "0.1.23" [target.'cfg(fuzzing)'.dependencies] hyper = { version = "0.14.2", features = ["http1", "http2"] } linkerd-app-test = { path = "../test" } +arbitrary = { version = "1", features = ["derive"] } +libfuzzer-sys = { version = "0.4.0", features = ["arbitrary-derive"] } [dependencies.tower] version = "0.4" diff --git a/linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs b/linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs index eda0fe81ab..ab9f23c00e 100644 --- a/linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs +++ b/linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs @@ -1,27 +1,11 @@ #![no_main] -use libfuzzer_sys::arbitrary::Arbitrary; use libfuzzer_sys::fuzz_target; -#[derive(Debug, Arbitrary)] -struct TransportHeaderSpec { - uri: Vec, - header_name: Vec, - header_value: Vec, - http_method: bool, -} - -fuzz_target!(|inp: TransportHeaderSpec| { - if let Ok(uri) = std::str::from_utf8(&inp.uri[..]) { - if let Ok(header_name) = std::str::from_utf8(&inp.header_name[..]) { - if let Ok(header_value) = std::str::from_utf8(&inp.header_value[..]) { - let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(linkerd_app_inbound::http::fuzz_logic::fuzz_entry_raw( - uri, - header_name, - header_value, - inp.http_method, - )); - } - } +fuzz_target!(|packets: Vec| { + if packets.len() == 0 { + return; } + + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(linkerd_app_inbound::http::fuzz_logic::fuzz_entry_raw(packets)); }); diff --git a/linkerd/app/inbound/src/http/mod.rs b/linkerd/app/inbound/src/http/mod.rs index 61995c56c4..8012d4d166 100644 --- a/linkerd/app/inbound/src/http/mod.rs +++ b/linkerd/app/inbound/src/http/mod.rs @@ -259,6 +259,7 @@ pub mod fuzz_logic { }; use hyper::http; use hyper::{client::conn::Builder as ClientBuilder, Body, Request, Response}; + use libfuzzer_sys::arbitrary::Arbitrary; use linkerd_app_core::{ io::{self, BoxedIo}, proxy, @@ -270,7 +271,15 @@ pub mod fuzz_logic { pub use linkerd_app_test as support; use linkerd_app_test::*; - pub async fn fuzz_entry_raw(uri: &str, header_name: &str, header_value: &str, is_get: bool) { + #[derive(Debug, Arbitrary)] + pub struct TransportHeaderSpec { + pub uri: Vec, + pub header_name: Vec, + pub header_value: Vec, + pub http_method: bool, + } + + pub async fn fuzz_entry_raw(packets: Vec) { let mut server = hyper::server::conn::Http::new(); server.http1_only(true); let mut client = ClientBuilder::new(); @@ -295,29 +304,29 @@ pub mod fuzz_logic { let server = build_fuzz_server(cfg, rt, profiles, connect).new_service(accept); let (mut client, bg) = http_util::connect_and_accept(&mut client, server).await; - let http_method = if is_get { - http::Method::GET - } else { - http::Method::POST - }; - - if let Ok(req) = Request::builder() - .method(http_method) - .uri(uri) - .header(header_name, header_value) - .body(Body::default()) - { - let rsp = http_util::http_request(&mut client, req).await; - let _body = http_util::body_to_string(rsp.into_body()).await; + // Now send all of the packets + for inp in packets.iter() { + if let Ok(uri) = std::str::from_utf8(&inp.uri[..]) { + if let Ok(header_name) = std::str::from_utf8(&inp.header_name[..]) { + if let Ok(header_value) = std::str::from_utf8(&inp.header_value[..]) { + let http_method = if inp.http_method { + http::Method::GET + } else { + http::Method::POST + }; - // Let's send one with a correct URL - let req2 = Request::builder() - .method(http::Method::GET) - .uri("http://foo.svc.cluster.local:5550") - .body(Body::default()) - .unwrap(); - let rsp2 = http_util::http_request(&mut client, req2).await; - let _body = http_util::body_to_string(rsp2.into_body()).await; + if let Ok(req) = Request::builder() + .method(http_method) + .uri(uri) + .header(header_name, header_value) + .body(Body::default()) + { + let rsp = http_util::http_request(&mut client, req).await; + let _body = http_util::body_to_string(rsp.into_body()).await; + } + } + } + } } drop(client); From b1d27609774fcb96f0ae1748c874efb2bdcb7c09 Mon Sep 17 00:00:00 2001 From: davkor Date: Tue, 20 Apr 2021 11:12:25 +0100 Subject: [PATCH 2/4] transport-header: fuzzer: fix coverage for structure-aware fuzzer Signed-off-by: davkor --- linkerd/transport-header/Cargo.toml | 4 ++ .../fuzz_targets/fuzz_target_structured.rs | 23 +++------- linkerd/transport-header/src/lib.rs | 44 ++++++++++++------- 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/linkerd/transport-header/Cargo.toml b/linkerd/transport-header/Cargo.toml index de5d3b64cd..72edff7be7 100644 --- a/linkerd/transport-header/Cargo.toml +++ b/linkerd/transport-header/Cargo.toml @@ -21,6 +21,10 @@ tracing = "0.1.23" [build-dependencies] prost-build = { version = "0.7", default-features = false } +[target.'cfg(fuzzing)'.dependencies] +arbitrary = { version = "1", features = ["derive"] } +libfuzzer-sys = { version = "0.4.0", features = ["arbitrary-derive"] } + [dev-dependencies] tokio = { version = "1", features = ["macros"] } tokio-test = "0.4" diff --git a/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_structured.rs b/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_structured.rs index 4469f78978..5954b69d76 100644 --- a/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_structured.rs +++ b/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_structured.rs @@ -1,22 +1,11 @@ #![no_main] use libfuzzer_sys::fuzz_target; -use libfuzzer_sys::arbitrary::Arbitrary; -#[derive(Debug, Arbitrary)] -struct TransportHeaderSpec { - data: Vec, - port: u16, - protocol: bool, -} - -fuzz_target!(|inp: TransportHeaderSpec| { - if let Ok(s) = std::str::from_utf8(&inp.data[..]) { +fuzz_target!( + |inp: linkerd_transport_header::fuzz_logic::TransportHeaderSpec| { let rt = tokio::runtime::Runtime::new().unwrap(); - let proto = if inp.protocol { - linkerd_transport_header::SessionProtocol::Http2 - } else { - linkerd_transport_header::SessionProtocol::Http1 - }; - rt.block_on(linkerd_transport_header::fuzz_logic::fuzz_entry_structured(s, inp.port, proto)); + rt.block_on(linkerd_transport_header::fuzz_logic::fuzz_entry_structured( + inp, + )); } -}); +); diff --git a/linkerd/transport-header/src/lib.rs b/linkerd/transport-header/src/lib.rs index 88c73898b1..fc4e79a400 100644 --- a/linkerd/transport-header/src/lib.rs +++ b/linkerd/transport-header/src/lib.rs @@ -273,23 +273,35 @@ mod tests { #[cfg(fuzzing)] pub mod fuzz_logic { use super::*; - pub async fn fuzz_entry_structured( - fuzz_name: &str, - fuzz_port: u16, - fuzz_proto: SessionProtocol, - ) { - let header = TransportHeader { - port: fuzz_port, - name: Name::from_str(fuzz_name).ok(), - protocol: Some(fuzz_proto), - }; - let mut rx = { + use libfuzzer_sys::arbitrary::Arbitrary; + + #[derive(Debug, Arbitrary)] + pub struct TransportHeaderSpec { + data: Vec, + port: u16, + protocol: bool, + } + + pub async fn fuzz_entry_structured(transport_header: TransportHeaderSpec) { + if let Ok(fuzz_name) = std::str::from_utf8(&transport_header.data[..]) { + let fuzz_proto = if transport_header.protocol { + SessionProtocol::Http2 + } else { + SessionProtocol::Http1 + }; + let header = TransportHeader { + port: transport_header.port, + name: Name::from_str(fuzz_name).ok(), + protocol: Some(fuzz_proto), + }; + let mut rx = { + let mut buf = BytesMut::new(); + header.encode_prefaced(&mut buf).expect("must encode"); + std::io::Cursor::new(buf.freeze()) + }; let mut buf = BytesMut::new(); - header.encode_prefaced(&mut buf).expect("must encode"); - std::io::Cursor::new(buf.freeze()) - }; - let mut buf = BytesMut::new(); - let _h = TransportHeader::read_prefaced(&mut rx, &mut buf).await; + let _h = TransportHeader::read_prefaced(&mut rx, &mut buf).await; + } } pub async fn fuzz_entry_raw(fuzz_data: &[u8]) { From 7ff89f85036e2362fb0ebd38f97db9b2aa989897 Mon Sep 17 00:00:00 2001 From: Oliver Gould Date: Tue, 20 Apr 2021 15:21:50 +0000 Subject: [PATCH 3/4] Update lockfile --- Cargo.lock | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 567fe7fd10..9843dc94d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,6 +36,15 @@ version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" +[[package]] +name = "arbitrary" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "698b65a961a9d730fb45b6b0327e20207810c9f61ee421b082b27ba003f49e2b" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "async-stream" version = "0.3.0" @@ -163,6 +172,17 @@ dependencies = [ "gzip-header", ] +[[package]] +name = "derive_arbitrary" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df89dd0d075dea5cc5fdd6d5df6b8a61172a710b3efac1d6bdb9dd8b78f82c1a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dyn-clone" version = "1.0.4" @@ -570,6 +590,16 @@ version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" +[[package]] +name = "libfuzzer-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86c975d637bc2a2f99440932b731491fc34c7f785d239e38af3addd3c2fd0e46" +dependencies = [ + "arbitrary", + "cc", +] + [[package]] name = "libmimalloc-sys" version = "0.1.20" @@ -700,11 +730,13 @@ dependencies = [ name = "linkerd-app-inbound" version = "0.1.0" dependencies = [ + "arbitrary", "bytes", "futures", "http", "hyper", "indexmap", + "libfuzzer-sys", "linkerd-app-core", "linkerd-app-test", "linkerd-io", @@ -1384,9 +1416,11 @@ dependencies = [ name = "linkerd-transport-header" version = "0.1.0" dependencies = [ + "arbitrary", "async-trait", "bytes", "futures", + "libfuzzer-sys", "linkerd-dns-name", "linkerd-error", "linkerd-io", From 2abf6e2a067246fd9eefddfa7cb2a4de88d9404f Mon Sep 17 00:00:00 2001 From: davkor Date: Tue, 20 Apr 2021 20:49:33 +0100 Subject: [PATCH 4/4] fuzzers: cleanup the style. Signed-off-by: davkor --- linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs | 7 ++++--- linkerd/app/inbound/src/http/mod.rs | 8 ++++---- .../transport-header/fuzz/fuzz_targets/fuzz_target_raw.rs | 3 ++- .../fuzz/fuzz_targets/fuzz_target_structured.rs | 5 +++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs b/linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs index ab9f23c00e..9da3ddad8d 100644 --- a/linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs +++ b/linkerd/app/inbound/fuzz/fuzz_targets/fuzz_target_1.rs @@ -1,11 +1,12 @@ #![no_main] use libfuzzer_sys::fuzz_target; +use linkerd_app_inbound::http::fuzz_logic::*; -fuzz_target!(|packets: Vec| { - if packets.len() == 0 { +fuzz_target!(|requests: Vec| { + if requests.len() == 0 { return; } let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(linkerd_app_inbound::http::fuzz_logic::fuzz_entry_raw(packets)); + rt.block_on(fuzz_entry_raw(requests)); }); diff --git a/linkerd/app/inbound/src/http/mod.rs b/linkerd/app/inbound/src/http/mod.rs index 8012d4d166..4710e45f08 100644 --- a/linkerd/app/inbound/src/http/mod.rs +++ b/linkerd/app/inbound/src/http/mod.rs @@ -272,14 +272,14 @@ pub mod fuzz_logic { use linkerd_app_test::*; #[derive(Debug, Arbitrary)] - pub struct TransportHeaderSpec { + pub struct HttpRequestSpec { pub uri: Vec, pub header_name: Vec, pub header_value: Vec, pub http_method: bool, } - pub async fn fuzz_entry_raw(packets: Vec) { + pub async fn fuzz_entry_raw(requests: Vec) { let mut server = hyper::server::conn::Http::new(); server.http1_only(true); let mut client = ClientBuilder::new(); @@ -304,8 +304,8 @@ pub mod fuzz_logic { let server = build_fuzz_server(cfg, rt, profiles, connect).new_service(accept); let (mut client, bg) = http_util::connect_and_accept(&mut client, server).await; - // Now send all of the packets - for inp in packets.iter() { + // Now send all of the requests + for inp in requests.iter() { if let Ok(uri) = std::str::from_utf8(&inp.uri[..]) { if let Ok(header_name) = std::str::from_utf8(&inp.header_name[..]) { if let Ok(header_value) = std::str::from_utf8(&inp.header_value[..]) { diff --git a/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_raw.rs b/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_raw.rs index 0b5351044f..326cf23f5b 100644 --- a/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_raw.rs +++ b/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_raw.rs @@ -1,7 +1,8 @@ #![no_main] use libfuzzer_sys::fuzz_target; +use linkerd_transport_header::fuzz_logic::*; fuzz_target!(|data: &[u8]| { let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(linkerd_transport_header::fuzz_logic::fuzz_entry_raw(data)); + rt.block_on(fuzz_entry_raw(data)); }); diff --git a/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_structured.rs b/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_structured.rs index 5954b69d76..ac355c9726 100644 --- a/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_structured.rs +++ b/linkerd/transport-header/fuzz/fuzz_targets/fuzz_target_structured.rs @@ -1,10 +1,11 @@ #![no_main] use libfuzzer_sys::fuzz_target; +use linkerd_transport_header::fuzz_logic::*; fuzz_target!( - |inp: linkerd_transport_header::fuzz_logic::TransportHeaderSpec| { + |inp: TransportHeaderSpec| { let rt = tokio::runtime::Runtime::new().unwrap(); - rt.block_on(linkerd_transport_header::fuzz_logic::fuzz_entry_structured( + rt.block_on(fuzz_entry_structured( inp, )); }