add a fuzzer
This commit is contained in:
parent
e52ce4a61d
commit
bb9cb386b6
9 changed files with 4364 additions and 33 deletions
|
@ -6,6 +6,10 @@ edition = "2021"
|
|||
license = "EUPL-1.2"
|
||||
description = "A robust email server"
|
||||
|
||||
[lib]
|
||||
name = "aerogramme"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
# async runtime
|
||||
tokio = { version = "1.18", default-features = false, features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros", "sync", "signal", "fs"] }
|
||||
|
|
4
fuzz/.gitignore
vendored
Normal file
4
fuzz/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
target
|
||||
corpus
|
||||
artifacts
|
||||
coverage
|
4249
fuzz/Cargo.lock
generated
Normal file
4249
fuzz/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
27
fuzz/Cargo.toml
Normal file
27
fuzz/Cargo.toml
Normal file
|
@ -0,0 +1,27 @@
|
|||
[package]
|
||||
name = "aerogramme-fuzz"
|
||||
version = "0.0.0"
|
||||
publish = false
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
libfuzzer-sys = "0.4"
|
||||
tokio = { version = "1.18", default-features = false, features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros", "sync", "signal", "fs"] }
|
||||
quick-xml = { version = "0.31", features = ["async-tokio"] }
|
||||
|
||||
[dependencies.aerogramme]
|
||||
path = ".."
|
||||
|
||||
[patch.crates-io]
|
||||
imap-types = { git = "https://github.com/superboum/imap-codec", branch = "custom/aerogramme" }
|
||||
imap-codec = { git = "https://github.com/superboum/imap-codec", branch = "custom/aerogramme" }
|
||||
|
||||
[[bin]]
|
||||
name = "dav"
|
||||
path = "fuzz_targets/dav.rs"
|
||||
test = false
|
||||
doc = false
|
||||
bench = false
|
48
fuzz/fuzz_targets/dav.rs
Normal file
48
fuzz/fuzz_targets/dav.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use aerogramme::dav::{types, realization, xml};
|
||||
use quick_xml::reader::NsReader;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
async fn serialize(elem: &impl xml::QWrite) -> Vec<u8> {
|
||||
let mut buffer = Vec::new();
|
||||
let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer);
|
||||
let q = quick_xml::writer::Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
|
||||
let ns_to_apply = vec![ ("xmlns:D".into(), "DAV:".into()) ];
|
||||
let mut writer = xml::Writer { q, ns_to_apply };
|
||||
|
||||
elem.qwrite(&mut writer).await.expect("xml serialization");
|
||||
tokio_buffer.flush().await.expect("tokio buffer flush");
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
type Object = types::Multistatus<realization::Core, types::PropValue<realization::Core>>;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let rt = Runtime::new().expect("tokio runtime initialization");
|
||||
|
||||
rt.block_on(async {
|
||||
// 1. Setup fuzzing by finding an input that seems correct, do not crash yet then.
|
||||
let mut rdr = match xml::Reader::new(NsReader::from_reader(data)).await {
|
||||
Err(_) => return,
|
||||
Ok(r) => r,
|
||||
};
|
||||
let reference = match rdr.find::<Object>().await {
|
||||
Err(_) => return,
|
||||
Ok(m) => m,
|
||||
};
|
||||
|
||||
// 2. Re-serialize the input
|
||||
let my_serialization = serialize(&reference).await;
|
||||
|
||||
// 3. De-serialize my serialization
|
||||
let mut rdr2 = xml::Reader::new(NsReader::from_reader(my_serialization.as_slice())).await.expect("XML Reader init");
|
||||
let comparison = rdr2.find::<Object>().await.expect("Deserialize again");
|
||||
|
||||
// 4. Both the first decoding and last decoding must be identical
|
||||
assert_eq!(reference, comparison);
|
||||
})
|
||||
});
|
|
@ -1,11 +1,11 @@
|
|||
// utils
|
||||
mod error;
|
||||
mod xml;
|
||||
pub mod error;
|
||||
pub mod xml;
|
||||
|
||||
// webdav
|
||||
mod types;
|
||||
mod encoder;
|
||||
mod decoder;
|
||||
pub mod types;
|
||||
pub mod encoder;
|
||||
pub mod decoder;
|
||||
|
||||
// calendar
|
||||
mod caltypes;
|
||||
|
@ -17,7 +17,7 @@ mod acltypes;
|
|||
mod versioningtypes;
|
||||
|
||||
// final type
|
||||
mod realization;
|
||||
pub mod realization;
|
||||
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
|
|
@ -12,7 +12,7 @@ pub const CARD_URN: &[u8] = b"urn:ietf:params:xml:ns:carddav";
|
|||
|
||||
// Async traits
|
||||
pub trait IWrite = AsyncWrite + Unpin;
|
||||
pub trait IRead = AsyncBufRead + Unpin + 'static;
|
||||
pub trait IRead = AsyncBufRead + Unpin;
|
||||
|
||||
// Serialization/Deserialization traits
|
||||
pub trait QWrite {
|
||||
|
@ -78,7 +78,7 @@ impl<T: IRead> Reader<T> {
|
|||
/// skip a node at current level
|
||||
/// I would like to make this one private but not ready
|
||||
pub async fn skip(&mut self) -> Result<Event<'static>, ParsingError> {
|
||||
println!("skipping inside node {:?}", self.parents.last());
|
||||
//println!("skipping inside node {:?}", self.parents.last());
|
||||
match &self.cur {
|
||||
Event::Start(b) => {
|
||||
let _span = self.rdr.read_to_end_into_async(b.to_end().name(), &mut self.buf).await?;
|
||||
|
@ -235,7 +235,7 @@ impl<T: IRead> Reader<T> {
|
|||
_ => return Err(ParsingError::Recoverable),
|
||||
};
|
||||
|
||||
println!("open tag {:?}", evt);
|
||||
//println!("open tag {:?}", evt);
|
||||
self.parents.push(evt.clone());
|
||||
Ok(evt)
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ impl<T: IRead> Reader<T> {
|
|||
|
||||
// find stop tag
|
||||
pub async fn close(&mut self) -> Result<Event<'static>, ParsingError> {
|
||||
println!("close tag {:?}", self.parents.last());
|
||||
//println!("close tag {:?}", self.parents.last());
|
||||
|
||||
// Handle the empty case
|
||||
if !self.parent_has_child() {
|
||||
|
|
19
src/lib.rs
Normal file
19
src/lib.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(async_fn_in_trait)]
|
||||
#![feature(async_closure)]
|
||||
#![feature(trait_alias)]
|
||||
|
||||
pub mod auth;
|
||||
pub mod bayou;
|
||||
pub mod config;
|
||||
pub mod cryptoblob;
|
||||
pub mod dav;
|
||||
pub mod imap;
|
||||
pub mod k2v_util;
|
||||
pub mod lmtp;
|
||||
pub mod login;
|
||||
pub mod mail;
|
||||
pub mod server;
|
||||
pub mod storage;
|
||||
pub mod timestamp;
|
||||
pub mod user;
|
26
src/main.rs
26
src/main.rs
|
@ -1,23 +1,3 @@
|
|||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(async_fn_in_trait)]
|
||||
#![feature(async_closure)]
|
||||
#![feature(trait_alias)]
|
||||
|
||||
mod auth;
|
||||
mod bayou;
|
||||
mod config;
|
||||
mod cryptoblob;
|
||||
mod dav;
|
||||
mod imap;
|
||||
mod k2v_util;
|
||||
mod lmtp;
|
||||
mod login;
|
||||
mod mail;
|
||||
mod server;
|
||||
mod storage;
|
||||
mod timestamp;
|
||||
mod user;
|
||||
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -25,9 +5,9 @@ use anyhow::{bail, Context, Result};
|
|||
use clap::{Parser, Subcommand};
|
||||
use nix::{sys::signal, unistd::Pid};
|
||||
|
||||
use config::*;
|
||||
use login::{static_provider::*, *};
|
||||
use server::Server;
|
||||
use aerogramme::config::*;
|
||||
use aerogramme::login::{static_provider::*, *};
|
||||
use aerogramme::server::Server;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
|
|
Loading…
Reference in a new issue