10
0
Fork 0
mirror of https://github.com/ZeusWPI/ZNS.git synced 2024-11-24 06:11:10 +01:00

add fuzzer

This commit is contained in:
Xander Bil 2024-10-09 19:23:49 +02:00
parent 3779125367
commit 341f79f5ad
No known key found for this signature in database
GPG key ID: EC9706B54A278598
12 changed files with 253 additions and 4 deletions

53
Cargo.lock generated
View file

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "addr2line" name = "addr2line"
@ -66,6 +66,15 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "asn1" name = "asn1"
version = "0.16.2" version = "0.16.2"
@ -149,6 +158,8 @@ version = "1.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48"
dependencies = [ dependencies = [
"jobserver",
"libc",
"shlex", "shlex",
] ]
@ -255,6 +266,17 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "derive_arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "diesel" name = "diesel"
version = "2.2.2" version = "2.2.2"
@ -640,6 +662,15 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "jobserver"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.70" version = "0.3.70"
@ -655,6 +686,17 @@ version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
name = "libfuzzer-sys"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7"
dependencies = [
"arbitrary",
"cc",
"once_cell",
]
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.14" version = "0.4.14"
@ -1614,6 +1656,7 @@ checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
name = "zns" name = "zns"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"arbitrary",
"base64", "base64",
"int-enum", "int-enum",
"thiserror", "thiserror",
@ -1645,3 +1688,11 @@ dependencies = [
"tokio", "tokio",
"zns", "zns",
] ]
[[package]]
name = "zns-fuzz"
version = "0.0.0"
dependencies = [
"libfuzzer-sys",
"zns",
]

View file

@ -5,4 +5,5 @@ members = [
"zns", "zns",
"zns-cli", "zns-cli",
"zns-daemon", "zns-daemon",
"fuzz"
] ]

4
fuzz/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
target
corpus
artifacts
coverage

19
fuzz/Cargo.toml Normal file
View file

@ -0,0 +1,19 @@
[package]
name = "zns-fuzz"
version = "0.0.0"
publish = false
edition = "2021"
[package.metadata]
cargo-fuzz = true
[dependencies]
libfuzzer-sys = "0.4"
zns = {path = "../zns", features = ["arbitrary"]}
[[bin]]
name = "parser"
path = "fuzz_targets/parser.rs"
test = false
doc = false
bench = false

42
fuzz/cov.sh Executable file
View file

@ -0,0 +1,42 @@
#!/bin/env bash
set -e
# Check if the correct number of arguments is provided
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <llvm-cov> <fuzz_target>"
exit 1
fi
# Assign the first argument to the fuzz_target variable
COMMAND=$1
FUZZ_TARGET=$2
if ! command -v $(COMMAND) &> /dev/null; then
echo "llvm-cov could not be found, please install LLVM."
exit 1
fi
if ! command -v rustfilt &> /dev/null; then
echo "rustfilt could not be found, please install rustfilt."
exit 1
fi
cargo fuzz coverage "$FUZZ_TARGET"
TARGET_DIR="target/x86_64-unknown-linux-gnu/coverage/x86_64-unknown-linux-gnu/release"
PROF_DATA="coverage/$FUZZ_TARGET/coverage.profdata"
OUTPUT_FILE="coverage/index.html"
if [ ! -f "$PROF_DATA" ]; then
echo "Coverage data file $PROF_DATA not found."
exit 1
fi
$COMMAND show "$TARGET_DIR/$FUZZ_TARGET" --format=html \
-Xdemangler=rustfilt \
--ignore-filename-regex="\.cargo" \
-instr-profile="$PROF_DATA" \
> "$OUTPUT_FILE"
echo "Coverage report generated as $OUTPUT_FILE"

82
fuzz/flake.lock Normal file
View file

@ -0,0 +1,82 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1728241625,
"narHash": "sha256-yumd4fBc/hi8a9QgA9IT8vlQuLZ2oqhkJXHPKxH/tRw=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "c31898adf5a8ed202ce5bea9f347b1c6871f32d1",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1728354625,
"narHash": "sha256-r+Sa1NRRT7LXKzCaVaq75l1GdZcegODtF06uaxVVVbI=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "d216ade5a0091ce60076bf1f8bc816433a1fc5da",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

31
fuzz/flake.nix Normal file
View file

@ -0,0 +1,31 @@
{
description = "flake for fuzzer as it needs nightly";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
};
outputs = {self, nixpkgs, flake-utils, rust-overlay, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
in
with pkgs;
{
devShell = mkShell {
buildInputs = [
(rust-bin.nightly.latest.default.override { extensions = [ "llvm-tools-preview" ]; })
cargo-fuzz
rustfilt
];
};
});
}

View file

@ -0,0 +1,9 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use zns::{parser::FromBytes, reader::Reader, structs::Message};
fuzz_target!(|data: &[u8]| {
let mut reader = Reader::new(data);
let _ = Message::from_bytes(&mut reader);
});

View file

@ -11,6 +11,7 @@ test-utils = []
base64 = "0.22.0" base64 = "0.22.0"
int-enum = "1.1" int-enum = "1.1"
thiserror = "1.0" thiserror = "1.0"
arbitrary = { version = "^1.3.2", optional = true, features = ["derive"] }
[dev-dependencies] [dev-dependencies]
zns = { path = ".", features = ["test-utils"] } zns = { path = ".", features = ["test-utils"] }

View file

@ -1,6 +1,7 @@
use std::fmt::Display; use std::fmt::Display;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct LabelString(Vec<String>); pub struct LabelString(Vec<String>);
pub fn labels_equal(vec1: &LabelString, vec2: &LabelString) -> bool { pub fn labels_equal(vec1: &LabelString, vec2: &LabelString) -> bool {

View file

@ -66,12 +66,12 @@ impl<'a> Reader<'a> {
} }
pub fn seek(&self, position: usize) -> Result<Self> { pub fn seek(&self, position: usize) -> Result<Self> {
if position >= self.position - 2 { if self.position < 2 || position >= self.position - 2 {
Err(ZNSError::Reader { Err(ZNSError::Reader {
message: String::from("Seeking into the future is not allowed!!"), message: String::from("Seeking into the future is not allowed!!"),
}) })
} else { } else {
let mut reader = Reader::new(&self.buffer[..self.position]); let mut reader = Reader::new(&self.buffer[..self.position - 1]);
reader.position = position; reader.position = position;
Ok(reader) Ok(reader)
} }
@ -126,7 +126,7 @@ mod tests {
let new_reader = reader.seek(1); let new_reader = reader.seek(1);
assert!(new_reader.is_ok()); assert!(new_reader.is_ok());
assert_eq!(new_reader.unwrap().unread_bytes(), 10); assert_eq!(new_reader.unwrap().unread_bytes(), 9);
let new_reader = reader.seek(100); let new_reader = reader.seek(100);
assert!(new_reader.is_err()); assert!(new_reader.is_err());

View file

@ -3,6 +3,7 @@ use int_enum::IntEnum;
use crate::labelstring::LabelString; use crate::labelstring::LabelString;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Type { pub enum Type {
Type(RRType), Type(RRType),
Other(u16), Other(u16),
@ -10,6 +11,7 @@ pub enum Type {
#[repr(u16)] #[repr(u16)]
#[derive(Debug, Clone, PartialEq, IntEnum)] #[derive(Debug, Clone, PartialEq, IntEnum)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum RRType { pub enum RRType {
A = 1, A = 1,
SOA = 6, SOA = 6,
@ -20,6 +22,7 @@ pub enum RRType {
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum Class { pub enum Class {
Class(RRClass), Class(RRClass),
Other(u16), Other(u16),
@ -27,6 +30,7 @@ pub enum Class {
#[repr(u16)] #[repr(u16)]
#[derive(Debug, Clone, PartialEq, IntEnum)] #[derive(Debug, Clone, PartialEq, IntEnum)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub enum RRClass { pub enum RRClass {
IN = 1, IN = 1,
NONE = 254, NONE = 254,
@ -56,6 +60,7 @@ pub enum Opcode {
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Question { pub struct Question {
pub qname: LabelString, pub qname: LabelString,
pub qtype: Type, // NOTE: should be QTYPE, right now not really needed pub qtype: Type, // NOTE: should be QTYPE, right now not really needed
@ -63,6 +68,7 @@ pub struct Question {
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Header { pub struct Header {
pub id: u16, pub id: u16,
pub flags: u16, // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | ; 1 | 4 | 1 | 1 | 1 | 1 | 3 | 4 pub flags: u16, // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | ; 1 | 4 | 1 | 1 | 1 | 1 | 3 | 4
@ -73,6 +79,7 @@ pub struct Header {
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct Message { pub struct Message {
pub header: Header, pub header: Header,
pub question: Vec<Question>, pub question: Vec<Question>,
@ -82,6 +89,7 @@ pub struct Message {
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct RR { pub struct RR {
pub name: LabelString, pub name: LabelString,
pub _type: Type, pub _type: Type,