From c83e8e1e6255374b085292ba8673efdca7388d76 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sat, 19 Oct 2019 18:23:01 +0200 Subject: Remove lcamtuf's old email from Google (not valid anymore), also remove maintainance from him. --- libtokencap/Makefile | 2 +- libtokencap/libtokencap.so.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'libtokencap') diff --git a/libtokencap/Makefile b/libtokencap/Makefile index 3fd01b2c..91933140 100644 --- a/libtokencap/Makefile +++ b/libtokencap/Makefile @@ -2,7 +2,7 @@ # american fuzzy lop - libtokencap # -------------------------------- # -# Written by Michal Zalewski +# Written by Michal Zalewski # # Copyright 2016 Google Inc. All rights reserved. # diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index 17b6190c..39095beb 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -3,7 +3,7 @@ american fuzzy lop - extract tokens passed to strcmp / memcmp ------------------------------------------------------------- - Written and maintained by Michal Zalewski + Written by Michal Zalewski Copyright 2016 Google Inc. All rights reserved. -- cgit 1.4.1 From 814242225725f338e35f9af372ee55daba5b4f38 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Wed, 23 Oct 2019 20:07:16 +0100 Subject: Porting libtokencap to Darwin. Reading only main addresses and read only's. --- libtokencap/Makefile | 3 +++ libtokencap/libtokencap.so.c | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) (limited to 'libtokencap') diff --git a/libtokencap/Makefile b/libtokencap/Makefile index 91933140..702ce696 100644 --- a/libtokencap/Makefile +++ b/libtokencap/Makefile @@ -24,6 +24,9 @@ CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign ifeq "$(shell uname)" "Linux" TARGETS = libtokencap.so endif +ifeq "$(shell uname)" "Darwin" + TARGETS = libtokencap.so +endif all: $(TARGETS) libtokencap.so: libtokencap.so.c ../config.h diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index 39095beb..212fa31d 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -26,10 +26,15 @@ #include "../types.h" #include "../config.h" -#ifndef __linux__ -#error "Sorry, this library is Linux-specific for now!" +#if !defined(__linux__) && !defined(__APPLE__) +#error "Sorry, this library is unsupported in this platform for now!" #endif /* !__linux__ */ +#if defined(__APPLE__) +#include +#include +#endif + /* Mapping data and such */ #define MAX_MAPPINGS 1024 @@ -46,6 +51,7 @@ static FILE* __tokencap_out_file; static void __tokencap_load_mappings(void) { +#if defined(__linux__) u8 buf[MAX_LINE]; FILE* f = fopen("/proc/self/maps", "r"); @@ -69,7 +75,34 @@ static void __tokencap_load_mappings(void) { } fclose(f); +#elif defined(__APPLE__) + struct vm_region_submap_info_64 region; + mach_msg_type_number_t cnt = VM_REGION_SUBMAP_INFO_COUNT_64; + vm_address_t base = 0; + vm_size_t size = 0; + natural_t depth = 0; + + __tokencap_ro_loaded = 1; + + while (1) { + + if (vm_region_recurse_64(mach_task_self(), &base, &size, &depth, + (vm_region_info_64_t)®ion, &cnt) != KERN_SUCCESS) break; + + if (region.is_submap) { + depth++; + } else { + /* We only care of main map addresses and the read only kinds */ + if ((region.protection & VM_PROT_READ) && !(region.protection & VM_PROT_WRITE)) { + __tokencap_ro[__tokencap_ro_cnt].st = (void *)base; + __tokencap_ro[__tokencap_ro_cnt].en = (void *)(base + size); + + if (++__tokencap_ro_cnt == MAX_MAPPINGS) break; + } + } + } +#endif } /* Check an address against the list of read-only mappings. */ -- cgit 1.4.1 From b4b26d420771ca19a26828d9fdd53cdd66dab9ee Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 24 Oct 2019 18:48:08 +0100 Subject: FreeBSD implementation --- libtokencap/Makefile | 3 +++ libtokencap/libtokencap.so.c | 50 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) (limited to 'libtokencap') diff --git a/libtokencap/Makefile b/libtokencap/Makefile index 702ce696..07c13144 100644 --- a/libtokencap/Makefile +++ b/libtokencap/Makefile @@ -27,6 +27,9 @@ endif ifeq "$(shell uname)" "Darwin" TARGETS = libtokencap.so endif +ifeq "$(shell uname)" "FreeBSD" + TARGETS = libtokencap.so +endif all: $(TARGETS) libtokencap.so: libtokencap.so.c ../config.h diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index 212fa31d..1050378c 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -22,17 +22,23 @@ #include #include #include +#include #include "../types.h" #include "../config.h" -#if !defined(__linux__) && !defined(__APPLE__) +#if !defined(__linux__) && !defined(__APPLE__) && !defined(__FreeBSD__) #error "Sorry, this library is unsupported in this platform for now!" #endif /* !__linux__ */ #if defined(__APPLE__) #include #include +#elif defined(__FreeBSD__) +#include +#include +#include +#include #endif /* Mapping data and such */ @@ -102,6 +108,48 @@ static void __tokencap_load_mappings(void) { } } +#elif defined(__FreeBSD__) + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; + char *buf, *low, *high; + size_t miblen = sizeof(mib)/sizeof(mib[0]); + size_t len; + + if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) return; + + len = len * 4 / 3; + buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); + + if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) { + + munmap(buf, len); + return; + + } + + low = buf; + high = low + len; + + __tokencap_ro_loaded = 1; + + while (low < high) { + struct kinfo_vmentry *region = (struct kinfo_vmentry *)low; + size_t size = region->kve_structsize; + + if (size == 0) break; + + /* We go through the whole mapping of the process and track read-only addresses */ + if ((region->kve_protection & KVME_PROT_READ) && + !(region->kve_protection & KVME_PROT_WRITE)) { + __tokencap_ro[__tokencap_ro_cnt].st = (void *)region->kve_start; + __tokencap_ro[__tokencap_ro_cnt].en = (void *)region->kve_end; + + if (++__tokencap_ro_cnt == MAX_MAPPINGS) break; + } + + low += size; + } + + munmap(buf, len); #endif } -- cgit 1.4.1 From e0ff20dd372579f4e4a540df00c8d6f4e218672b Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Fri, 25 Oct 2019 01:51:53 +0200 Subject: cosmetics --- libtokencap/libtokencap.so.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'libtokencap') diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index 1050378c..ddeae8b8 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -27,18 +27,18 @@ #include "../types.h" #include "../config.h" -#if !defined(__linux__) && !defined(__APPLE__) && !defined(__FreeBSD__) -#error "Sorry, this library is unsupported in this platform for now!" -#endif /* !__linux__ */ - -#if defined(__APPLE__) -#include -#include -#elif defined(__FreeBSD__) -#include -#include -#include -#include +#if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ +# error "Sorry, this library is unsupported in this platform for now!" +#endif /* !__linux__ && !__APPLE__ && ! __FreeBSD__ */ + +#if defined __APPLE__ +# include +# include +#elif defined __FreeBSD__ +# include +# include +# include +# include #endif /* Mapping data and such */ @@ -57,7 +57,8 @@ static FILE* __tokencap_out_file; static void __tokencap_load_mappings(void) { -#if defined(__linux__) +#if defined __linux__ + u8 buf[MAX_LINE]; FILE* f = fopen("/proc/self/maps", "r"); @@ -81,7 +82,9 @@ static void __tokencap_load_mappings(void) { } fclose(f); -#elif defined(__APPLE__) + +#elif defined __APPLE__ + struct vm_region_submap_info_64 region; mach_msg_type_number_t cnt = VM_REGION_SUBMAP_INFO_COUNT_64; vm_address_t base = 0; @@ -108,7 +111,8 @@ static void __tokencap_load_mappings(void) { } } -#elif defined(__FreeBSD__) +#elif defined __FreeBSD__ + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; char *buf, *low, *high; size_t miblen = sizeof(mib)/sizeof(mib[0]); -- cgit 1.4.1 From b8abf27b86e74a4ab6889322ef232a00f1f018c4 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Fri, 25 Oct 2019 09:36:17 +0200 Subject: Update README.md remove Linux-only :-), list supported OSes --- libtokencap/README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'libtokencap') diff --git a/libtokencap/README.md b/libtokencap/README.md index baf69da1..8aae38bf 100644 --- a/libtokencap/README.md +++ b/libtokencap/README.md @@ -2,7 +2,7 @@ (See ../docs/README for the general instruction manual.) -This Linux-only companion library allows you to instrument `strcmp()`, `memcmp()`, +This companion library allows you to instrument `strcmp()`, `memcmp()`, and related functions to automatically extract syntax tokens passed to any of these libcalls. The resulting list of tokens may be then given as a starting dictionary to afl-fuzz (the -x option) to improve coverage on subsequent @@ -55,9 +55,10 @@ If you don't get any results, the target library is probably not using strcmp() and memcmp() to parse input; or you haven't compiled it with -fno-builtin; or the whole thing isn't dynamically linked, and LD_PRELOAD is having no effect. -PS. The library is Linux-only because there is probably no particularly portable -and non-invasive way to distinguish between read-only and read-write memory -mappings. The `__tokencap_load_mappings()` function is the only thing that would -need to be changed for other OSes. Porting to platforms with /proc//maps -(e.g., FreeBSD) should be trivial. +Portability hints: There is probably no particularly portable and non-invasive +way to distinguish between read-only and read-write memory mappings. +The `__tokencap_load_mappings()` function is the only thing that would +need to be changed for other OSes. + +Current supported OSes are: Linux, Darwin, FreeBSD (thanks to @devnexen) -- cgit 1.4.1 From 3e9e7e17504517d8db92e47e7a5f904b023ba91e Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sat, 26 Oct 2019 00:17:51 +0200 Subject: libtokencap ported to OpenBSD --- libtokencap/Makefile | 3 +++ libtokencap/libtokencap.so.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) (limited to 'libtokencap') diff --git a/libtokencap/Makefile b/libtokencap/Makefile index 07c13144..441412c7 100644 --- a/libtokencap/Makefile +++ b/libtokencap/Makefile @@ -30,6 +30,9 @@ endif ifeq "$(shell uname)" "FreeBSD" TARGETS = libtokencap.so endif +ifeq "$(shell uname)" "OpenBSD" + TARGETS = libtokencap.so +endif all: $(TARGETS) libtokencap.so: libtokencap.so.c ../config.h diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index ddeae8b8..d33de8a4 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -27,14 +27,14 @@ #include "../types.h" #include "../config.h" -#if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ +#if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ && !defined __OpenBSD__ # error "Sorry, this library is unsupported in this platform for now!" #endif /* !__linux__ && !__APPLE__ && ! __FreeBSD__ */ #if defined __APPLE__ # include # include -#elif defined __FreeBSD__ +#elif defined __FreeBSD__ || defined __OpenBSD__ # include # include # include @@ -111,17 +111,29 @@ static void __tokencap_load_mappings(void) { } } -#elif defined __FreeBSD__ +#elif defined __FreeBSD__ || defined __OpenBSD__ +#if defined __FreeBSD__ int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; +#elif defined __OpenBSD__ + int mib[] = {CTL_KERN, KERN_PROC_VMMAP, getpid()}; +#endif char *buf, *low, *high; size_t miblen = sizeof(mib)/sizeof(mib[0]); size_t len; if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) return; +#if defined __FreeBSD__ len = len * 4 / 3; +#elif defined __OpenBSD__ + len -= len % sizeof(struct kinfo_vmentry); +#endif + buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); + if (!buf) { + return; + } if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) { @@ -137,6 +149,9 @@ static void __tokencap_load_mappings(void) { while (low < high) { struct kinfo_vmentry *region = (struct kinfo_vmentry *)low; + +#if defined __FreeBSD__ + size_t size = region->kve_structsize; if (size == 0) break; @@ -144,6 +159,15 @@ static void __tokencap_load_mappings(void) { /* We go through the whole mapping of the process and track read-only addresses */ if ((region->kve_protection & KVME_PROT_READ) && !(region->kve_protection & KVME_PROT_WRITE)) { + +#elif defined __OpenBSD__ + + size_t size = sizeof (*region); + + /* We go through the whole mapping of the process and track read-only addresses */ + if ((region->kve_protection & KVE_PROT_READ) && + !(region->kve_protection & KVE_PROT_WRITE)) { +#endif __tokencap_ro[__tokencap_ro_cnt].st = (void *)region->kve_start; __tokencap_ro[__tokencap_ro_cnt].en = (void *)region->kve_end; -- cgit 1.4.1 From 74df3e24913a882d22a39a3ea32ec7288921f0e0 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sun, 27 Oct 2019 07:27:48 +0100 Subject: WIP for NetBSD port, iteration has an unknown problem causing a seg fault --- libtokencap/libtokencap.so.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'libtokencap') diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index d33de8a4..7ed231fe 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -27,14 +27,14 @@ #include "../types.h" #include "../config.h" -#if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ && !defined __OpenBSD__ +#if !defined __linux__ && !defined __APPLE__ && !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ # error "Sorry, this library is unsupported in this platform for now!" -#endif /* !__linux__ && !__APPLE__ && ! __FreeBSD__ */ +#endif /* !__linux__ && !__APPLE__ && ! __FreeBSD__ && ! __OpenBSD__ && !__NetBSD__*/ #if defined __APPLE__ # include # include -#elif defined __FreeBSD__ || defined __OpenBSD__ +#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ # include # include # include @@ -111,12 +111,14 @@ static void __tokencap_load_mappings(void) { } } -#elif defined __FreeBSD__ || defined __OpenBSD__ +#elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ #if defined __FreeBSD__ int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; #elif defined __OpenBSD__ int mib[] = {CTL_KERN, KERN_PROC_VMMAP, getpid()}; +#elif defined __NetBSD__ + int mib[] = {CTL_VM, VM_PROC, VM_PROC_MAP, getpid(), sizeof(struct kinfo_vmentry)}; #endif char *buf, *low, *high; size_t miblen = sizeof(mib)/sizeof(mib[0]); @@ -124,7 +126,7 @@ static void __tokencap_load_mappings(void) { if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1) return; -#if defined __FreeBSD__ +#if defined __FreeBSD__ || defined __NetBSD__ len = len * 4 / 3; #elif defined __OpenBSD__ len -= len % sizeof(struct kinfo_vmentry); @@ -150,11 +152,15 @@ static void __tokencap_load_mappings(void) { while (low < high) { struct kinfo_vmentry *region = (struct kinfo_vmentry *)low; -#if defined __FreeBSD__ +#if defined __FreeBSD__ || defined __NetBSD__ +#if defined __FreeBSD__ size_t size = region->kve_structsize; if (size == 0) break; +#elif defined __NetBSD__ + size_t size = sizeof (*region); +#endif /* We go through the whole mapping of the process and track read-only addresses */ if ((region->kve_protection & KVME_PROT_READ) && -- cgit 1.4.1 From 942f8d0ec9bed45c9038112aef7cd9b8a05f6f30 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 28 Oct 2019 11:01:37 +0000 Subject: Fix proposal for libtokencap Avoiding fopen API seems buggy on NetBSD. --- libtokencap/Makefile | 3 +++ libtokencap/libtokencap.so.c | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'libtokencap') diff --git a/libtokencap/Makefile b/libtokencap/Makefile index 441412c7..df2426ed 100644 --- a/libtokencap/Makefile +++ b/libtokencap/Makefile @@ -33,6 +33,9 @@ endif ifeq "$(shell uname)" "OpenBSD" TARGETS = libtokencap.so endif +ifeq "$(shell uname)" "NetBSD" + TARGETS = libtokencap.so +endif all: $(TARGETS) libtokencap.so: libtokencap.so.c ../config.h diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index 7ed231fe..e1977127 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "../types.h" #include "../config.h" @@ -49,7 +50,7 @@ static struct mapping { void *st, *en; } __tokencap_ro[MAX_MAPPINGS]; static u32 __tokencap_ro_cnt; static u8 __tokencap_ro_loaded; -static FILE* __tokencap_out_file; +static int __tokencap_out_file = -1; /* Identify read-only regions in memory. Only parameters that fall into these ranges are worth dumping when passed to strcmp() and so on. Read-write @@ -211,7 +212,7 @@ static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) { u32 i; u32 pos = 0; - if (len < MIN_AUTO_EXTRA || len > MAX_AUTO_EXTRA || !__tokencap_out_file) + if (len < MIN_AUTO_EXTRA || len > MAX_AUTO_EXTRA || __tokencap_out_file == -1) return; for (i = 0; i < len; i++) { @@ -237,7 +238,9 @@ static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) { buf[pos] = 0; - fprintf(__tokencap_out_file, "\"%s\"\n", buf); + write(__tokencap_out_file, "\"", 1); + write(__tokencap_out_file, buf, pos); + write(__tokencap_out_file, "\"\n", 2); } @@ -403,8 +406,13 @@ char* strcasestr(const char* haystack, const char* needle) { __attribute__((constructor)) void __tokencap_init(void) { u8* fn = getenv("AFL_TOKEN_FILE"); - if (fn) __tokencap_out_file = fopen(fn, "a"); - if (!__tokencap_out_file) __tokencap_out_file = stderr; + if (fn) __tokencap_out_file = open(fn, O_RDWR | O_CREAT | O_APPEND, 0655); + if (__tokencap_out_file == -1) __tokencap_out_file = STDERR_FILENO; } +/* closing as best as we can the tokens file */ +__attribute__((destructor)) void __tokencap_shutdown(void) { + if (__tokencap_out_file != STDERR_FILENO) close(__tokencap_out_file); +} + -- cgit 1.4.1 From 25443918c4ab15c4c1f9ba0861f5d48daa29a412 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Mon, 28 Oct 2019 16:45:30 +0100 Subject: silence some compiler warnings --- libtokencap/libtokencap.so.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libtokencap') diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index e1977127..820f5bc4 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -238,9 +238,9 @@ static void __tokencap_dump(const u8* ptr, size_t len, u8 is_text) { buf[pos] = 0; - write(__tokencap_out_file, "\"", 1); - write(__tokencap_out_file, buf, pos); - write(__tokencap_out_file, "\"\n", 2); + int wrt_ok = ( 1 == write(__tokencap_out_file, "\"", 1)); + wrt_ok &= (pos == write(__tokencap_out_file, buf, pos)); + wrt_ok &= (2 == write(__tokencap_out_file, "\"\n", 2)); } -- cgit 1.4.1 From df5c7eef39ac20497d5b372033874c70bb7a47e9 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 29 Oct 2019 10:49:16 +0000 Subject: libtokencap, respect constness also considering pointer arithmetic is non C standard, some compilers might not have GNU extensions. --- libtokencap/libtokencap.so.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'libtokencap') diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index 820f5bc4..7e55963c 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -256,7 +256,7 @@ int strcmp(const char* str1, const char* str2) { while (1) { - unsigned char c1 = *str1, c2 = *str2; + const unsigned char c1 = *str1, c2 = *str2; if (c1 != c2) return (c1 > c2) ? 1 : -1; if (!c1) return 0; @@ -298,7 +298,7 @@ int strcasecmp(const char* str1, const char* str2) { while (1) { - unsigned char c1 = tolower(*str1), c2 = tolower(*str2); + const unsigned char c1 = tolower(*str1), c2 = tolower(*str2); if (c1 != c2) return (c1 > c2) ? 1 : -1; if (!c1) return 0; @@ -318,7 +318,7 @@ int strncasecmp(const char* str1, const char* str2, size_t len) { while (len--) { - unsigned char c1 = tolower(*str1), c2 = tolower(*str2); + const unsigned char c1 = tolower(*str1), c2 = tolower(*str2); if (!c1) return 0; if (c1 != c2) return (c1 > c2) ? 1 : -1; @@ -338,12 +338,15 @@ int memcmp(const void* mem1, const void* mem2, size_t len) { if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0); if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0); + const char *strmem1 = (const char *)mem1; + const char *strmem2 = (const char *)mem2; + while (len--) { - unsigned char c1 = *(const char*)mem1, c2 = *(const char*)mem2; + const unsigned char c1 = *strmem1, c2 = *strmem2; if (c1 != c2) return (c1 > c2) ? 1 : -1; - mem1++; - mem2++; + strmem1++; + strmem2++; } -- cgit 1.4.1 From c87210820c1566c74bf08ab4345679598cabd71b Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 29 Oct 2019 15:06:20 +0000 Subject: libtokencap update proposal - bcmp interception. - FreeBSD using default argument to get current pid for the mapping data gathering, getpid seems to cause some issues under certain conditions (getenv call). --- libtokencap/libtokencap.so.c | 28 ++++++++++++++++++++++++---- llvm_mode/afl-clang-fast.c | 3 +++ src/afl-gcc.c | 1 + 3 files changed, 28 insertions(+), 4 deletions(-) (limited to 'libtokencap') diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index 7e55963c..2fe9ae63 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -115,7 +115,7 @@ static void __tokencap_load_mappings(void) { #elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ #if defined __FreeBSD__ - int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, -1}; #elif defined __OpenBSD__ int mib[] = {CTL_KERN, KERN_PROC_VMMAP, getpid()}; #elif defined __NetBSD__ @@ -134,9 +134,7 @@ static void __tokencap_load_mappings(void) { #endif buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); - if (!buf) { - return; - } + if (buf == MAP_FAILED) return; if (sysctl(mib, miblen, buf, &len, NULL, 0) == -1) { @@ -354,6 +352,28 @@ int memcmp(const void* mem1, const void* mem2, size_t len) { } +#undef bcmp + +int bcmp(const void* mem1, const void* mem2, size_t len) { + + if (__tokencap_is_ro(mem1)) __tokencap_dump(mem1, len, 0); + if (__tokencap_is_ro(mem2)) __tokencap_dump(mem2, len, 0); + + const char *strmem1 = (const char *)mem1; + const char *strmem2 = (const char *)mem2; + + while (len--) { + + int diff = *strmem1 ^ *strmem2; + if (diff != 0) return 1; + strmem1++; + strmem2++; + + } + + return 0; +} + #undef strstr char* strstr(const char* haystack, const char* needle) { diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index a7f6acdc..1acf8856 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -273,6 +273,9 @@ static void edit_params(u32 argc, char** argv) { cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-bcmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-strstr"; + cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr"; } diff --git a/src/afl-gcc.c b/src/afl-gcc.c index 740442dc..e0706a5f 100644 --- a/src/afl-gcc.c +++ b/src/afl-gcc.c @@ -320,6 +320,7 @@ static void edit_params(u32 argc, char** argv) { cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp"; cc_params[cc_par_cnt++] = "-fno-builtin-memcmp"; + cc_params[cc_par_cnt++] = "-fno-builtin-bcmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strstr"; cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr"; -- cgit 1.4.1 From b33bb0943ac4957eaf7b16ef694a4e4b4a538212 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 31 Oct 2019 15:50:58 +0000 Subject: libtokencap/libdislocator README rename proposals and fixing the install tasks in the process. --- README.md | 2 +- docs/notes_for_asan.txt | 2 +- libdislocator/Makefile | 2 +- libdislocator/README.dislocator.md | 60 +++++++++++++++++++++++++++++++++++ libdislocator/README.md | 60 ----------------------------------- libdislocator/libdislocator.so.c | 2 +- libtokencap/Makefile | 2 +- libtokencap/README.md | 64 -------------------------------------- libtokencap/README.tokencap.md | 64 ++++++++++++++++++++++++++++++++++++++ libtokencap/libtokencap.so.c | 2 +- 10 files changed, 130 insertions(+), 130 deletions(-) create mode 100644 libdislocator/README.dislocator.md delete mode 100644 libdislocator/README.md delete mode 100644 libtokencap/README.md create mode 100644 libtokencap/README.tokencap.md (limited to 'libtokencap') diff --git a/README.md b/README.md index 88a86aaa..e8d4e6a8 100644 --- a/README.md +++ b/README.md @@ -457,7 +457,7 @@ parsers and grammars, but isn't nearly as good as the -x mode. If a dictionary is really hard to come by, another option is to let AFL run for a while, and then use the token capture library that comes as a companion -utility with AFL. For that, see [libtokencap/README.md](libtokencap/README.md). +utility with AFL. For that, see [libtokencap/README.md](libtokencap/README.tokencap.md). ## 11) Crash triage diff --git a/docs/notes_for_asan.txt b/docs/notes_for_asan.txt index 972ca909..09ca172e 100644 --- a/docs/notes_for_asan.txt +++ b/docs/notes_for_asan.txt @@ -34,7 +34,7 @@ Note that ASAN is incompatible with -static, so be mindful of that. There is also the option of generating a corpus using a non-ASAN binary, and then feeding it to an ASAN-instrumented one to check for bugs. This is faster, and can give you somewhat comparable results. You can also try using -libdislocator (see libdislocator/README.dislocator in the parent directory) as a +libdislocator (see libdislocator/README.dislocator.md in the parent directory) as a lightweight and hassle-free (but less thorough) alternative. 2) Long version diff --git a/libdislocator/Makefile b/libdislocator/Makefile index 91efba07..05ba26b3 100644 --- a/libdislocator/Makefile +++ b/libdislocator/Makefile @@ -34,5 +34,5 @@ clean: install: all install -m 755 ../libdislocator.so $${DESTDIR}$(HELPER_PATH) - install -m 644 README.dislocator $${DESTDIR}$(HELPER_PATH) + install -m 644 README.dislocator.md $${DESTDIR}$(HELPER_PATH) diff --git a/libdislocator/README.dislocator.md b/libdislocator/README.dislocator.md new file mode 100644 index 00000000..5d5a1464 --- /dev/null +++ b/libdislocator/README.dislocator.md @@ -0,0 +1,60 @@ +# libdislocator, an abusive allocator + + (See ../docs/README for the general instruction manual.) + +This is a companion library that can be used as a drop-in replacement for the +libc allocator in the fuzzed binaries. It improves the odds of bumping into +heap-related security bugs in several ways: + + - It allocates all buffers so that they are immediately adjacent to a + subsequent PROT_NONE page, causing most off-by-one reads and writes to + immediately segfault, + + - It adds a canary immediately below the allocated buffer, to catch writes + to negative offsets (won't catch reads, though), + + - It sets the memory returned by malloc() to garbage values, improving the + odds of crashing when the target accesses uninitialized data, + + - It sets freed memory to PROT_NONE and does not actually reuse it, causing + most use-after-free bugs to segfault right away, + + - It forces all realloc() calls to return a new address - and sets + PROT_NONE on the original block. This catches use-after-realloc bugs, + + - It checks for calloc() overflows and can cause soft or hard failures + of alloc requests past a configurable memory limit (AFL_LD_LIMIT_MB, + AFL_LD_HARD_FAIL). + +Basically, it is inspired by some of the non-default options available for the +OpenBSD allocator - see malloc.conf(5) on that platform for reference. It is +also somewhat similar to several other debugging libraries, such as gmalloc +and DUMA - but is simple, plug-and-play, and designed specifically for fuzzing +jobs. + +Note that it does nothing for stack-based memory handling errors. The +-fstack-protector-all setting for GCC / clang, enabled when using AFL_HARDEN, +can catch some subset of that. + +The allocator is slow and memory-intensive (even the tiniest allocation uses up +4 kB of physical memory and 8 kB of virtual mem), making it completely unsuitable +for "production" uses; but it can be faster and more hassle-free than ASAN / MSAN +when fuzzing small, self-contained binaries. + +To use this library, run AFL like so: + +``` +AFL_PRELOAD=/path/to/libdislocator.so ./afl-fuzz [...other params...] +``` + +You *have* to specify path, even if it's just ./libdislocator.so or +$PWD/libdislocator.so. + +Similarly to afl-tmin, the library is not "proprietary" and can be used with +other fuzzers or testing tools without the need for any code tweaks. It does not +require AFL-instrumented binaries to work. + +Note that the AFL_PRELOAD approach (which AFL internally maps to LD_PRELOAD or +DYLD_INSERT_LIBRARIES, depending on the OS) works only if the target binary is +dynamically linked. Otherwise, attempting to use the library will have no +effect. diff --git a/libdislocator/README.md b/libdislocator/README.md deleted file mode 100644 index 5d5a1464..00000000 --- a/libdislocator/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# libdislocator, an abusive allocator - - (See ../docs/README for the general instruction manual.) - -This is a companion library that can be used as a drop-in replacement for the -libc allocator in the fuzzed binaries. It improves the odds of bumping into -heap-related security bugs in several ways: - - - It allocates all buffers so that they are immediately adjacent to a - subsequent PROT_NONE page, causing most off-by-one reads and writes to - immediately segfault, - - - It adds a canary immediately below the allocated buffer, to catch writes - to negative offsets (won't catch reads, though), - - - It sets the memory returned by malloc() to garbage values, improving the - odds of crashing when the target accesses uninitialized data, - - - It sets freed memory to PROT_NONE and does not actually reuse it, causing - most use-after-free bugs to segfault right away, - - - It forces all realloc() calls to return a new address - and sets - PROT_NONE on the original block. This catches use-after-realloc bugs, - - - It checks for calloc() overflows and can cause soft or hard failures - of alloc requests past a configurable memory limit (AFL_LD_LIMIT_MB, - AFL_LD_HARD_FAIL). - -Basically, it is inspired by some of the non-default options available for the -OpenBSD allocator - see malloc.conf(5) on that platform for reference. It is -also somewhat similar to several other debugging libraries, such as gmalloc -and DUMA - but is simple, plug-and-play, and designed specifically for fuzzing -jobs. - -Note that it does nothing for stack-based memory handling errors. The --fstack-protector-all setting for GCC / clang, enabled when using AFL_HARDEN, -can catch some subset of that. - -The allocator is slow and memory-intensive (even the tiniest allocation uses up -4 kB of physical memory and 8 kB of virtual mem), making it completely unsuitable -for "production" uses; but it can be faster and more hassle-free than ASAN / MSAN -when fuzzing small, self-contained binaries. - -To use this library, run AFL like so: - -``` -AFL_PRELOAD=/path/to/libdislocator.so ./afl-fuzz [...other params...] -``` - -You *have* to specify path, even if it's just ./libdislocator.so or -$PWD/libdislocator.so. - -Similarly to afl-tmin, the library is not "proprietary" and can be used with -other fuzzers or testing tools without the need for any code tweaks. It does not -require AFL-instrumented binaries to work. - -Note that the AFL_PRELOAD approach (which AFL internally maps to LD_PRELOAD or -DYLD_INSERT_LIBRARIES, depending on the OS) works only if the target binary is -dynamically linked. Otherwise, attempting to use the library will have no -effect. diff --git a/libdislocator/libdislocator.so.c b/libdislocator/libdislocator.so.c index 7fe40afa..106b44f4 100644 --- a/libdislocator/libdislocator.so.c +++ b/libdislocator/libdislocator.so.c @@ -14,7 +14,7 @@ http://www.apache.org/licenses/LICENSE-2.0 This is a companion library that can be used as a drop-in replacement - for the libc allocator in the fuzzed binaries. See README.dislocator for + for the libc allocator in the fuzzed binaries. See README.dislocator.md for more info. */ diff --git a/libtokencap/Makefile b/libtokencap/Makefile index df2426ed..6e1319d8 100644 --- a/libtokencap/Makefile +++ b/libtokencap/Makefile @@ -49,5 +49,5 @@ clean: install: all install -m 755 ../libtokencap.so $${DESTDIR}$(HELPER_PATH) - install -m 644 README.tokencap $${DESTDIR}$(HELPER_PATH) + install -m 644 README.tokencap.md $${DESTDIR}$(HELPER_PATH) diff --git a/libtokencap/README.md b/libtokencap/README.md deleted file mode 100644 index 8aae38bf..00000000 --- a/libtokencap/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# strcmp() / memcmp() token capture library - - (See ../docs/README for the general instruction manual.) - -This companion library allows you to instrument `strcmp()`, `memcmp()`, -and related functions to automatically extract syntax tokens passed to any of -these libcalls. The resulting list of tokens may be then given as a starting -dictionary to afl-fuzz (the -x option) to improve coverage on subsequent -fuzzing runs. - -This may help improving coverage in some targets, and do precisely nothing in -others. In some cases, it may even make things worse: if libtokencap picks up -syntax tokens that are not used to process the input data, but that are a part -of - say - parsing a config file... well, you're going to end up wasting a lot -of CPU time on trying them out in the input stream. In other words, use this -feature with care. Manually screening the resulting dictionary is almost -always a necessity. - -As for the actual operation: the library stores tokens, without any deduping, -by appending them to a file specified via AFL_TOKEN_FILE. If the variable is not -set, the tool uses stderr (which is probably not what you want). - -Similarly to afl-tmin, the library is not "proprietary" and can be used with -other fuzzers or testing tools without the need for any code tweaks. It does not -require AFL-instrumented binaries to work. - -To use the library, you *need* to make sure that your fuzzing target is compiled -with -fno-builtin and is linked dynamically. If you wish to automate the first -part without mucking with CFLAGS in Makefiles, you can set AFL_NO_BUILTIN=1 -when using afl-gcc. This setting specifically adds the following flags: - -``` - -fno-builtin-strcmp -fno-builtin-strncmp -fno-builtin-strcasecmp - -fno-builtin-strcasencmp -fno-builtin-memcmp -fno-builtin-strstr - -fno-builtin-strcasestr -``` - -The next step is simply loading this library via LD_PRELOAD. The optimal usage -pattern is to allow afl-fuzz to fuzz normally for a while and build up a corpus, -and then fire off the target binary, with libtokencap.so loaded, on every file -found by AFL in that earlier run. This demonstrates the basic principle: - -``` - export AFL_TOKEN_FILE=$PWD/temp_output.txt - - for i in /queue/id*; do - LD_PRELOAD=/path/to/libtokencap.so \ - /path/to/target/program [...params, including $i...] - done - - sort -u temp_output.txt >afl_dictionary.txt -``` - -If you don't get any results, the target library is probably not using strcmp() -and memcmp() to parse input; or you haven't compiled it with -fno-builtin; or -the whole thing isn't dynamically linked, and LD_PRELOAD is having no effect. - -Portability hints: There is probably no particularly portable and non-invasive -way to distinguish between read-only and read-write memory mappings. -The `__tokencap_load_mappings()` function is the only thing that would -need to be changed for other OSes. - -Current supported OSes are: Linux, Darwin, FreeBSD (thanks to @devnexen) - diff --git a/libtokencap/README.tokencap.md b/libtokencap/README.tokencap.md new file mode 100644 index 00000000..8aae38bf --- /dev/null +++ b/libtokencap/README.tokencap.md @@ -0,0 +1,64 @@ +# strcmp() / memcmp() token capture library + + (See ../docs/README for the general instruction manual.) + +This companion library allows you to instrument `strcmp()`, `memcmp()`, +and related functions to automatically extract syntax tokens passed to any of +these libcalls. The resulting list of tokens may be then given as a starting +dictionary to afl-fuzz (the -x option) to improve coverage on subsequent +fuzzing runs. + +This may help improving coverage in some targets, and do precisely nothing in +others. In some cases, it may even make things worse: if libtokencap picks up +syntax tokens that are not used to process the input data, but that are a part +of - say - parsing a config file... well, you're going to end up wasting a lot +of CPU time on trying them out in the input stream. In other words, use this +feature with care. Manually screening the resulting dictionary is almost +always a necessity. + +As for the actual operation: the library stores tokens, without any deduping, +by appending them to a file specified via AFL_TOKEN_FILE. If the variable is not +set, the tool uses stderr (which is probably not what you want). + +Similarly to afl-tmin, the library is not "proprietary" and can be used with +other fuzzers or testing tools without the need for any code tweaks. It does not +require AFL-instrumented binaries to work. + +To use the library, you *need* to make sure that your fuzzing target is compiled +with -fno-builtin and is linked dynamically. If you wish to automate the first +part without mucking with CFLAGS in Makefiles, you can set AFL_NO_BUILTIN=1 +when using afl-gcc. This setting specifically adds the following flags: + +``` + -fno-builtin-strcmp -fno-builtin-strncmp -fno-builtin-strcasecmp + -fno-builtin-strcasencmp -fno-builtin-memcmp -fno-builtin-strstr + -fno-builtin-strcasestr +``` + +The next step is simply loading this library via LD_PRELOAD. The optimal usage +pattern is to allow afl-fuzz to fuzz normally for a while and build up a corpus, +and then fire off the target binary, with libtokencap.so loaded, on every file +found by AFL in that earlier run. This demonstrates the basic principle: + +``` + export AFL_TOKEN_FILE=$PWD/temp_output.txt + + for i in /queue/id*; do + LD_PRELOAD=/path/to/libtokencap.so \ + /path/to/target/program [...params, including $i...] + done + + sort -u temp_output.txt >afl_dictionary.txt +``` + +If you don't get any results, the target library is probably not using strcmp() +and memcmp() to parse input; or you haven't compiled it with -fno-builtin; or +the whole thing isn't dynamically linked, and LD_PRELOAD is having no effect. + +Portability hints: There is probably no particularly portable and non-invasive +way to distinguish between read-only and read-write memory mappings. +The `__tokencap_load_mappings()` function is the only thing that would +need to be changed for other OSes. + +Current supported OSes are: Linux, Darwin, FreeBSD (thanks to @devnexen) + diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index 2fe9ae63..7495180d 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -15,7 +15,7 @@ This Linux-only companion library allows you to instrument strcmp(), memcmp(), and related functions to automatically extract tokens. - See README.tokencap for more info. + See README.tokencap.md for more info. */ -- cgit 1.4.1 From 61e46a636ccf143dc648fef6189112dfdce37933 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 5 Nov 2019 10:59:22 +0000 Subject: catching current pid before library usage in case implementations rely on those string calls --- libtokencap/libtokencap.so.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'libtokencap') diff --git a/libtokencap/libtokencap.so.c b/libtokencap/libtokencap.so.c index 7495180d..467be05b 100644 --- a/libtokencap/libtokencap.so.c +++ b/libtokencap/libtokencap.so.c @@ -51,6 +51,7 @@ static struct mapping { void *st, *en; } __tokencap_ro[MAX_MAPPINGS]; static u32 __tokencap_ro_cnt; static u8 __tokencap_ro_loaded; static int __tokencap_out_file = -1; +static pid_t __tokencap_pid = -1; /* Identify read-only regions in memory. Only parameters that fall into these ranges are worth dumping when passed to strcmp() and so on. Read-write @@ -115,11 +116,11 @@ static void __tokencap_load_mappings(void) { #elif defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ #if defined __FreeBSD__ - int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, -1}; + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, __tokencap_pid}; #elif defined __OpenBSD__ - int mib[] = {CTL_KERN, KERN_PROC_VMMAP, getpid()}; + int mib[] = {CTL_KERN, KERN_PROC_VMMAP, __tokencap_pid}; #elif defined __NetBSD__ - int mib[] = {CTL_VM, VM_PROC, VM_PROC_MAP, getpid(), sizeof(struct kinfo_vmentry)}; + int mib[] = {CTL_VM, VM_PROC, VM_PROC_MAP, __tokencap_pid, sizeof(struct kinfo_vmentry)}; #endif char *buf, *low, *high; size_t miblen = sizeof(mib)/sizeof(mib[0]); @@ -431,6 +432,7 @@ __attribute__((constructor)) void __tokencap_init(void) { u8* fn = getenv("AFL_TOKEN_FILE"); if (fn) __tokencap_out_file = open(fn, O_RDWR | O_CREAT | O_APPEND, 0655); if (__tokencap_out_file == -1) __tokencap_out_file = STDERR_FILENO; + __tokencap_pid = getpid(); } -- cgit 1.4.1