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