1178476Sjb/*
2178476Sjb * CDDL HEADER START
3178476Sjb *
4178476Sjb * The contents of this file are subject to the terms of the
5178476Sjb * Common Development and Distribution License (the "License").
6178476Sjb * You may not use this file except in compliance with the License.
7178476Sjb *
8178476Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178476Sjb * or http://www.opensolaris.org/os/licensing.
10178476Sjb * See the License for the specific language governing permissions
11178476Sjb * and limitations under the License.
12178476Sjb *
13178476Sjb * When distributing Covered Code, include this CDDL HEADER in each
14178476Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178476Sjb * If applicable, add the following below this CDDL HEADER, with the
16178476Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17178476Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18178476Sjb *
19178476Sjb * CDDL HEADER END
20178476Sjb */
21178476Sjb
22178476Sjb/*
23210767Srpaulo * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24178476Sjb * Use is subject to license terms.
25178476Sjb */
26178476Sjb
27178476Sjb#include <sys/stat.h>
28178476Sjb#include <stdio.h>
29178476Sjb#include <stdlib.h>
30178476Sjb#include <fcntl.h>
31178476Sjb#include <sys/varargs.h>
32178476Sjb#include <errno.h>
33178476Sjb#include <math.h>
34178476Sjb#include <dtrace.h>
35178476Sjb
36178476Sjbvoid
37178476Sjbfatal(char *fmt, ...)
38178476Sjb{
39178476Sjb	va_list ap;
40178476Sjb
41178476Sjb	va_start(ap, fmt);
42178476Sjb
43178476Sjb	fprintf(stderr, "%s: ", "baddof");
44178476Sjb	vfprintf(stderr, fmt, ap);
45178476Sjb
46178476Sjb	if (fmt[strlen(fmt) - 1] != '\n')
47178476Sjb		fprintf(stderr, ": %s\n", strerror(errno));
48178476Sjb
49178476Sjb	exit(1);
50178476Sjb}
51178476Sjb
52178476Sjb#define	LEAP_DISTANCE		20
53178476Sjb
54178476Sjbvoid
55178476Sjbcorrupt(int fd, unsigned char *buf, int len)
56178476Sjb{
57178476Sjb	static int ttl, valid;
58178476Sjb	int bit, i;
59178476Sjb	unsigned char saved;
60178476Sjb	int val[LEAP_DISTANCE], pos[LEAP_DISTANCE];
61178476Sjb	int new, rv;
62178476Sjb
63178476Sjbagain:
64178476Sjb	printf("valid DOF #%d\n", valid++);
65178476Sjb
66178476Sjb	/*
67178476Sjb	 * We are going iterate through, flipping one bit and attempting
68178476Sjb	 * to enable.
69178476Sjb	 */
70178476Sjb	for (bit = 0; bit < len * 8; bit++) {
71178476Sjb		saved = buf[bit / 8];
72178476Sjb		buf[bit / 8] ^= (1 << (bit % 8));
73178476Sjb
74178476Sjb		if ((bit % 100) == 0)
75178476Sjb			printf("%d\n", bit);
76178476Sjb
77178476Sjb		if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) == -1) {
78178476Sjb			/*
79178476Sjb			 * That failed -- restore the bit and drive on.
80178476Sjb			 */
81178476Sjb			buf[bit / 8] = saved;
82178476Sjb			continue;
83178476Sjb		}
84178476Sjb
85178476Sjb		/*
86178476Sjb		 * That worked -- and it may have enabled probes.  To keep
87178476Sjb		 * enabled probes down to a reasonable level, we'll close
88178476Sjb		 * and reopen pseudodevice if we have more than 10,000
89178476Sjb		 * probes enabled.
90178476Sjb		 */
91178476Sjb		ttl += rv;
92178476Sjb
93178476Sjb		if (ttl < 10000) {
94178476Sjb			buf[bit / 8] = saved;
95178476Sjb			continue;
96178476Sjb		}
97178476Sjb
98178476Sjb		printf("enabled %d probes; resetting device.\n", ttl);
99178476Sjb		close(fd);
100178476Sjb
101178476Sjb		new = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR);
102178476Sjb
103178476Sjb		if (new == -1)
104178476Sjb			fatal("couldn't open DTrace pseudo device");
105178476Sjb
106178476Sjb		if (new != fd) {
107178476Sjb			dup2(new, fd);
108178476Sjb			close(new);
109178476Sjb		}
110178476Sjb
111178476Sjb		ttl = 0;
112178476Sjb		buf[bit / 8] = saved;
113178476Sjb	}
114178476Sjb
115178476Sjb	for (;;) {
116178476Sjb		/*
117178476Sjb		 * Now we want to get as many bits away as possible.  We flip
118178476Sjb		 * bits randomly -- getting as far away as we can until we don't
119178476Sjb		 * seem to be making any progress.
120178476Sjb		 */
121178476Sjb		for (i = 0; i < LEAP_DISTANCE; i++) {
122178476Sjb			/*
123178476Sjb			 * Pick a random bit and corrupt it.
124178476Sjb			 */
125178476Sjb			bit = lrand48() % (len * 8);
126178476Sjb
127178476Sjb			val[i] = buf[bit / 8];
128178476Sjb			pos[i] = bit / 8;
129178476Sjb			buf[bit / 8] ^= (1 << (bit % 8));
130178476Sjb		}
131178476Sjb
132178476Sjb		/*
133178476Sjb		 * Let's see if that managed to get us valid DOF...
134178476Sjb		 */
135178476Sjb		if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) > 0) {
136178476Sjb			/*
137178476Sjb			 * Success!  This will be our new base for valid DOF.
138178476Sjb			 */
139178476Sjb			ttl += rv;
140178476Sjb			goto again;
141178476Sjb		}
142178476Sjb
143178476Sjb		/*
144178476Sjb		 * No luck -- we'll restore those bits and try flipping a
145178476Sjb		 * different set.  Note that this must be done in reverse
146178476Sjb		 * order...
147178476Sjb		 */
148178476Sjb		for (i = LEAP_DISTANCE - 1; i >= 0; i--)
149178476Sjb			buf[pos[i]] = val[i];
150178476Sjb	}
151178476Sjb}
152178476Sjb
153178476Sjbint
154178476Sjbmain(int argc, char **argv)
155178476Sjb{
156178476Sjb	char *filename = argv[1];
157178476Sjb	dtrace_hdl_t *dtp;
158178476Sjb	dtrace_prog_t *pgp;
159178476Sjb	int err, fd, len;
160178476Sjb	FILE *fp;
161178476Sjb	unsigned char *dof, *copy;
162178476Sjb
163210767Srpaulo	if (argc < 2)
164178476Sjb		fatal("expected D script as argument\n");
165178476Sjb
166178476Sjb	if ((fp = fopen(filename, "r")) == NULL)
167178476Sjb		fatal("couldn't open %s", filename);
168178476Sjb
169178476Sjb	/*
170178476Sjb	 * First, we need to compile our provided D into DOF.
171178476Sjb	 */
172178476Sjb	if ((dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
173178476Sjb		fatal("cannot open dtrace library: %s\n",
174178476Sjb		    dtrace_errmsg(NULL, err));
175178476Sjb	}
176178476Sjb
177178476Sjb	pgp = dtrace_program_fcompile(dtp, fp, 0, 0, NULL);
178178476Sjb	fclose(fp);
179178476Sjb
180178476Sjb	if (pgp == NULL) {
181178476Sjb		fatal("failed to compile script %s: %s\n", filename,
182178476Sjb		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
183178476Sjb	}
184178476Sjb
185178476Sjb	dof = dtrace_dof_create(dtp, pgp, 0);
186178476Sjb	len = ((dof_hdr_t *)dof)->dofh_loadsz;
187178476Sjb
188178476Sjb	if ((copy = malloc(len)) == NULL)
189178476Sjb		fatal("could not allocate copy of %d bytes", len);
190178476Sjb
191178476Sjb	for (;;) {
192178476Sjb		bcopy(dof, copy, len);
193178476Sjb		/*
194178476Sjb		 * Open another instance of the dtrace device.
195178476Sjb		 */
196178476Sjb		fd = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR);
197178476Sjb
198178476Sjb		if (fd == -1)
199178476Sjb			fatal("couldn't open DTrace pseudo device");
200178476Sjb
201178476Sjb		corrupt(fd, copy, len);
202178476Sjb		close(fd);
203178476Sjb	}
204178476Sjb
205178476Sjb	/* NOTREACHED */
206178476Sjb	return (0);
207178476Sjb}
208