19512fe8ahl/*
29512fe8ahl * CDDL HEADER START
39512fe8ahl *
49512fe8ahl * The contents of this file are subject to the terms of the
59512fe8ahl * Common Development and Distribution License (the "License").
69512fe8ahl * You may not use this file except in compliance with the License.
79512fe8ahl *
89512fe8ahl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99512fe8ahl * or http://www.opensolaris.org/os/licensing.
109512fe8ahl * See the License for the specific language governing permissions
119512fe8ahl * and limitations under the License.
129512fe8ahl *
139512fe8ahl * When distributing Covered Code, include this CDDL HEADER in each
149512fe8ahl * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159512fe8ahl * If applicable, add the following below this CDDL HEADER, with the
169512fe8ahl * fields enclosed by brackets "[]" replaced with your own identifying
179512fe8ahl * information: Portions Copyright [yyyy] [name of copyright owner]
189512fe8ahl *
199512fe8ahl * CDDL HEADER END
209512fe8ahl */
219512fe8ahl
229512fe8ahl/*
238cb7497Jonathan Haslam * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
249512fe8ahl * Use is subject to license terms.
259512fe8ahl */
269512fe8ahl
279512fe8ahl#include <sys/stat.h>
289512fe8ahl#include <stdio.h>
299512fe8ahl#include <stdlib.h>
309512fe8ahl#include <fcntl.h>
319512fe8ahl#include <sys/varargs.h>
329512fe8ahl#include <errno.h>
339512fe8ahl#include <math.h>
3473427c5ahl#include <dtrace.h>
359512fe8ahl
369512fe8ahlvoid
379512fe8ahlfatal(char *fmt, ...)
389512fe8ahl{
399512fe8ahl	va_list ap;
409512fe8ahl
419512fe8ahl	va_start(ap, fmt);
429512fe8ahl
439512fe8ahl	fprintf(stderr, "%s: ", "baddof");
449512fe8ahl	vfprintf(stderr, fmt, ap);
459512fe8ahl
469512fe8ahl	if (fmt[strlen(fmt) - 1] != '\n')
479512fe8ahl		fprintf(stderr, ": %s\n", strerror(errno));
489512fe8ahl
499512fe8ahl	exit(1);
509512fe8ahl}
519512fe8ahl
529512fe8ahl#define	LEAP_DISTANCE		20
539512fe8ahl
549512fe8ahlvoid
559512fe8ahlcorrupt(int fd, unsigned char *buf, int len)
569512fe8ahl{
579512fe8ahl	static int ttl, valid;
589512fe8ahl	int bit, i;
599512fe8ahl	unsigned char saved;
609512fe8ahl	int val[LEAP_DISTANCE], pos[LEAP_DISTANCE];
619512fe8ahl	int new, rv;
629512fe8ahl
639512fe8ahlagain:
649512fe8ahl	printf("valid DOF #%d\n", valid++);
659512fe8ahl
669512fe8ahl	/*
679512fe8ahl	 * We are going iterate through, flipping one bit and attempting
689512fe8ahl	 * to enable.
699512fe8ahl	 */
709512fe8ahl	for (bit = 0; bit < len * 8; bit++) {
719512fe8ahl		saved = buf[bit / 8];
729512fe8ahl		buf[bit / 8] ^= (1 << (bit % 8));
739512fe8ahl
749512fe8ahl		if ((bit % 100) == 0)
759512fe8ahl			printf("%d\n", bit);
769512fe8ahl
779512fe8ahl		if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) == -1) {
789512fe8ahl			/*
799512fe8ahl			 * That failed -- restore the bit and drive on.
809512fe8ahl			 */
819512fe8ahl			buf[bit / 8] = saved;
829512fe8ahl			continue;
839512fe8ahl		}
849512fe8ahl
859512fe8ahl		/*
869512fe8ahl		 * That worked -- and it may have enabled probes.  To keep
879512fe8ahl		 * enabled probes down to a reasonable level, we'll close
889512fe8ahl		 * and reopen pseudodevice if we have more than 10,000
899512fe8ahl		 * probes enabled.
909512fe8ahl		 */
919512fe8ahl		ttl += rv;
929512fe8ahl
939512fe8ahl		if (ttl < 10000) {
949512fe8ahl			buf[bit / 8] = saved;
959512fe8ahl			continue;
969512fe8ahl		}
979512fe8ahl
989512fe8ahl		printf("enabled %d probes; resetting device.\n", ttl);
999512fe8ahl		close(fd);
1009512fe8ahl
1019512fe8ahl		new = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR);
1029512fe8ahl
1039512fe8ahl		if (new == -1)
1049512fe8ahl			fatal("couldn't open DTrace pseudo device");
1059512fe8ahl
1069512fe8ahl		if (new != fd) {
1079512fe8ahl			dup2(new, fd);
1089512fe8ahl			close(new);
1099512fe8ahl		}
1109512fe8ahl
1119512fe8ahl		ttl = 0;
1129512fe8ahl		buf[bit / 8] = saved;
1139512fe8ahl	}
1149512fe8ahl
1159512fe8ahl	for (;;) {
1169512fe8ahl		/*
1179512fe8ahl		 * Now we want to get as many bits away as possible.  We flip
1189512fe8ahl		 * bits randomly -- getting as far away as we can until we don't
1199512fe8ahl		 * seem to be making any progress.
1209512fe8ahl		 */
1219512fe8ahl		for (i = 0; i < LEAP_DISTANCE; i++) {
1229512fe8ahl			/*
1239512fe8ahl			 * Pick a random bit and corrupt it.
1249512fe8ahl			 */
1259512fe8ahl			bit = lrand48() % (len * 8);
1269512fe8ahl
1279512fe8ahl			val[i] = buf[bit / 8];
1289512fe8ahl			pos[i] = bit / 8;
1299512fe8ahl			buf[bit / 8] ^= (1 << (bit % 8));
1309512fe8ahl		}
1319512fe8ahl
1329512fe8ahl		/*
1339512fe8ahl		 * Let's see if that managed to get us valid DOF...
1349512fe8ahl		 */
1359512fe8ahl		if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) > 0) {
1369512fe8ahl			/*
1379512fe8ahl			 * Success!  This will be our new base for valid DOF.
1389512fe8ahl			 */
1399512fe8ahl			ttl += rv;
1409512fe8ahl			goto again;
1419512fe8ahl		}
1429512fe8ahl
1439512fe8ahl		/*
1449512fe8ahl		 * No luck -- we'll restore those bits and try flipping a
1459512fe8ahl		 * different set.  Note that this must be done in reverse
1469512fe8ahl		 * order...
1479512fe8ahl		 */
1489512fe8ahl		for (i = LEAP_DISTANCE - 1; i >= 0; i--)
1499512fe8ahl			buf[pos[i]] = val[i];
1509512fe8ahl	}
1519512fe8ahl}
1529512fe8ahl
1534fe0161rafint
1549512fe8ahlmain(int argc, char **argv)
1559512fe8ahl{
1569512fe8ahl	char *filename = argv[1];
1579512fe8ahl	dtrace_hdl_t *dtp;
1589512fe8ahl	dtrace_prog_t *pgp;
1599512fe8ahl	int err, fd, len;
1609512fe8ahl	FILE *fp;
1619512fe8ahl	unsigned char *dof, *copy;
1629512fe8ahl
1638cb7497Jonathan Haslam	if (argc < 2)
1649512fe8ahl		fatal("expected D script as argument\n");
1659512fe8ahl
1669512fe8ahl	if ((fp = fopen(filename, "r")) == NULL)
1679512fe8ahl		fatal("couldn't open %s", filename);
1689512fe8ahl
1699512fe8ahl	/*
1709512fe8ahl	 * First, we need to compile our provided D into DOF.
1719512fe8ahl	 */
1729512fe8ahl	if ((dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
1739512fe8ahl		fatal("cannot open dtrace library: %s\n",
1749512fe8ahl		    dtrace_errmsg(NULL, err));
1759512fe8ahl	}
1769512fe8ahl
1779512fe8ahl	pgp = dtrace_program_fcompile(dtp, fp, 0, 0, NULL);
1789512fe8ahl	fclose(fp);
1799512fe8ahl
1809512fe8ahl	if (pgp == NULL) {
1819512fe8ahl		fatal("failed to compile script %s: %s\n", filename,
1829512fe8ahl		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
1839512fe8ahl	}
1849512fe8ahl
18573427c5ahl	dof = dtrace_dof_create(dtp, pgp, 0);
1869512fe8ahl	len = ((dof_hdr_t *)dof)->dofh_loadsz;
1879512fe8ahl
1889512fe8ahl	if ((copy = malloc(len)) == NULL)
1899512fe8ahl		fatal("could not allocate copy of %d bytes", len);
1909512fe8ahl
1919512fe8ahl	for (;;) {
1929512fe8ahl		bcopy(dof, copy, len);
1939512fe8ahl		/*
1949512fe8ahl		 * Open another instance of the dtrace device.
1959512fe8ahl		 */
1969512fe8ahl		fd = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR);
1979512fe8ahl
1989512fe8ahl		if (fd == -1)
1999512fe8ahl			fatal("couldn't open DTrace pseudo device");
2009512fe8ahl
2019512fe8ahl		corrupt(fd, copy, len);
2029512fe8ahl		close(fd);
2039512fe8ahl	}
2044fe0161raf
2054fe0161raf	/* NOTREACHED */
2064fe0161raf	return (0);
2079512fe8ahl}
208