⬢ DragonFlyBSD Kernel Audit
DF-2296 / fwhctl.c
← back to finding ↓ download raw
/*
 * fwhctl.c -- root-only control helper for the fwdev.c verification
 * harness (/dev/fwhctl0).  Emulates the FireWire peer / OHCI hardware:
 *
 *   fwhctl maxrec N      set fabricated fc->maxrec (10=S400, 11=S800)
 *   fwhctl inject LEN    inject received iso packet with stream.len=LEN
 *   fwhctl spray N SIZE  spray N x SIZE canary chunks (mixed-size zone)
 *   fwhctl unspray       free sprayed chunks
 *   fwhctl resp L F      emulate peer block response of L bytes, fill F
 *   fwhctl spraychk      report canary corruption (kernel dmesg + exit)
 *   fwhctl dump FILE     dump the captured "wire" payload to FILE
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdint.h>

#include "fwharness.h"

int
main(int argc, char **argv)
{
	struct fwh_sprayreq sr;
	struct fwh_respreq rr;
	struct fwh_chkreq cr;
	u_int32_t v;
	int fd;

	if (argc < 2) {
		fprintf(stderr, "usage: fwhctl maxrec N | inject LEN | "
		    "spray N SIZE | unspray | resp L F | spraychk | "
		    "dump FILE\n");
		return 2;
	}
	fd = open("/dev/fwhctl0", O_RDWR);
	if (fd < 0) { perror("open /dev/fwhctl0"); return 1; }

	if (strcmp(argv[1], "maxrec") == 0) {
		v = (u_int32_t)strtoul(argv[2], NULL, 0);
		if (ioctl(fd, FWHIOC_MAXREC, &v) != 0) { perror("ioctl"); return 1; }
	} else if (strcmp(argv[1], "inject") == 0) {
		v = (u_int32_t)strtoul(argv[2], NULL, 0);
		if (ioctl(fd, FWHIOC_INJECT, &v) != 0) { perror("ioctl"); return 1; }
	} else if (strcmp(argv[1], "spray") == 0) {
		sr.n = (u_int32_t)strtoul(argv[2], NULL, 0);
		sr.size = (u_int32_t)strtoul(argv[3], NULL, 0);
		if (ioctl(fd, FWHIOC_SPRAY, &sr) != 0) { perror("ioctl"); return 1; }
	} else if (strcmp(argv[1], "unspray") == 0) {
		ioctl(fd, FWHIOC_UNSPRAY, &v);
	} else if (strcmp(argv[1], "resp") == 0) {
		rr.paylen = (u_int32_t)strtoul(argv[2], NULL, 0);
		rr.fill = (u_int32_t)strtoul(argv[3], NULL, 0);
		if (ioctl(fd, FWHIOC_RESP, &rr) != 0) { perror("ioctl"); return 1; }
	} else if (strcmp(argv[1], "spraychk") == 0) {
		memset(&cr, 0, sizeof(cr));
		if (ioctl(fd, FWHIOC_SPRAYCHK, &cr) != 0) { perror("ioctl"); return 1; }
		printf("fwhctl: spraychk corrupt=%u badwords=%u\n",
		    cr.corrupt, cr.badwords);
		return (cr.corrupt ? 3 : 0);
	} else if (strcmp(argv[1], "spraypop") == 0) {
		if (ioctl(fd, FWHIOC_SPRAYPOP, &v) != 0) { perror("ioctl"); return 1; }
	} else if (strcmp(argv[1], "sprayfree") == 0) {
		v = (u_int32_t)strtoul(argv[2], NULL, 0);
		if (ioctl(fd, FWHIOC_SPRAYFREE, &v) != 0) { perror("ioctl"); return 1; }
	} else if (strcmp(argv[1], "spraydump") == 0) {
		static struct fwh_dumpreq dr;
		FILE *out;
		u_int i, j;
		dr.start = (argc > 3) ? strtoul(argv[3], NULL, 0) : 0;
		dr.n = FWH_DUMP_CHUNKS;
		if (ioctl(fd, FWHIOC_SPRAYDUMP, &dr) != 0) { perror("ioctl"); return 1; }
		out = fopen(argv[2], "w");
		if (out == NULL) { perror(argv[2]); return 1; }
		for (i = 0; i < dr.n; i++) {
			fprintf(out, "chunk %u size %u\n",
			    dr.chunk[i].idx, dr.chunk[i].size);
			for (j = 0; j < FWH_DUMP_HDR / 4; j++) {
				if ((j % 4) == 0) fprintf(out, "  %04x:", j * 4);
				fprintf(out, " %08x", dr.chunk[i].data[j]);
				if ((j % 4) == 3) fprintf(out, "\n");
			}
		}
		fclose(out);
		printf("fwhctl: dumped %u spray chunks to %s\n", dr.n, argv[2]);
	} else if (strcmp(argv[1], "dump") == 0) {
		static u_char buf[256 * 1024];
		int out, n;
		n = read(fd, buf, sizeof(buf));
		if (n <= 0) { perror("read"); return 1; }
		out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
		if (out < 0) { perror(argv[2]); return 1; }
		if (write(out, buf, n) != n) { perror("write"); return 1; }
		close(out);
		printf("fwhctl: dumped %d bytes to %s\n", n, argv[2]);
	} else {
		fprintf(stderr, "unknown op %s\n", argv[1]);
		return 2;
	}
	return 0;
}