1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"@(#)baddof.c	1.1	06/08/28 SMI"
28
29#include <sys/stat.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <fcntl.h>
33#include <sys/varargs.h>
34#include <errno.h>
35#include <math.h>
36
37#define	DTRACE_VERSION	1
38
39typedef struct dtrace_hdl dtrace_hdl_t;
40typedef struct dtrace_prog dtrace_prog_t;
41typedef struct dtrace_vector dtrace_vector_t;
42typedef int64_t dtrace_aggvarid_t;
43
44#define	DTRACEIOC		(('d' << 24) | ('t' << 16) | ('r' << 8))
45#define	DTRACEIOC_ENABLE	(DTRACEIOC | 6)		/* enable probes */
46
47extern dtrace_hdl_t *dtrace_open(int, int, int *);
48extern dtrace_prog_t *dtrace_program_fcompile(dtrace_hdl_t *,
49    FILE *, uint_t, int, char *const []);
50extern void *dtrace_program_dof(dtrace_hdl_t *, dtrace_prog_t *, uint_t);
51
52#define	DOF_ID_SIZE	16	/* total size of dofh_ident[] in bytes */
53
54typedef struct dof_hdr {
55	uint8_t dofh_ident[DOF_ID_SIZE]; /* identification bytes (see below) */
56	uint32_t dofh_flags;		/* file attribute flags (if any) */
57	uint32_t dofh_hdrsize;		/* size of file header in bytes */
58	uint32_t dofh_secsize;		/* size of section header in bytes */
59	uint32_t dofh_secnum;		/* number of section headers */
60	uint64_t dofh_secoff;		/* file offset of section headers */
61	uint64_t dofh_loadsz;		/* file size of loadable portion */
62	uint64_t dofh_filesz;		/* file size of entire DOF file */
63	uint64_t dofh_pad;		/* reserved for future use */
64} dof_hdr_t;
65
66void
67fatal(char *fmt, ...)
68{
69	va_list ap;
70
71	va_start(ap, fmt);
72
73	fprintf(stderr, "%s: ", "baddof");
74	vfprintf(stderr, fmt, ap);
75
76	if (fmt[strlen(fmt) - 1] != '\n')
77		fprintf(stderr, ": %s\n", strerror(errno));
78
79	exit(1);
80}
81
82#define	LEAP_DISTANCE		20
83
84void
85corrupt(int fd, unsigned char *buf, int len)
86{
87	static int ttl, valid;
88	int bit, i;
89	unsigned char saved;
90	int val[LEAP_DISTANCE], pos[LEAP_DISTANCE];
91	int new, rv;
92
93again:
94	printf("valid DOF #%d\n", valid++);
95
96	/*
97	 * We are going iterate through, flipping one bit and attempting
98	 * to enable.
99	 */
100	for (bit = 0; bit < len * 8; bit++) {
101		saved = buf[bit / 8];
102		buf[bit / 8] ^= (1 << (bit % 8));
103
104		if ((bit % 100) == 0)
105			printf("%d\n", bit);
106
107		if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) == -1) {
108			/*
109			 * That failed -- restore the bit and drive on.
110			 */
111			buf[bit / 8] = saved;
112			continue;
113		}
114
115		/*
116		 * That worked -- and it may have enabled probes.  To keep
117		 * enabled probes down to a reasonable level, we'll close
118		 * and reopen pseudodevice if we have more than 10,000
119		 * probes enabled.
120		 */
121		ttl += rv;
122
123		if (ttl < 10000) {
124			buf[bit / 8] = saved;
125			continue;
126		}
127
128		printf("enabled %d probes; resetting device.\n", ttl);
129		close(fd);
130
131		new = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR);
132
133		if (new == -1)
134			fatal("couldn't open DTrace pseudo device");
135
136		if (new != fd) {
137			dup2(new, fd);
138			close(new);
139		}
140
141		ttl = 0;
142		buf[bit / 8] = saved;
143	}
144
145	for (;;) {
146		/*
147		 * Now we want to get as many bits away as possible.  We flip
148		 * bits randomly -- getting as far away as we can until we don't
149		 * seem to be making any progress.
150		 */
151		for (i = 0; i < LEAP_DISTANCE; i++) {
152			/*
153			 * Pick a random bit and corrupt it.
154			 */
155			bit = lrand48() % (len * 8);
156
157			val[i] = buf[bit / 8];
158			pos[i] = bit / 8;
159			buf[bit / 8] ^= (1 << (bit % 8));
160		}
161
162		/*
163		 * Let's see if that managed to get us valid DOF...
164		 */
165		if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) > 0) {
166			/*
167			 * Success!  This will be our new base for valid DOF.
168			 */
169			ttl += rv;
170			goto again;
171		}
172
173		/*
174		 * No luck -- we'll restore those bits and try flipping a
175		 * different set.  Note that this must be done in reverse
176		 * order...
177		 */
178		for (i = LEAP_DISTANCE - 1; i >= 0; i--)
179			buf[pos[i]] = val[i];
180	}
181}
182
183void
184main(int argc, char **argv)
185{
186	char *filename = argv[1];
187	dtrace_hdl_t *dtp;
188	dtrace_prog_t *pgp;
189	int err, fd, len;
190	FILE *fp;
191	unsigned char *dof, *copy;
192
193	if (argc < 1)
194		fatal("expected D script as argument\n");
195
196	if ((fp = fopen(filename, "r")) == NULL)
197		fatal("couldn't open %s", filename);
198
199	/*
200	 * First, we need to compile our provided D into DOF.
201	 */
202	if ((dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) {
203		fatal("cannot open dtrace library: %s\n",
204		    dtrace_errmsg(NULL, err));
205	}
206
207	pgp = dtrace_program_fcompile(dtp, fp, 0, 0, NULL);
208	fclose(fp);
209
210	if (pgp == NULL) {
211		fatal("failed to compile script %s: %s\n", filename,
212		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
213	}
214
215	dof = dtrace_program_dof(dtp, pgp, 0);
216	len = ((dof_hdr_t *)dof)->dofh_loadsz;
217
218	if ((copy = malloc(len)) == NULL)
219		fatal("could not allocate copy of %d bytes", len);
220
221	for (;;) {
222		bcopy(dof, copy, len);
223		/*
224		 * Open another instance of the dtrace device.
225		 */
226		fd = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR);
227
228		if (fd == -1)
229			fatal("couldn't open DTrace pseudo device");
230
231		corrupt(fd, copy, len);
232		close(fd);
233	}
234}
235