forked from mirrors/kingfisher
openssf scorecard suggested improvements
This commit is contained in:
parent
ae8c5f62a4
commit
0c77e3c4a3
7 changed files with 3710 additions and 1 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -19,8 +19,13 @@ logs/*
|
|||
*.html
|
||||
!docs/access-map-viewer/index.html
|
||||
*.dot
|
||||
fuzz/
|
||||
fuzz/*
|
||||
!fuzz/Cargo.toml
|
||||
!fuzz/Cargo.lock
|
||||
!fuzz/fuzz_targets/
|
||||
!fuzz/fuzz_targets/*.rs
|
||||
fuzz/corpus/
|
||||
fuzz/target/
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
|
|
@ -69,6 +74,7 @@ bin/
|
|||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
!fuzz/Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
|
|
|||
3573
fuzz/Cargo.lock
generated
Normal file
3573
fuzz/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
49
fuzz/Cargo.toml
Normal file
49
fuzz/Cargo.toml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
[package]
|
||||
name = "kingfisher-fuzz"
|
||||
version = "0.0.0"
|
||||
publish = false
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
libfuzzer-sys = "0.4"
|
||||
|
||||
[dependencies.kingfisher-core]
|
||||
path = "../crates/kingfisher-core"
|
||||
|
||||
[dependencies.kingfisher-scanner]
|
||||
path = "../crates/kingfisher-scanner"
|
||||
|
||||
# Expose base64 for the fuzz target that exercises get_base64_strings
|
||||
[dependencies.base64]
|
||||
version = "0.22"
|
||||
|
||||
[workspace]
|
||||
members = ["."]
|
||||
|
||||
# Must mirror the root workspace patch so vectorscan-rs builds from the vendored copy
|
||||
[patch.crates-io]
|
||||
vectorscan-rs = { path = "../vendor/vectorscan-rs/vectorscan-rs" }
|
||||
vectorscan-rs-sys = { path = "../vendor/vectorscan-rs/vectorscan-rs-sys" }
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_entropy"
|
||||
path = "fuzz_targets/fuzz_entropy.rs"
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_location"
|
||||
path = "fuzz_targets/fuzz_location.rs"
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_base64"
|
||||
path = "fuzz_targets/fuzz_base64.rs"
|
||||
doc = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_span"
|
||||
path = "fuzz_targets/fuzz_span.rs"
|
||||
doc = false
|
||||
16
fuzz/fuzz_targets/fuzz_base64.rs
Normal file
16
fuzz/fuzz_targets/fuzz_base64.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#![no_main]
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use kingfisher_scanner::primitives::get_base64_strings;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let results = get_base64_strings(data);
|
||||
|
||||
for decoded in &results {
|
||||
// Every returned span must be within the input bounds
|
||||
assert!(decoded.pos_start <= decoded.pos_end);
|
||||
assert!(decoded.pos_end <= data.len());
|
||||
// Decoded data must be non-empty and ASCII (per the function contract)
|
||||
assert!(!decoded.decoded.is_empty());
|
||||
assert!(decoded.decoded.is_ascii());
|
||||
}
|
||||
});
|
||||
11
fuzz/fuzz_targets/fuzz_entropy.rs
Normal file
11
fuzz/fuzz_targets/fuzz_entropy.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#![no_main]
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use kingfisher_core::calculate_shannon_entropy;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let entropy = calculate_shannon_entropy(data);
|
||||
// Invariants that must always hold:
|
||||
assert!(entropy.is_finite(), "entropy must be finite");
|
||||
assert!(entropy >= 0.0, "entropy must be non-negative");
|
||||
assert!(entropy <= 8.0, "entropy must be <= 8.0 for byte data");
|
||||
});
|
||||
27
fuzz/fuzz_targets/fuzz_location.rs
Normal file
27
fuzz/fuzz_targets/fuzz_location.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#![no_main]
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use kingfisher_core::location::{LocationMapping, OffsetSpan};
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
if data.len() < 4 {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use last 4 bytes to derive offsets, rest as the input text
|
||||
let text_len = data.len() - 4;
|
||||
let text = &data[..text_len];
|
||||
let offset_a = u16::from_le_bytes([data[text_len], data[text_len + 1]]) as usize;
|
||||
let offset_b = u16::from_le_bytes([data[text_len + 2], data[text_len + 3]]) as usize;
|
||||
|
||||
let mapping = LocationMapping::new(text);
|
||||
|
||||
// Exercise get_source_point with an arbitrary offset (may be beyond text length)
|
||||
let point = mapping.get_source_point(offset_a);
|
||||
assert!(point.line >= 1, "line numbers are 1-indexed");
|
||||
|
||||
// Exercise get_source_span with a span that might be empty, inverted, or out of bounds
|
||||
let start = offset_a.min(offset_b);
|
||||
let end = offset_a.max(offset_b);
|
||||
let span = OffsetSpan { start, end };
|
||||
let _source_span = mapping.get_source_span(&span);
|
||||
});
|
||||
27
fuzz/fuzz_targets/fuzz_span.rs
Normal file
27
fuzz/fuzz_targets/fuzz_span.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#![no_main]
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use kingfisher_core::OffsetSpan;
|
||||
use kingfisher_scanner::primitives::insert_span;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
// Interpret the input as a sequence of (start: u16, end: u16) span pairs
|
||||
if data.len() < 4 {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut spans: Vec<OffsetSpan> = Vec::new();
|
||||
let mut i = 0;
|
||||
while i + 3 < data.len() {
|
||||
let start = u16::from_le_bytes([data[i], data[i + 1]]) as usize;
|
||||
let end = u16::from_le_bytes([data[i + 2], data[i + 3]]) as usize;
|
||||
i += 4;
|
||||
|
||||
let span = OffsetSpan { start, end };
|
||||
insert_span(&mut spans, span);
|
||||
|
||||
// Invariant: the spans list must remain sorted by start offset
|
||||
for w in spans.windows(2) {
|
||||
assert!(w[0].start <= w[1].start, "spans must stay sorted");
|
||||
}
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue