xref: /illumos-gate/usr/src/cmd/dtrace/test/cmd/baddof/baddof.c (revision cb6207858a9fcc2feaee22e626912fba281ac969)
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	"%Z%%M%	%I%	%E% 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 
39 typedef struct dtrace_hdl dtrace_hdl_t;
40 typedef struct dtrace_prog dtrace_prog_t;
41 typedef struct dtrace_vector dtrace_vector_t;
42 typedef int64_t dtrace_aggvarid_t;
43 
44 #define	DTRACEIOC		(('d' << 24) | ('t' << 16) | ('r' << 8))
45 #define	DTRACEIOC_ENABLE	(DTRACEIOC | 6)		/* enable probes */
46 
47 extern dtrace_hdl_t *dtrace_open(int, int, int *);
48 extern dtrace_prog_t *dtrace_program_fcompile(dtrace_hdl_t *,
49     FILE *, uint_t, int, char *const []);
50 extern 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 
54 typedef 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 
66 void
67 fatal(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 
84 void
85 corrupt(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 
93 again:
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 
183 void
184 main(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