diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2017-08-28 18:32:41 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2017-08-29 15:27:31 +0100 |
commit | 51fc224d19b7aab6c6e39843a258b0b10482ce6e (patch) | |
tree | 878fc1c0f7fa91979b811fd580dfdb6da1f8036c | |
parent | f55234c41fd94116caf7b6ea03bd008cd315e7c5 (diff) |
fixafl
-rw-r--r-- | afl/Makefile | 16 | ||||
-rw-r--r-- | afl/byte-afl.c | 76 | ||||
-rw-r--r-- | afl/byte-decompile.c | 173 | ||||
-rw-r--r-- | afl/byte-kcov.c (renamed from afl/byte-server.c) | 26 | ||||
-rw-r--r-- | afl/bytecode.c | 76 | ||||
-rw-r--r-- | afl/bytecode.h | 8 | ||||
-rw-r--r-- | afl/i915_driver.c | 2 | ||||
-rw-r--r-- | afl/i915_object.c | 78 |
8 files changed, 412 insertions, 43 deletions
diff --git a/afl/Makefile b/afl/Makefile index 6a14378c..7aef8fbf 100644 --- a/afl/Makefile +++ b/afl/Makefile @@ -1,4 +1,4 @@ -CFLAGS := -Wall -fPIC -g +CFLAGS := -Wall -fPIC -g3 -O0 DRIVERS := \ drm_crtc.o drm_driver.o drm_framebuffer.o drm_object.o \ @@ -8,10 +8,16 @@ DRIVERS := \ i915.so \ vgem.so -byte-server: byte-server.o afl.o kcov.o kmod.o bytecode.o ${DRIVERS} +byte-kcov: byte-kcov.o afl.o kcov.o kmod.o bytecode.o ${DRIVERS} $(CC) -o $@ $^ -lm -lkmod -Wl,-rpath=$(shell pwd) - sudo chown root:root byte-server - sudo chmod u+s byte-server + sudo chown root:root byte-kcov + sudo chmod u+s byte-kcov + +byte-afl: byte-afl.o kmod.o bytecode.o ${DRIVERS} + $(CC) -o $@ $^ -lm -lkmod -Wl,-rpath=$(shell pwd) + +byte-decompile: byte-decompile.o + $(CC) -o $@ $^ i915.so: \ i915_context.o \ @@ -26,4 +32,4 @@ vgem.so: vgem_driver.o $(CC) -shared -o $@ $^ clean: - rm -f *.o *.so byte-server + rm -f *.o *.so byte-kcov byte-afl diff --git a/afl/byte-afl.c b/afl/byte-afl.c new file mode 100644 index 00000000..308b35b4 --- /dev/null +++ b/afl/byte-afl.c @@ -0,0 +1,76 @@ +#include <assert.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "afl.h" +#include "bytecode.h" +#include "driver_factory.h" +#include "kcov.h" + +static unsigned int lookup_driver_atom(const char *name) +{ + const unsigned int DRIVER_ATOM = 0; + static const char *drivers[] = { + "i915", + "vgem", + NULL, + }; + const char **driver; + + for (driver = drivers; *driver; driver++) + if (!strcmp(*driver, name)) + return DRIVER_ATOM + (driver - drivers); + + return -1; +} + +static int run(int fd) +{ + struct drm_driver *drv[16]; + struct byte_vm b; + int i, count; + + if (byte_open(&b, fd, 2048)) + return -77; + + for (i = count = 0; i < 16; i++) { + char path[128]; + int fd; + + snprintf(path, sizeof(path), "/dev/dri/card%d", i); + fd = open(path, O_RDWR); + if (fd < 0) + continue; + + drv[count] = driver_factory_create(fd); + if (!drv[count]) { + close(fd); + continue; + } + + byte_add_global_object(&b, + drv[count]->name, + lookup_driver_atom(drv[count]->name), + &drv[count]->byte); + count++; + } + + return byte_run(&b); +} + +int main(int argc, char **argv) +{ + int fd = 0; + + if (argc > 1) { + fd = open(argv[1], O_RDONLY); + if (fd < 0) + return 127; + } + + return !!run(fd); +} diff --git a/afl/byte-decompile.c b/afl/byte-decompile.c new file mode 100644 index 00000000..88b0f374 --- /dev/null +++ b/afl/byte-decompile.c @@ -0,0 +1,173 @@ +#include <ctype.h> +#include <errno.h> +#include <math.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "compiler.h" + +typedef union { + uint64_t enc; + double value; +} real __attribute__ ((__transparent_union__)); + + +static uint8_t __get8(FILE *in) +{ + return fgetc(in); +} + +static uint16_t __get16(FILE *in) +{ + return __get8(in) | (uint16_t)__get8(in) << 8; +} + +static uint32_t __get32(FILE *in) +{ + return __get16(in) | (uint32_t)__get16(in) << 16; +} + +static uint64_t __get64(FILE *in) +{ + return __get32(in) | (uint64_t)__get32(in) << 32; +} + +static void print_string(unsigned int len, FILE *in, FILE *out) +{ + fprintf(out, "("); + while (len--) { + int c = fgetc(in); + if (c == EOF) + break; + else if (isprint(c)) + fprintf(out, "%c", c); + else + fprintf(out, "\\x%x", (uint8_t)c); + } + fprintf(out, ") "); +} + +static void decompile(FILE *in, FILE *out) +{ + static const void *tbl[256] = { + [0 ... 255] = &&illegal, + + [0 ... 64] = &&smallint, + [(uint8_t)-64 ... 255] = &&smallint, + + [65 ... 79] = &&smallpot, + + /* 80+ -> integer types */ + &&u8, + &&u16, + &&u32, + &&u64, + + /* floating point types */ + &&real, + + /* strings */ + &&string8, + &&string16, + &&string32, + + /* stack manipulation */ + &&pop, + &&roll, + &&index, + &&dup, + &&xchg, + &©, + &&clear, + + /* functions */ + &&call, + }; + int code; + +next: + code = fgetc(in); + if (code == EOF) { + fprintf(out, "\n"); + return; + } + + goto *tbl[code]; + +illegal: + return; + +smallint: + fprintf(out, "%d ", (int8_t)code); + goto next; + +smallpot: + fprintf(out, "0x%lx ", 1ul << (code - 64 + 6)); + goto next; + +u8: + fprintf(out, "0x%x ", __get8(in)); + goto next; + +u16: + fprintf(out, "0x%x ", __get16(in)); + goto next; + +u32: + fprintf(out, "0x%x ", __get32(in)); + goto next; + +u64: + fprintf(out, "0x%llx ", (long long)__get64(in)); + goto next; + +real: + fprintf(out, "%f ", ((real){ .enc = __get64(in) }).value); + goto next; + +string8: + print_string(__get8(in), in, out); + goto next; + +string16: + print_string(__get16(in), in, out); + goto next; + +string32: + print_string(__get32(in), in, out); + goto next; + +pop: + fprintf(out, "pop "); + goto next; +roll: + fprintf(out, "roll "); + goto next; +index: + fprintf(out, "index "); + goto next; +dup: + fprintf(out, "dup "); + goto next; +xchg: + fprintf(out, "xchg "); + goto next; +copy: + fprintf(out, "copy "); + goto next; +clear: + fprintf(out, "clear "); + goto next; +call: + fprintf(out, "call "); + goto next; +} + +int main(int argc, char **argv) +{ + decompile(stdin, stdout); +} diff --git a/afl/byte-server.c b/afl/byte-kcov.c index 423d9fb6..545f5861 100644 --- a/afl/byte-server.c +++ b/afl/byte-kcov.c @@ -28,18 +28,13 @@ static unsigned int lookup_driver_atom(const char *name) return -1; } -int main(void) +int main(int argc, char **argv) { struct drm_driver *drv[16]; struct byte_vm b; struct kcov kcov; int i, count; - if (kcov_open(&kcov)) { - fprintf(stderr, "Unable to open kcov\n"); - return -77; - } - if (byte_open(&b, 0 /* read from stdin */, 2048)) return -77; @@ -65,6 +60,25 @@ int main(void) count++; } + if (argc > 1) { + for (i = 1; i < argc; i++) { + int fd = open(argv[i], O_RDONLY); + if (fd < 0) + continue; + + b.fd = fd; + byte_run(&b); + close(b.fd); + } + + return 0; + } + + if (kcov_open(&kcov)) { + fprintf(stderr, "Unable to open kcov\n"); + return -77; + } + while (afl_persistent_loop(INT_MAX)) { for (i = 0; i < count; i++) drv[i]->ops->reset(drv[i]); diff --git a/afl/bytecode.c b/afl/bytecode.c index 9a7ca549..f0e7aee5 100644 --- a/afl/bytecode.c +++ b/afl/bytecode.c @@ -63,10 +63,11 @@ enum type { static void stack_push(struct byte_vm *b, uint64_t datum) { if (unlikely(b->top == b->size)) { - b->size *= 2; - b->stack = realloc(b->stack, b->size * sizeof(uint64_t)); + unsigned long sz = b->size * 2; + b->stack = realloc(b->stack, sz * sizeof(uint64_t)); if (!b->stack) longjmp(b->exit, -ENOSPC); + b->size = sz; } b->stack[b->top++] = datum; @@ -108,7 +109,11 @@ static void stack_push_real(struct byte_vm *b, real datum) { double *value; - if (datum.value < UINT32_MAX && floor(datum.value) == datum.value) { + if (isnan(datum.value)) + longjmp(b->exit, -EDOM); + + if (fabs(datum.value) < INT32_MAX && + floor(datum.value) == datum.value) { stack_push(b, datum.value); return; } @@ -167,17 +172,31 @@ static void stack_push_string(struct byte_vm *b, unsigned int len) if (b->b + len <= b->end) { memcpy(s->str, b->b, len); b->b += len; - s->str[len] = '\0'; } else { - unsigned this = b->end - b->b; + unsigned int this = b->end - b->b; + unsigned int rem = len - this; + memcpy(s->str, b->b, this); b->b = b->end; - len -= this; - if (read(b->fd, s->str + this, len) < len) - longjmp(b->exit, -EINVAL); - s->str[len + this] = '\0'; + do { + int ret; + + ret = read(b->fd, s->str + this, rem); + if (ret == 0) + longjmp(b->exit, -EINVAL); + if (ret < 0) { + int err = errno; + if (err == EAGAIN || err == EINTR) + continue; + longjmp(b->exit, -err); + } + + rem -= ret; + this += ret; + } while (rem); } + s->str[len] = '\0'; stack_push(b, set_type(s, STRING)); } @@ -185,7 +204,7 @@ static void stack_push_string(struct byte_vm *b, unsigned int len) static void *u64_to_pointer(uint64_t v) { v <<= 4; /* clear type bits */ - v = ((int64_t)v >> 4); /* replace with signbit */ + v = (int64_t)v >> 4; /* replace with signbit */ return (void *)(uintptr_t)v; } @@ -266,7 +285,7 @@ static int stack_get_int(struct byte_vm *b) v = b->stack[--b->top]; switch (get_type(v)) { case SMALLINT: - return v; + return (uint32_t)v; case BIGINT: ptr = u64_to_pointer(v); v = *(uint64_t *)ptr; @@ -290,11 +309,12 @@ static int stack_get_int(struct byte_vm *b) static void stack_roll(struct byte_vm *b) { uint64_t stack_copy[128], *copy; - int mod, n, last, i, len; + unsigned int n, last, i, len; + int mod; mod = stack_get_int(b); n = stack_get_int(b); - if (unlikely(mod >= n || n >= b->top)) + if (unlikely(!n || n >= b->top)) longjmp(b->exit, -EINVAL); switch (mod) { @@ -307,14 +327,20 @@ static void stack_roll(struct byte_vm *b) return; case -1: - last = b->top - 1; - stack_copy[0] = b->stack[i = last - n + 1]; - for (; --n; i++) + last = b->top - n - 1; + stack_copy[0] = b->stack[last]; + for (i = last; --n; i++) b->stack[i] = b->stack[i+1]; b->stack[i] = stack_copy[0]; return; } + mod = -mod; + if (mod < 0) + mod += n; + if (mod < 0 || mod >= n) + longjmp(b->exit, -EINVAL); + if (n > 128) { copy = malloc(n * sizeof(uint64_t)); if (unlikely(!copy)) @@ -325,9 +351,7 @@ static void stack_roll(struct byte_vm *b) i = b->top - n; memcpy(copy, b->stack + i, n * sizeof(uint64_t)); - mod = -mod; - if (mod < 0) - mod += n; + last = mod; for (len = n; n--; i++) { b->stack[i] = copy[last]; @@ -394,9 +418,9 @@ static void stack_clear(struct byte_vm *b) static int dictcmp(const void *a, const void *b) { - const struct byte_dictionary *A = a; - const struct byte_dictionary *B = b; - return strcmp(A->name, B->name); + const char *name = a; + const struct byte_dictionary *dict = b; + return strcmp(name, dict->name); } static const struct byte_dictionary * @@ -537,7 +561,7 @@ illegal: longjmp(b->exit, -EINVAL); smallint: - stack_push(b, (int8_t)code); + stack_push(b, (uint32_t)(int8_t)code); goto next; smallpot: @@ -750,12 +774,6 @@ void byte_push_object(struct byte_vm *b, struct byte_object *obj) stack_push(b, set_type(obj, OBJECT)); } -void byte_push_object_ref(struct byte_vm *b, struct byte_object *obj) -{ - obj->ref++; - stack_push(b, set_type(obj, OBJECT)); -} - struct byte_object *byte_pop_object(struct byte_vm *b) { uint64_t v; diff --git a/afl/bytecode.h b/afl/bytecode.h index f1c9e5b6..5eaf5083 100644 --- a/afl/bytecode.h +++ b/afl/bytecode.h @@ -17,7 +17,7 @@ struct byte_vm { uint8_t buf[4096], *b, *end; uint64_t *stack; - int size, top; + unsigned long size, top; struct byte_object **atoms; unsigned int maxatom; @@ -100,8 +100,12 @@ uint64_t byte_pop_u64(struct byte_vm *b); struct byte_object *byte_pop_object(struct byte_vm *b); void byte_push_cstring(struct byte_vm *b, const char *str); -void byte_push_object_ref(struct byte_vm *b, struct byte_object *obj); void byte_push_object(struct byte_vm *b, struct byte_object *obj); +static inline void +byte_push_object_ref(struct byte_vm *b, struct byte_object *obj) +{ + byte_push_object(b, byte_object_ref(obj)); +} void byte_push_u64(struct byte_vm *b, uint64_t v); void *byte_pop_struct(struct byte_vm *b, int maxdepth, unsigned long *sz); diff --git a/afl/i915_driver.c b/afl/i915_driver.c index 70974c02..e678818e 100644 --- a/afl/i915_driver.c +++ b/afl/i915_driver.c @@ -99,7 +99,7 @@ static void b_engine(struct byte_vm *b, struct byte_object *obj) if (id >= __I915_NUM_ENGINES || !i915->engine[id]) longjmp(b->exit, -ERANGE); - byte_push_object(b, &i915->engine[id]->byte); + byte_push_object_ref(b, &i915->engine[id]->byte); } static const struct byte_dictionary i915_dictionary[] = { diff --git a/afl/i915_object.c b/afl/i915_object.c index 4033bcb9..37538fff 100644 --- a/afl/i915_object.c +++ b/afl/i915_object.c @@ -1,4 +1,5 @@ #include <stdlib.h> +#include <string.h> #include <libdrm/i915_drm.h> @@ -48,6 +49,29 @@ int __i915_object_read(int fd, uint32_t handle, return sys_ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &arg); } +static int +__i915_object_set_caching(int fd, uint32_t handle, uint32_t caching) +{ + struct drm_i915_gem_caching arg = { + .handle = handle, + .caching = caching, + }; + + return sys_ioctl(fd, DRM_IOCTL_I915_GEM_SET_CACHING, &arg); +} + +static int +__i915_object_set_domain(int fd, uint32_t handle, uint32_t read, uint32_t write) +{ + struct drm_i915_gem_set_domain arg = { + .handle = handle, + .read_domains = read, + .write_domain = write, + }; + + return sys_ioctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &arg); +} + static int __i915_object_set_tiling(int fd, uint32_t handle, unsigned int tiling, unsigned int stride) { @@ -100,6 +124,36 @@ static void b_busy(struct byte_vm *b, struct byte_object *obj) bo->base.handle)); } +static void b_set_caching(struct byte_vm *b, struct byte_object *obj) +{ + struct i915_object *bo = to_i915_bo(obj); + unsigned int level; + int err; + + level = byte_pop_u64(b); + + err = __i915_object_set_caching(bo->base.driver->fd, + bo->base.handle, + level); + if (err) + longjmp(b->exit, err); +} + +static void b_set_domain(struct byte_vm *b, struct byte_object *obj) +{ + struct i915_object *bo = to_i915_bo(obj); + unsigned int read, write; + int err; + + write = byte_pop_u64(b); + read = byte_pop_u64(b); + + err = __i915_object_set_domain(bo->base.driver->fd, bo->base.handle, + read, write); + if (err) + longjmp(b->exit, err); +} + static void b_set_tiling(struct byte_vm *b, struct byte_object *obj) { struct i915_object *bo = to_i915_bo(obj); @@ -116,9 +170,33 @@ static void b_set_tiling(struct byte_vm *b, struct byte_object *obj) i915_image_set_tiling(bo->model, tiling, 0); } +static void b_write(struct byte_vm *b, struct byte_object *obj) +{ + struct i915_object *bo = to_i915_bo(obj); + unsigned long size; + uint64_t offset; + void *mem; + int err; + + offset = byte_pop_u64(b); + mem = byte_pop_struct(b, 0, &size); + + err = __i915_object_write(bo->base.driver->fd, + bo->base.handle, offset, + mem, size); + if (err) + longjmp(b->exit, err); + + memcpy(bo->model->pixels + offset, mem, size); + byte_free_struct(b, mem); +} + static const struct byte_dictionary i915_object_dictionary[] = { { "busy", b_busy }, + { "set-caching", b_set_caching }, + { "set-domain", b_set_domain }, { "set-tiling", b_set_tiling }, + { "write", b_write }, { }, }; |