summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2017-08-28 18:32:41 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2017-08-29 15:27:31 +0100
commit51fc224d19b7aab6c6e39843a258b0b10482ce6e (patch)
tree878fc1c0f7fa91979b811fd580dfdb6da1f8036c
parentf55234c41fd94116caf7b6ea03bd008cd315e7c5 (diff)
fixafl
-rw-r--r--afl/Makefile16
-rw-r--r--afl/byte-afl.c76
-rw-r--r--afl/byte-decompile.c173
-rw-r--r--afl/byte-kcov.c (renamed from afl/byte-server.c)26
-rw-r--r--afl/bytecode.c76
-rw-r--r--afl/bytecode.h8
-rw-r--r--afl/i915_driver.c2
-rw-r--r--afl/i915_object.c78
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,
+ &&copy,
+ &&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 },
{ },
};