DragonFlyBSD Kernel Audit
DF-0755 / race_harness_fixed.c
← back to finding ↓ download raw
/*
 * DF-0755 - "fixed" variant of the userspace harness.
 *
 * Identical to race_harness.c except the index increment + wrap are
 * serialized by a pthread spinlock, mirroring the kernel fix.diff which
 * wraps tcp_debx in `struct spinlock tcp_debx_spin` and takes it around
 * `slot = tcp_debx++; if (tcp_debx == TCP_NDEBUG) tcp_debx = 0;`.
 *
 * With the lock, the index is mathematically unable to exceed TCP_NDEBUG-1.
 * Contrast with race_harness.c (no lock) which routinely blows past the
 * bound by millions of slots per run.
 *
 * Build:  cc -O2 -pthread -o race_harness_fixed race_harness_fixed.c
 * Run:    ./race_harness_fixed
 */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define TCP_NDEBUG 100
#define NTHREADS   8
#define ITERS      2000000

static struct { char pad[64]; } tcp_debug[TCP_NDEBUG];
static volatile int tcp_debx = 0;
/* pthread spinlock stands in for the kernel's `struct spinlock`. */
static pthread_spinlock_t tcp_debx_spin;

static volatile int max_idx_seen = 0;
static volatile int oob_count = 0;

static void *
tracer(void *arg)
{
	(void)arg;
	for (long i = 0; i < ITERS; i++) {
		int slot;
		struct { char pad[64]; } *td;

		pthread_spin_lock(&tcp_debx_spin);
		slot = tcp_debx++;
		if (tcp_debx == TCP_NDEBUG)
			tcp_debx = 0;
		pthread_spin_unlock(&tcp_debx_spin);
		td = &tcp_debug[slot];
		(void)td;

		if (slot > max_idx_seen) max_idx_seen = slot;
		if (slot >= TCP_NDEBUG) oob_count++;
	}
	return NULL;
}

int
main(void)
{
	pthread_t th[NTHREADS];
	pthread_spin_init(&tcp_debx_spin, 0);
	for (int i = 0; i < NTHREADS; i++)
		pthread_create(&th[i], NULL, tracer, NULL);
	for (int i = 0; i < NTHREADS; i++)
		pthread_join(th[i], NULL);

	printf("TCP_NDEBUG (array bound) = %d\n", TCP_NDEBUG);
	printf("max slot index used      = %d\n", max_idx_seen);
	printf("OOB writes (slot>=100)   = %d\n", oob_count);
	if (max_idx_seen < TCP_NDEBUG) {
		printf("RESULT: INDEX BOUNDED -- spinlock keeps tcp_debx in [0,99]\n");
		printf("=> fix closes the race; no OOB write possible\n");
		return 0;
	} else {
		printf("RESULT: UNEXPECTED OOB (lock failed?)\n");
		return 1;
	}
}