Add fuzzing of DNS server response parsing
authorMatt Corallo <git@bluematt.me>
Sun, 11 Feb 2024 20:43:30 +0000 (20:43 +0000)
committerMatt Corallo <git@bluematt.me>
Sun, 11 Feb 2024 20:43:30 +0000 (20:43 +0000)
fuzz/Cargo.toml [new file with mode: 0644]
fuzz/src/parse_response.rs [new file with mode: 0644]
fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.1b2d5a02ed.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz [new file with mode: 0644]
fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.c7bb77f34.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz [new file with mode: 0644]
fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.cbd61ac64.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz [new file with mode: 0644]
fuzz/test_cases/parse_response/SIGSEGV.PC.5555555998f9.STACK.1a75cee75b.CODE.1.ADDR.7fffff7feff8.INSTR.push___%rbx.fuzz [new file with mode: 0644]
src/query.rs

diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
new file mode 100644 (file)
index 0000000..c613c87
--- /dev/null
@@ -0,0 +1,46 @@
+[package]
+name = "fuzz"
+version = "0.0.1"
+authors = ["Automatically generated"]
+publish = false
+edition = "2021"
+# Because the function is unused it gets dropped before we link lightning, so
+# we have to duplicate build.rs here. Note that this is only required for
+# fuzzing mode.
+
+[package.metadata]
+cargo-fuzz = true
+
+[features]
+afl_fuzz = ["afl"]
+honggfuzz_fuzz = ["honggfuzz"]
+libfuzzer_fuzz = ["libfuzzer-sys"]
+stdin_fuzz = []
+
+[dependencies]
+dnssec-prover = { path = "../", features = ["validation", "std", "build_server"] }
+
+afl = { version = "0.12", optional = true }
+honggfuzz = { version = "0.5", optional = true, default-features = false }
+libfuzzer-sys = { version = "0.4", optional = true }
+
+[build-dependencies]
+cc = "1.0"
+
+# Prevent this from interfering with workspaces
+[workspace]
+members = ["."]
+
+[profile.release]
+lto = true
+codegen-units = 1
+debug-assertions = true
+overflow-checks = true
+
+# When testing a large fuzz corpus, -O1 offers a nice speedup
+[profile.dev]
+opt-level = 1
+
+[[bin]]
+name = "parse_response"
+path = "src/parse_response.rs"
diff --git a/fuzz/src/parse_response.rs b/fuzz/src/parse_response.rs
new file mode 100644 (file)
index 0000000..b958776
--- /dev/null
@@ -0,0 +1,68 @@
+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+#![cfg_attr(feature = "libfuzzer_fuzz", no_main)]
+
+#[cfg(not(fuzzing))]
+compile_error!("Fuzz targets need cfg=fuzzing");
+
+extern crate dnssec_prover;
+use dnssec_prover::query::fuzz_response;
+
+#[cfg(feature = "afl")]
+#[macro_use] extern crate afl;
+#[cfg(feature = "afl")]
+fn main() {
+       fuzz!(|data| {
+               fuzz_response(data);
+       });
+}
+
+#[cfg(feature = "honggfuzz")]
+#[macro_use] extern crate honggfuzz;
+#[cfg(feature = "honggfuzz")]
+fn main() {
+       loop {
+               fuzz!(|data| {
+                       fuzz_response(data);
+               });
+       }
+}
+
+#[cfg(feature = "libfuzzer_fuzz")]
+#[macro_use] extern crate libfuzzer_sys;
+#[cfg(feature = "libfuzzer_fuzz")]
+fuzz_target!(|data: &[u8]| {
+       fuzz_response(data);
+});
+
+#[cfg(feature = "stdin_fuzz")]
+fn main() {
+       use std::io::Read;
+
+       let mut data = Vec::with_capacity(8192);
+       std::io::stdin().read_to_end(&mut data).unwrap();
+       fuzz_response(&data);
+}
+
+#[test]
+fn run_test_cases() {
+       use std::fs;
+       use std::io::Read;
+
+       if let Ok(tests) = fs::read_dir("test_cases/parse_response") {
+               for test in tests {
+                       let mut data: Vec<u8> = Vec::new();
+                       let path = test.unwrap().path();
+                       fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap();
+
+                       fuzz_response(&data);
+               }
+       }
+}
diff --git a/fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.1b2d5a02ed.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz b/fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.1b2d5a02ed.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz
new file mode 100644 (file)
index 0000000..ba42741
Binary files /dev/null and b/fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.1b2d5a02ed.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz differ
diff --git a/fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.c7bb77f34.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz b/fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.c7bb77f34.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz
new file mode 100644 (file)
index 0000000..13f45bb
Binary files /dev/null and b/fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.c7bb77f34.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz differ
diff --git a/fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.cbd61ac64.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz b/fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.cbd61ac64.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz
new file mode 100644 (file)
index 0000000..6ab92b6
Binary files /dev/null and b/fuzz/test_cases/parse_response/SIGABRT.PC.7ffff7e42d3c.STACK.cbd61ac64.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz differ
diff --git a/fuzz/test_cases/parse_response/SIGSEGV.PC.5555555998f9.STACK.1a75cee75b.CODE.1.ADDR.7fffff7feff8.INSTR.push___%rbx.fuzz b/fuzz/test_cases/parse_response/SIGSEGV.PC.5555555998f9.STACK.1a75cee75b.CODE.1.ADDR.7fffff7feff8.INSTR.push___%rbx.fuzz
new file mode 100644 (file)
index 0000000..ba42741
Binary files /dev/null and b/fuzz/test_cases/parse_response/SIGSEGV.PC.5555555998f9.STACK.1a75cee75b.CODE.1.ADDR.7fffff7feff8.INSTR.push___%rbx.fuzz differ
index d13e8c6954043174db2f76e393bba63304d93846..3b1d21775ce2ac8c393b092f0534c3da361e9ca4 100644 (file)
@@ -53,6 +53,13 @@ async fn send_query_async(stream: &mut TokioTcpStream, domain: &Name, ty: u16) -
        Ok(())
 }
 
+#[cfg(fuzzing)]
+/// Read some input and parse it as if it came from a server, for fuzzing.
+pub fn fuzz_response(response: &[u8]) {
+       let (mut proof, mut names) = (Vec::new(), Vec::new());
+       let _ = handle_response(response, &mut proof, &mut names);
+}
+
 fn handle_response(resp: &[u8], proof: &mut Vec<u8>, rrsig_key_names: &mut Vec<Name>) -> Result<u32, Error> {
        let mut read: &[u8] = resp;
        if emap(read_u16(&mut read))? != TXID { return Err(Error::new(ErrorKind::Other, "bad txid")); }