penguin/tinyproxy

An L4 proxy designed to act as a tiny transparent shim

fuzz/fuzz_file_conf.c

raw ยท 1966 bytes

#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include "file_conf.h"

static void check_endpoint(const struct endpoint *ep)
{
	switch (ep->kind) {
	case ENDPOINT_INET:
		if (ep->port == 0) {
			abort();
		}
		if (ep->host[0] == '\0') {
			abort();
		}
		break;

	case ENDPOINT_UNIX:
	case ENDPOINT_UNIX_DGRAM:
		if (ep->path[0] == '\0') {
			abort();
		}
		break;

	default:
		abort();
	}
}

static void check_route(const struct route *r)
{
	check_endpoint(&r->listen);
	check_endpoint(&r->upstream);

	switch (r->proto) {
	case PROTO_TCP:
	case PROTO_UDP:
		break;
	default:
		abort();
	}

	if (r->line_no == 0) {
		abort();
	}

	if (r->opts.idle_timeout_sec <= 0) {
		abort();
	}

	if (r->opts.connect_timeout_sec <= 0) {
		abort();
	}
}

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
	/*
	 * Keep the fuzzer fast. file_conf.c has MAX_LINE_LEN=512, so this is
	 * already enough to exercise normal, multiline, and overlong cases.
	 */
	if (size > 8192) {
		return 0;
	}

	char path[] = "/tmp/tinyproxy-file-conf-fuzz-XXXXXX";
	int fd = mkstemp(path);
	if (fd < 0) {
		return 0;
	}

	size_t off = 0;
	while (off < size) {
		ssize_t n = write(fd, data + off, size - off);
		if (n < 0) {
			if (errno == EINTR) {
				continue;
			}

			close(fd);
			unlink(path);
			return 0;
		}

		if (n == 0) {
			break;
		}

		off += (size_t)n;
	}

	close(fd);

	struct route *routes = NULL;
	size_t count = 0;

	int rc = load_routes_from_file(path, &routes, &count);

	unlink(path);

	if (rc == 0) {
		if (count > 0 && routes == NULL) {
			abort();
		}

		for (size_t i = 0; i < count; i++) {
			check_route(&routes[i]);
		}

		free_routes(routes);
	} else {
		/*
		 * On failure, load_routes_from_file() should not transfer ownership.
		 * Keep this loose because callers should not rely on output values
		 * after error unless the API explicitly promises that.
		 */
	}

	return 0;
}