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