From 370d2888b6294cf433f30b9fa59ff2d7dea654cc Mon Sep 17 00:00:00 2001 From: Jose Quintana <1700322+joseluisq@users.noreply.github.com> Date: Fri, 9 Feb 2024 06:53:38 +0100 Subject: [PATCH] chore: base fuzz and micro-benchmark testing for static files module (#310) it just introduces fuzzing and micro-benchmark tests for the static files module. As a way to continue enhancing the performance and security of SWS in general. It is expected to be improved over time including other modules as well. --- benches/Cargo.toml | 5 +++++ benches/static_files.rs | 29 +++++++++++++++++++++++++++++ fuzz/.gitignore | 6 ++++++ fuzz/Cargo.toml | 22 ++++++++++++++++++++++ fuzz/src/static_files.rs | 17 +++++++++++++++++ src/static_files.rs | 12 ++++++++++++ 6 files changed, 91 insertions(+) create mode 100644 benches/static_files.rs create mode 100644 fuzz/.gitignore create mode 100644 fuzz/Cargo.toml create mode 100644 fuzz/src/static_files.rs diff --git a/benches/Cargo.toml b/benches/Cargo.toml index a2d0406..69ac104 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -13,3 +13,8 @@ hyper = { version = "0.14", features = ["stream", "http1", "http2", "tcp", "serv name = "control_headers" path = "control_headers.rs" harness = false + +[[bench]] +name = "static_files" +path = "static_files.rs" +harness = false diff --git a/benches/static_files.rs b/benches/static_files.rs new file mode 100644 index 0000000..12f1897 --- /dev/null +++ b/benches/static_files.rs @@ -0,0 +1,29 @@ +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; + +use static_web_server::static_files; + +#[derive(Debug)] +struct Inputs<'a> { + base_path: &'a std::path::Path, + uri_path: &'a str, +} +impl std::fmt::Display for Inputs<'_> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(fmt, "{:?}", self) + } +} + +fn sanitize_path_benchmark(c: &mut Criterion) { + let base_path = std::path::Path::new("root/../"); + let uri_path: &str = "../assets/../../.../image.jpg"; + let inputs = Inputs { + base_path, + uri_path, + }; + c.bench_with_input(BenchmarkId::new("path_inputs", &inputs), &inputs, |b, s| { + b.iter(|| static_files::sanitize_path(s.base_path, s.uri_path)) + }); +} + +criterion_group!(static_files_bench, sanitize_path_benchmark); +criterion_main!(static_files_bench); diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..e7c4f16 --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,6 @@ +target +corpus +artifacts +coverage +Cargo.lock +crash* diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..6b6bab9 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "static-web-server-fuzz" +version = "0.0.0" +publish = false +edition = "2021" +rust-version = "1.70.0" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +arbitrary = { version = "1", features = ["derive"] } +libfuzzer-sys = { version = "0.4", features = ["arbitrary-derive"] } +static-web-server = { path = ".." } +hyper = { version = "0.14", features = ["stream", "http1", "http2", "tcp", "server"] } + +[profile.release] +debug = 1 + +[[bin]] +name = "static_files" +path = "src/static_files.rs" diff --git a/fuzz/src/static_files.rs b/fuzz/src/static_files.rs new file mode 100644 index 0000000..3a80a95 --- /dev/null +++ b/fuzz/src/static_files.rs @@ -0,0 +1,17 @@ +#![no_main] + +use libfuzzer_sys::arbitrary::Arbitrary; +use libfuzzer_sys::fuzz_target; +use static_web_server::static_files; + +#[derive(Debug, Arbitrary)] +struct RequestPath { + base: Vec, + uri: Vec, +} + +fuzz_target!(|input: RequestPath| { + let uri = unsafe { std::str::from_utf8_unchecked(&input.uri[..]) }; + let base = unsafe { std::str::from_utf8_unchecked(&input.base[..]) }; + let _ = static_files::sanitize_path(std::path::Path::new(base), uri); +}); diff --git a/src/static_files.rs b/src/static_files.rs index 82423a7..10fa84f 100644 --- a/src/static_files.rs +++ b/src/static_files.rs @@ -751,6 +751,18 @@ mod tests { sanitize_path(base_dir, "/../foo.html").unwrap(), root_dir().join("foo.html"), ); + assert_eq!( + sanitize_path(base_dir, "/../W�foo.html").unwrap(), + root_dir().join("W�foo.html"), + ); + assert_eq!( + sanitize_path(base_dir, "/%EF%BF%BD/../bar.html").unwrap(), + root_dir().join("�/bar.html"), + ); + assert_eq!( + sanitize_path(base_dir, "àí/é%20/öüñ").unwrap(), + root_dir().join("àí/é /öüñ"), + ); #[cfg(unix)] let expected_path = root_dir().join("C:\\/foo.html"); -- libgit2 1.7.2