Initial release
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
# libFuzzer harnesses for the untrusted (non-GGUF) input paths.
|
||||
# Requires clang; enable with the fuzz build:
|
||||
# CC=clang CXX=clang++ cmake -B build-fuzz -DTRELLIS2_FUZZ=ON
|
||||
# cmake --build build-fuzz -j
|
||||
# ./build-fuzz/fuzz/fuzz_image corpus_image/ -max_len=1048576
|
||||
# ./build-fuzz/fuzz/fuzz_dinodata corpus_dinodata/ -max_len=1048576
|
||||
|
||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
message(FATAL_ERROR "TRELLIS2_FUZZ requires clang (libFuzzer)")
|
||||
endif()
|
||||
|
||||
foreach(target fuzz_image fuzz_dinodata)
|
||||
add_executable(${target} ${target}.cpp)
|
||||
target_link_libraries(${target} PRIVATE trellis2)
|
||||
target_compile_options(${target} PRIVATE -fsanitize=fuzzer)
|
||||
target_link_options(${target} PRIVATE -fsanitize=fuzzer)
|
||||
target_compile_features(${target} PRIVATE cxx_std_14)
|
||||
endforeach()
|
||||
@@ -0,0 +1,10 @@
|
||||
# Fixed-crash regression seeds
|
||||
|
||||
Inputs that once crashed a fuzz harness and now must not. Re-run after changes:
|
||||
|
||||
./build-fuzz/fuzz/fuzz_dinodata fuzz/crashes-fixed/
|
||||
|
||||
- `dinodata-shape-overflow` — a `.dinodata` header whose shape dims multiply to
|
||||
an enormous element count; the loader used to `vector::resize` it and throw
|
||||
`std::length_error`. Fixed by an overflow-checked element-count cap in
|
||||
`trellis2_load_dinodata`.
|
||||
Binary file not shown.
@@ -0,0 +1,57 @@
|
||||
// libFuzzer harness for the .dinodata loader: arbitrary bytes -> temp file ->
|
||||
// trellis2_load_dinodata -> (on success) fingerprints over the payload.
|
||||
//
|
||||
// .dinodata files typically come from this codebase itself, but the demo and
|
||||
// CLI accept arbitrary paths, so the parser must be robust: reject bad magic /
|
||||
// truncated headers / shape overflow cleanly, never over-read.
|
||||
//
|
||||
// Invariants checked with abort() (not just "no crash"):
|
||||
// * on success, data.size() == product(shape) and shape is non-empty
|
||||
// * fingerprints run over the whole payload without UB
|
||||
//
|
||||
// Run: ./build-fuzz/fuzz/fuzz_dinodata corpus_dinodata/ -max_len=1048576
|
||||
|
||||
#include "../trellis2.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) {
|
||||
if (size > (16u << 20)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char path[] = "/tmp/fuzz_dinodata_XXXXXX";
|
||||
const int fd = mkstemp(path);
|
||||
if (fd < 0) {
|
||||
return 0;
|
||||
}
|
||||
const ssize_t written = write(fd, data, size);
|
||||
close(fd);
|
||||
if (written != (ssize_t) size) {
|
||||
unlink(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
trellis2_dino_cond cond;
|
||||
std::string err;
|
||||
if (trellis2_load_dinodata(path, cond, &err)) {
|
||||
int64_t total = 1;
|
||||
for (int64_t d : cond.shape) total *= d;
|
||||
if (cond.shape.empty() || (size_t) total != cond.data.size()) {
|
||||
abort(); // loader produced an inconsistent cond
|
||||
}
|
||||
const trellis2_dino_fingerprint fp = trellis2_dino_fingerprints(cond);
|
||||
if (fp.count != cond.data.size()) {
|
||||
abort();
|
||||
}
|
||||
} else if (err.empty()) {
|
||||
abort(); // failure must come with a reason
|
||||
}
|
||||
|
||||
unlink(path);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// libFuzzer harness for the image upload path: arbitrary bytes ->
|
||||
// t2_preprocess_image_bytes (stb_image decode -> alpha bbox crop ->
|
||||
// premultiply -> PIL-compatible Lanczos resize).
|
||||
//
|
||||
// This is the demo server's untrusted-input surface: the Go server hands
|
||||
// uploaded bytes straight to this function. GGUF model files are trusted
|
||||
// assets and deliberately not fuzzed here (privacy-filter.cpp threat model).
|
||||
//
|
||||
// Build via -DTRELLIS2_FUZZ=ON (clang only); run:
|
||||
// ./build-fuzz/fuzz/fuzz_image corpus_image/ -max_len=1048576
|
||||
//
|
||||
// Success invariant: the function either fails cleanly (nonzero + error
|
||||
// message) or fills exactly out_size^2*3 bytes. Any crash/leak/UB is a bug.
|
||||
|
||||
#include "../trellis2_capi.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) {
|
||||
if (size == 0 || size > (32u << 20)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Small output target keeps per-input cost low; the resampler code path
|
||||
// is identical for any out_size.
|
||||
static thread_local std::vector<unsigned char> out(64 * 64 * 3);
|
||||
char err[256] = {0};
|
||||
|
||||
(void) t2_preprocess_image_bytes(data, (int) size, 64, out.data(), err, sizeof(err));
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user