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 2007 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 #include <dtrace.h> 37 38 void 39 fatal(char *fmt, ...) 40 { 41 va_list ap; 42 43 va_start(ap, fmt); 44 45 fprintf(stderr, "%s: ", "baddof"); 46 vfprintf(stderr, fmt, ap); 47 48 if (fmt[strlen(fmt) - 1] != '\n') 49 fprintf(stderr, ": %s\n", strerror(errno)); 50 51 exit(1); 52 } 53 54 #define LEAP_DISTANCE 20 55 56 void 57 corrupt(int fd, unsigned char *buf, int len) 58 { 59 static int ttl, valid; 60 int bit, i; 61 unsigned char saved; 62 int val[LEAP_DISTANCE], pos[LEAP_DISTANCE]; 63 int new, rv; 64 65 again: 66 printf("valid DOF #%d\n", valid++); 67 68 /* 69 * We are going iterate through, flipping one bit and attempting 70 * to enable. 71 */ 72 for (bit = 0; bit < len * 8; bit++) { 73 saved = buf[bit / 8]; 74 buf[bit / 8] ^= (1 << (bit % 8)); 75 76 if ((bit % 100) == 0) 77 printf("%d\n", bit); 78 79 if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) == -1) { 80 /* 81 * That failed -- restore the bit and drive on. 82 */ 83 buf[bit / 8] = saved; 84 continue; 85 } 86 87 /* 88 * That worked -- and it may have enabled probes. To keep 89 * enabled probes down to a reasonable level, we'll close 90 * and reopen pseudodevice if we have more than 10,000 91 * probes enabled. 92 */ 93 ttl += rv; 94 95 if (ttl < 10000) { 96 buf[bit / 8] = saved; 97 continue; 98 } 99 100 printf("enabled %d probes; resetting device.\n", ttl); 101 close(fd); 102 103 new = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR); 104 105 if (new == -1) 106 fatal("couldn't open DTrace pseudo device"); 107 108 if (new != fd) { 109 dup2(new, fd); 110 close(new); 111 } 112 113 ttl = 0; 114 buf[bit / 8] = saved; 115 } 116 117 for (;;) { 118 /* 119 * Now we want to get as many bits away as possible. We flip 120 * bits randomly -- getting as far away as we can until we don't 121 * seem to be making any progress. 122 */ 123 for (i = 0; i < LEAP_DISTANCE; i++) { 124 /* 125 * Pick a random bit and corrupt it. 126 */ 127 bit = lrand48() % (len * 8); 128 129 val[i] = buf[bit / 8]; 130 pos[i] = bit / 8; 131 buf[bit / 8] ^= (1 << (bit % 8)); 132 } 133 134 /* 135 * Let's see if that managed to get us valid DOF... 136 */ 137 if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) > 0) { 138 /* 139 * Success! This will be our new base for valid DOF. 140 */ 141 ttl += rv; 142 goto again; 143 } 144 145 /* 146 * No luck -- we'll restore those bits and try flipping a 147 * different set. Note that this must be done in reverse 148 * order... 149 */ 150 for (i = LEAP_DISTANCE - 1; i >= 0; i--) 151 buf[pos[i]] = val[i]; 152 } 153 } 154 155 int 156 main(int argc, char **argv) 157 { 158 char *filename = argv[1]; 159 dtrace_hdl_t *dtp; 160 dtrace_prog_t *pgp; 161 int err, fd, len; 162 FILE *fp; 163 unsigned char *dof, *copy; 164 165 if (argc < 1) 166 fatal("expected D script as argument\n"); 167 168 if ((fp = fopen(filename, "r")) == NULL) 169 fatal("couldn't open %s", filename); 170 171 /* 172 * First, we need to compile our provided D into DOF. 173 */ 174 if ((dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) { 175 fatal("cannot open dtrace library: %s\n", 176 dtrace_errmsg(NULL, err)); 177 } 178 179 pgp = dtrace_program_fcompile(dtp, fp, 0, 0, NULL); 180 fclose(fp); 181 182 if (pgp == NULL) { 183 fatal("failed to compile script %s: %s\n", filename, 184 dtrace_errmsg(dtp, dtrace_errno(dtp))); 185 } 186 187 dof = dtrace_dof_create(dtp, pgp, 0); 188 len = ((dof_hdr_t *)dof)->dofh_loadsz; 189 190 if ((copy = malloc(len)) == NULL) 191 fatal("could not allocate copy of %d bytes", len); 192 193 for (;;) { 194 bcopy(dof, copy, len); 195 /* 196 * Open another instance of the dtrace device. 197 */ 198 fd = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR); 199 200 if (fd == -1) 201 fatal("couldn't open DTrace pseudo device"); 202 203 corrupt(fd, copy, len); 204 close(fd); 205 } 206 207 /* NOTREACHED */ 208 return (0); 209 } 210