This commit adds AFL++ (American Fuzzy Lop) fuzzing support to help find bugs, crashes, and security vulnerabilities in the URL parser. Changes: - Add fuzz_afl.c: AFL++ fuzz target that tests all parser functions - url_parse() with different flag combinations - url_parse_ipv4() and url_parse_ipv6() - url_serialize(), url_percent_decode(), url_remove_white_space() - Add build_afl.sh: Build script with AFL++ compiler detection - Add run_afl.sh: Automated fuzzing script with result reporting - Add url.dict: Dictionary file to guide AFL++ mutations - Add corpus/: Seed inputs covering various URL patterns - Basic URLs, IPv4/IPv6, percent-encoding, relative paths - Edge cases and special schemes (file://, mailto:, etc.) - Add FUZZING.md: Comprehensive documentation - Installation instructions - Quick start guide - Advanced usage (parallel fuzzing, sanitizers) - Troubleshooting tips - Add fuzz.c: Standalone mutation-based fuzzer (no AFL++ required) - Useful for quick testing without installing AFL++ - Implements various mutation strategies
116 lines
3.1 KiB
C
116 lines
3.1 KiB
C
/*
|
|
* AFL++ fuzz target for url.c parser
|
|
*
|
|
* Build with AFL++:
|
|
* afl-gcc -o fuzz_afl fuzz_afl.c ../url.c -Wall -Wextra -ggdb
|
|
*
|
|
* Or with afl-clang-fast for better instrumentation:
|
|
* afl-clang-fast -o fuzz_afl fuzz_afl.c ../url.c -Wall -Wextra -ggdb
|
|
*
|
|
* Run with:
|
|
* afl-fuzz -i corpus/ -o findings/ -- ./fuzz_afl
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
|
|
#include "../url.h"
|
|
|
|
// Maximum input size
|
|
#define MAX_INPUT_SIZE 8192
|
|
|
|
// Test buffer for outputs
|
|
static char output_buffer[16384];
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
(void)argc;
|
|
(void)argv;
|
|
|
|
// Read input from stdin (AFL++ feeds input this way)
|
|
unsigned char input[MAX_INPUT_SIZE];
|
|
ssize_t len = read(STDIN_FILENO, input, sizeof(input));
|
|
|
|
if (len <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
// Ensure null termination for safety
|
|
if (len < (ssize_t)sizeof(input)) {
|
|
input[len] = '\0';
|
|
}
|
|
|
|
// Fuzz url_parse with different flag combinations
|
|
URL url;
|
|
int flags_to_test[] = {
|
|
0,
|
|
URL_FLAG_ALLOWREF,
|
|
URL_FLAG_RFC3986,
|
|
URL_FLAG_ALLOWREF | URL_FLAG_RFC3986
|
|
};
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
int flags = flags_to_test[i];
|
|
|
|
// Test with NULL cursor
|
|
int ret = url_parse((char *)input, len, NULL, &url, flags);
|
|
|
|
// Test with cursor
|
|
int cursor = 0;
|
|
url_parse((char *)input, len, &cursor, &url, flags);
|
|
|
|
// If parse succeeded, test serialization
|
|
if (ret == 0) {
|
|
url_serialize(url, NULL, output_buffer, sizeof(output_buffer));
|
|
|
|
// Test serialization with itself as base
|
|
url_serialize(url, &url, output_buffer, sizeof(output_buffer));
|
|
}
|
|
}
|
|
|
|
// Test whitespace removal
|
|
int cleaned_len = url_remove_white_space((char *)input, len, output_buffer, sizeof(output_buffer));
|
|
|
|
// If whitespace removal succeeded, try parsing the cleaned input
|
|
if (cleaned_len > 0 && cleaned_len < (int)sizeof(output_buffer)) {
|
|
url_parse(output_buffer, cleaned_len, NULL, &url, 0);
|
|
}
|
|
|
|
// Test percent decode on the full input
|
|
URL_String str = { (char *)input, len };
|
|
url_percent_decode(str, output_buffer, sizeof(output_buffer));
|
|
|
|
// Test IPv4 parsing
|
|
URL_IPv4 ipv4;
|
|
url_parse_ipv4((char *)input, len, NULL, &ipv4);
|
|
|
|
int cursor = 0;
|
|
url_parse_ipv4((char *)input, len, &cursor, &ipv4);
|
|
|
|
// Test IPv6 parsing
|
|
URL_IPv6 ipv6;
|
|
url_parse_ipv6((char *)input, len, NULL, &ipv6);
|
|
|
|
cursor = 0;
|
|
url_parse_ipv6((char *)input, len, &cursor, &ipv6);
|
|
|
|
// Test parsing with base URL (if input is long enough)
|
|
if (len > 10) {
|
|
// Try to use first half as base, second half as reference
|
|
int mid = len / 2;
|
|
|
|
URL base_url;
|
|
if (url_parse((char *)input, mid, NULL, &base_url, 0) == 0) {
|
|
URL reference;
|
|
if (url_parse((char *)input + mid, len - mid, NULL, &reference, URL_FLAG_ALLOWREF) == 0) {
|
|
url_serialize(reference, &base_url, output_buffer, sizeof(output_buffer));
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|