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