Addendum: harness_ct.c
Full source for the MIME Content-Type parser AFL++ harness referenced in Part 3: Writing the Fuzzing Harness.
/*
* AFL++ harness: Sophos mailscanner MIME Content-Type parser.
*
* Loads mailscanner.so (converted from the mailscanner executable via LIEF)
* and calls mime_content_type_new_from_string with fuzz input.
*
* The parser handles Content-Type header values like:
* text/html; charset=utf-8; boundary="----=_Part_123"; name="file.txt"
*
* Build: clang -m32 -g -O2 -o harness_ct harness_ct.c -ldl
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <unistd.h>
typedef void *(*ct_parse_fn)(const char *, int, int);
typedef void (*ct_destroy_fn)(void *);
static ct_parse_fn parse;
static ct_destroy_fn destroy;
static void load_lib(void) {
if (!dlopen("./stubs.so", RTLD_LAZY | RTLD_GLOBAL)) {
fprintf(stderr, "dlopen stubs: %s\n", dlerror()); _exit(1);
}
void *h = dlopen("./mailscanner.so", RTLD_LAZY);
if (!h) { fprintf(stderr, "dlopen: %s\n", dlerror()); _exit(1); }
parse = (ct_parse_fn) dlsym(h, "mime_content_type_new_from_string");
destroy = (ct_destroy_fn)dlsym(h, "mime_content_type_destroy");
if (!parse || !destroy) {
fprintf(stderr, "dlsym: %s\n", dlerror()); _exit(1);
}
int *log_level = (int *)dlsym(h, "log_level");
if (log_level) *log_level = 0;
}
int main(int argc, char **argv) {
if (argc < 2) { fprintf(stderr, "Usage: %s <input>\n", argv[0]); return 1; }
static int init;
if (!init) { load_lib(); init = 1; }
FILE *f = fopen(argv[1], "rb");
if (!f) return 1;
fseek(f, 0, SEEK_END);
long len = ftell(f);
if (len < 0 || len > 64 * 1024) { fclose(f); return 1; }
fseek(f, 0, SEEK_SET);
char *buf = malloc(len + 1);
if (!buf) { fclose(f); return 1; }
size_t n = fread(buf, 1, len, f);
buf[n] = '\0';
fclose(f);
void *ct = parse(buf, 1, (int)n);
if (ct) destroy(ct);
free(buf);
return 0;
}