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