zupt/tests/fuzz_decompress.c
2026-08-31 14:14:36 -03:00

72 lines
2.1 KiB
C

/*
* SPDX-License-Identifier: AGPL-3.0-or-later
* Copyright (c) 2025-2026 Cristian Cezar Moisés
* ZUPT v2.0.0 — AFL++ Fuzzing Harness: Archive Decompression
* Copyright (c) 2026 Cristian Cezar Moisés — AGPL-3.0-or-later
*
* Reads a fuzzed .zupt archive from stdin, attempts to extract it.
* Catches crashes, buffer overflows, and undefined behavior.
*
* Build:
* afl-clang-fast -fsanitize=address,undefined -g -O1 \
* -Iinclude -Isrc $(SOURCES) tests/fuzz_decompress.c \
* -lm -lpthread -o fuzz_decompress
*
* Run:
* mkdir -p corpus findings
* # Generate seed corpus:
* ./zupt compress /tmp/fuzz_seed.zupt /path/to/small/testfile
* cp /tmp/fuzz_seed.zupt corpus/
* afl-fuzz -i corpus -o findings -- ./fuzz_decompress
*/
#include "zupt.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void) {
/* Read entire stdin into memory */
size_t cap = 4 * 1024 * 1024; /* 4 MB max fuzz input */
uint8_t *buf = (uint8_t *)malloc(cap);
if (!buf) return 1;
size_t total = 0;
while (total < cap) {
ssize_t n = read(0, buf + total, cap - total);
if (n <= 0) break;
total += (size_t)n;
}
if (total < 64) { free(buf); return 0; } /* Too small for a valid archive */
/* Write to temp file (zupt_extract_archive needs a file path) */
char tmp_arc[] = "/tmp/zupt_fuzz_XXXXXX";
int fd = mkstemp(tmp_arc);
if (fd < 0) { free(buf); return 1; }
write(fd, buf, total);
close(fd);
free(buf);
/* Attempt extraction — this is where crashes happen */
zupt_options_t opts;
zupt_default_options(&opts);
opts.quiet = 1;
char tmp_out[] = "/tmp/zupt_fuzz_out_XXXXXX";
mkdtemp(tmp_out);
zupt_extract_archive(tmp_arc, tmp_out, &opts);
/* Also try test (integrity check without extraction) */
zupt_test_archive(tmp_arc, &opts);
/* Also try list */
zupt_list_archive(tmp_arc, &opts);
/* Cleanup */
unlink(tmp_arc);
/* Note: not recursively removing tmp_out — AFL runs are ephemeral */
return 0;
}