Loading...
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (c) 2022 Google, Inc.
 * Written by Andrew Scull <ascull@google.com>
 */

#include <errno.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#include <os.h>
#include <asm/fuzzing_engine.h>
#include <asm/u-boot-sandbox.h>

static void *fuzzer_thread(void *ptr)
{
	char cmd[64];
	char *argv[5] = {"./u-boot", "-T", "-c", cmd, NULL};
	const char *fuzz_test;

	/* Find which test to run from an environment variable. */
	fuzz_test = getenv("UBOOT_SB_FUZZ_TEST");
	if (!fuzz_test)
		os_abort();

	snprintf(cmd, sizeof(cmd), "fuzz %s", fuzz_test);

	sandbox_main(4, argv);
	os_abort();
	return NULL;
}

static bool fuzzer_initialized;
static pthread_mutex_t fuzzer_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t fuzzer_cond = PTHREAD_COND_INITIALIZER;
static const uint8_t *fuzzer_data;
static size_t fuzzer_size;

int sandbox_fuzzing_engine_get_input(const uint8_t **data, size_t *size)
{
	if (!fuzzer_initialized)
		return -ENOSYS;

	/* Tell the main thread we need new inputs then wait for them. */
	pthread_mutex_lock(&fuzzer_mutex);
	pthread_cond_signal(&fuzzer_cond);
	pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex);
	*data = fuzzer_data;
	*size = fuzzer_size;
	pthread_mutex_unlock(&fuzzer_mutex);
	return 0;
}

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
	static pthread_t tid;

	pthread_mutex_lock(&fuzzer_mutex);

	/* Initialize the sandbox on another thread. */
	if (!fuzzer_initialized) {
		fuzzer_initialized = true;
		if (pthread_create(&tid, NULL, fuzzer_thread, NULL))
			os_abort();
		pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex);
	}

	/* Hand over the input. */
	fuzzer_data = data;
	fuzzer_size = size;
	pthread_cond_signal(&fuzzer_cond);

	/* Wait for the inputs to be finished with. */
	pthread_cond_wait(&fuzzer_cond, &fuzzer_mutex);
	pthread_mutex_unlock(&fuzzer_mutex);

	return 0;
}