diff options
Diffstat (limited to 'cddl/contrib/opensolaris/cmd/dtrace/test/cmd/baddof/baddof.c')
-rw-r--r-- | cddl/contrib/opensolaris/cmd/dtrace/test/cmd/baddof/baddof.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/baddof/baddof.c b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/baddof/baddof.c new file mode 100644 index 000000000000..1c14c6592c88 --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/cmd/baddof/baddof.c @@ -0,0 +1,207 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/varargs.h> +#include <errno.h> +#include <math.h> +#include <dtrace.h> + +void +fatal(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + + fprintf(stderr, "%s: ", "baddof"); + vfprintf(stderr, fmt, ap); + + if (fmt[strlen(fmt) - 1] != '\n') + fprintf(stderr, ": %s\n", strerror(errno)); + + exit(1); +} + +#define LEAP_DISTANCE 20 + +void +corrupt(int fd, unsigned char *buf, int len) +{ + static int ttl, valid; + int bit, i; + unsigned char saved; + int val[LEAP_DISTANCE], pos[LEAP_DISTANCE]; + int new, rv; + +again: + printf("valid DOF #%d\n", valid++); + + /* + * We are going iterate through, flipping one bit and attempting + * to enable. + */ + for (bit = 0; bit < len * 8; bit++) { + saved = buf[bit / 8]; + buf[bit / 8] ^= (1 << (bit % 8)); + + if ((bit % 100) == 0) + printf("%d\n", bit); + + if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) == -1) { + /* + * That failed -- restore the bit and drive on. + */ + buf[bit / 8] = saved; + continue; + } + + /* + * That worked -- and it may have enabled probes. To keep + * enabled probes down to a reasonable level, we'll close + * and reopen pseudodevice if we have more than 10,000 + * probes enabled. + */ + ttl += rv; + + if (ttl < 10000) { + buf[bit / 8] = saved; + continue; + } + + printf("enabled %d probes; resetting device.\n", ttl); + close(fd); + + new = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR); + + if (new == -1) + fatal("couldn't open DTrace pseudo device"); + + if (new != fd) { + dup2(new, fd); + close(new); + } + + ttl = 0; + buf[bit / 8] = saved; + } + + for (;;) { + /* + * Now we want to get as many bits away as possible. We flip + * bits randomly -- getting as far away as we can until we don't + * seem to be making any progress. + */ + for (i = 0; i < LEAP_DISTANCE; i++) { + /* + * Pick a random bit and corrupt it. + */ + bit = lrand48() % (len * 8); + + val[i] = buf[bit / 8]; + pos[i] = bit / 8; + buf[bit / 8] ^= (1 << (bit % 8)); + } + + /* + * Let's see if that managed to get us valid DOF... + */ + if ((rv = ioctl(fd, DTRACEIOC_ENABLE, buf)) > 0) { + /* + * Success! This will be our new base for valid DOF. + */ + ttl += rv; + goto again; + } + + /* + * No luck -- we'll restore those bits and try flipping a + * different set. Note that this must be done in reverse + * order... + */ + for (i = LEAP_DISTANCE - 1; i >= 0; i--) + buf[pos[i]] = val[i]; + } +} + +int +main(int argc, char **argv) +{ + char *filename = argv[1]; + dtrace_hdl_t *dtp; + dtrace_prog_t *pgp; + int err, fd, len; + FILE *fp; + unsigned char *dof, *copy; + + if (argc < 2) + fatal("expected D script as argument\n"); + + if ((fp = fopen(filename, "r")) == NULL) + fatal("couldn't open %s", filename); + + /* + * First, we need to compile our provided D into DOF. + */ + if ((dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) { + fatal("cannot open dtrace library: %s\n", + dtrace_errmsg(NULL, err)); + } + + pgp = dtrace_program_fcompile(dtp, fp, 0, 0, NULL); + fclose(fp); + + if (pgp == NULL) { + fatal("failed to compile script %s: %s\n", filename, + dtrace_errmsg(dtp, dtrace_errno(dtp))); + } + + dof = dtrace_dof_create(dtp, pgp, 0); + len = ((dof_hdr_t *)dof)->dofh_loadsz; + + if ((copy = malloc(len)) == NULL) + fatal("could not allocate copy of %d bytes", len); + + for (;;) { + bcopy(dof, copy, len); + /* + * Open another instance of the dtrace device. + */ + fd = open("/devices/pseudo/dtrace@0:dtrace", O_RDWR); + + if (fd == -1) + fatal("couldn't open DTrace pseudo device"); + + corrupt(fd, copy, len); + close(fd); + } + + /* NOTREACHED */ + return (0); +} |