aboutsummaryrefslogtreecommitdiff
path: root/custom_mutators
diff options
context:
space:
mode:
authorAlexander Shvedov <60114847+a-shvedov@users.noreply.github.com>2023-05-05 23:27:13 +0300
committerGitHub <noreply@github.com>2023-05-05 23:27:13 +0300
commit8012b555a8cbc49f1c78d4a33cad56ea59280780 (patch)
tree7795e30a1cec13eade2bc6e940dc66bb76898a49 /custom_mutators
parent8cdc48f73a17ddd557897f2098937a8ba3bfe184 (diff)
parent74be9ab5ce61d5b561faf688c245143da1a0141e (diff)
downloadafl++-8012b555a8cbc49f1c78d4a33cad56ea59280780.tar.gz
Merge pull request #1 from AFLplusplus/stable
sync
Diffstat (limited to 'custom_mutators')
-rw-r--r--custom_mutators/README.md41
-rw-r--r--custom_mutators/atnwalk/Makefile7
-rw-r--r--custom_mutators/atnwalk/README.md43
-rw-r--r--custom_mutators/atnwalk/atnwalk.c539
-rw-r--r--custom_mutators/autotokens/Makefile26
-rw-r--r--custom_mutators/autotokens/README34
-rw-r--r--custom_mutators/autotokens/autotokens.cpp1101
-rw-r--r--custom_mutators/examples/custom_mutator_helpers.h342
-rw-r--r--custom_mutators/examples/custom_send.c17
-rw-r--r--custom_mutators/examples/example.c116
-rw-r--r--custom_mutators/examples/post_library_gif.so.c53
-rw-r--r--custom_mutators/examples/post_library_png.so.c24
-rw-r--r--custom_mutators/examples/simple_example.c28
-rwxr-xr-xcustom_mutators/gramatron/build_gramatron_mutator.sh2
-rwxr-xr-xcustom_mutators/grammar_mutator/build_grammar_mutator.sh2
-rw-r--r--custom_mutators/honggfuzz/custom_mutator_helpers.h22
-rw-r--r--custom_mutators/honggfuzz/honggfuzz.c18
-rw-r--r--custom_mutators/honggfuzz/mangle.c1181
-rw-r--r--custom_mutators/libafl_base/Cargo.toml2
-rw-r--r--custom_mutators/libafl_base/src/lib.rs36
l---------custom_mutators/radamsa/custom_mutator_helpers.h1
-rw-r--r--custom_mutators/radamsa/radamsa-mutator.c11
-rw-r--r--custom_mutators/rust/custom_mutator-sys/Cargo.toml6
-rw-r--r--custom_mutators/rust/custom_mutator-sys/build.rs4
-rw-r--r--custom_mutators/rust/custom_mutator-sys/src/lib.rs2
-rw-r--r--custom_mutators/rust/custom_mutator/Cargo.toml2
-rw-r--r--custom_mutators/rust/custom_mutator/src/lib.rs109
-rw-r--r--custom_mutators/rust/example/Cargo.toml2
-rw-r--r--custom_mutators/rust/example_lain/Cargo.toml2
29 files changed, 2632 insertions, 1141 deletions
diff --git a/custom_mutators/README.md b/custom_mutators/README.md
index 0289e150..a5a572c0 100644
--- a/custom_mutators/README.md
+++ b/custom_mutators/README.md
@@ -11,7 +11,30 @@ The `./examples` folder contains examples for custom mutators in python and C.
In `./rust`, you will find rust bindings, including a simple example in `./rust/example` and an example for structured fuzzing, based on lain, in`./rust/example_lain`.
-## The AFL++ Grammar Mutator
+## Production-Ready Custom Mutators
+
+This directory holds ready to use custom mutators.
+Just type "make" in the individual subdirectories.
+
+Use with e.g.
+
+`AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/radamsa/radamsa-mutator.so afl-fuzz ....`
+
+and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
+
+Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
+
+### The AFL++ grammar agnostic grammar mutator
+
+In `./autotokens` you find a token-level fuzzer that does not need to know
+anything about the grammar of an input as long as it is in ascii and allows
+whitespace.
+It is very fast and effective.
+
+If you are looking for an example of how to effectively create a custom
+mutator take a look at this one.
+
+### The AFL++ Grammar Mutator
If you use git to clone AFL++, then the following will incorporate our
excellent grammar custom mutator:
@@ -24,18 +47,18 @@ Read the README in the [Grammar-Mutator] repository on how to use it.
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
-## Production-Ready Custom Mutators
-
-This directory holds ready to use custom mutators.
-Just type "make" in the individual subdirectories.
+Note that this custom mutator is not very good though!
-Use with e.g.
+### Other Mutators
-`AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/radamsa/radamsa-mutator.so afl-fuzz ....`
+atnwalk and gramatron are grammar custom mutators. Example grammars are
+provided.
-and add `AFL_CUSTOM_MUTATOR_ONLY=1` if you only want to use the custom mutator.
+honggfuzz, libfuzzer and libafl are partial implementations based on the
+mutator implementations of the respective fuzzers.
+More for playing than serious usage.
-Multiple custom mutators can be used by separating their paths with `:` in the environment variable.
+radamsa is slow and not very good.
## 3rd Party Custom Mutators
diff --git a/custom_mutators/atnwalk/Makefile b/custom_mutators/atnwalk/Makefile
new file mode 100644
index 00000000..bf83cae5
--- /dev/null
+++ b/custom_mutators/atnwalk/Makefile
@@ -0,0 +1,7 @@
+all: atnwalk.so
+
+atnwalk.so: atnwalk.c
+ $(CC) -I ../../include/ -shared -fPIC -O3 -o atnwalk.so atnwalk.c
+
+clean:
+ rm -f *.so *.o *~ core
diff --git a/custom_mutators/atnwalk/README.md b/custom_mutators/atnwalk/README.md
new file mode 100644
index 00000000..730349a3
--- /dev/null
+++ b/custom_mutators/atnwalk/README.md
@@ -0,0 +1,43 @@
+# ATNwalk: Grammar-Based Fuzzing using Only Bit-Mutations
+
+This is a custom mutator integration of ATNwalk that works by communicating via UNIX domain sockets.
+
+Refer to [https://github.com/atnwalk/testbed](https://github.com/atnwalk/testbed) for detailed instructions on how to get ATNwalk running.
+
+## Build
+
+Just type `make` to build `atnwalk.so`.
+
+## Run
+
+**NOTE:** The commands below just demonstrate an example how running ATNwalk looks like and require a working [testbed](https://github.com/atnwalk/testbed)
+
+```bash
+# create the required a random seed first
+mkdir -p ~/campaign/example/seeds
+cd ~/campaign/example/seeds
+head -c1 /dev/urandom | ~/atnwalk/build/javascript/bin/decode -wb > seed.decoded 2> seed.encoded
+
+# create the required atnwalk directory and copy the seed
+cd ../
+mkdir -p atnwalk/in
+cp ./seeds/seed.encoded atnwalk/in/seed
+cd atnwalk
+
+# assign to a single core when benchmarking it, change the CPU number as required
+CPU_ID=0
+
+# start the ATNwalk server
+nohup taskset -c ${CPU_ID} ${HOME}/atnwalk/build/javascript/bin/server 100 > server.log 2>&1 &
+
+# start AFL++ with ATNwalk
+AFL_SKIP_CPUFREQ=1 \
+ AFL_DISABLE_TRIM=1 \
+ AFL_CUSTOM_MUTATOR_ONLY=1 \
+ AFL_CUSTOM_MUTATOR_LIBRARY=${HOME}/AFLplusplus/custom_mutators/atnwalk/atnwalk.so \
+ AFL_POST_PROCESS_KEEP_ORIGINAL=1 \
+ ~/AFLplusplus/afl-fuzz -t 100 -i in/ -o out -b ${CPU_ID} -- ~/jerryscript/build/bin/jerry
+
+# make sure to kill the ATNwalk server process after you're done
+kill "$(cat atnwalk.pid)"
+```
diff --git a/custom_mutators/atnwalk/atnwalk.c b/custom_mutators/atnwalk/atnwalk.c
new file mode 100644
index 00000000..c3a2cd95
--- /dev/null
+++ b/custom_mutators/atnwalk/atnwalk.c
@@ -0,0 +1,539 @@
+#include "afl-fuzz.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#define BUF_SIZE_INIT 4096
+#define SOCKET_NAME "./atnwalk.socket"
+
+// how many errors (e.g. timeouts) to tolerate until moving on to the next queue
+// entry
+#define ATNWALK_ERRORS_MAX 1
+
+// how many execution timeouts to tolerate until moving on to the next queue
+// entry
+#define EXEC_TIMEOUT_MAX 2
+
+// handshake constants
+const uint8_t SERVER_ARE_YOU_ALIVE = 213;
+const uint8_t SERVER_YES_I_AM_ALIVE = 42;
+
+// control bits
+const uint8_t SERVER_CROSSOVER_BIT = 0b00000001;
+const uint8_t SERVER_MUTATE_BIT = 0b00000010;
+const uint8_t SERVER_DECODE_BIT = 0b00000100;
+const uint8_t SERVER_ENCODE_BIT = 0b00001000;
+
+typedef struct atnwalk_mutator {
+
+ afl_state_t *afl;
+ uint8_t atnwalk_error_count;
+ uint64_t prev_timeouts;
+ uint32_t prev_hits;
+ uint32_t stage_havoc_cur;
+ uint32_t stage_havoc_max;
+ uint32_t stage_splice_cur;
+ uint32_t stage_splice_max;
+ uint8_t *fuzz_buf;
+ size_t fuzz_size;
+ uint8_t *post_process_buf;
+ size_t post_process_size;
+
+} atnwalk_mutator_t;
+
+int read_all(int fd, uint8_t *buf, size_t buf_size) {
+
+ int n;
+ size_t offset = 0;
+ while (offset < buf_size) {
+
+ n = read(fd, buf + offset, buf_size - offset);
+ if (n == -1) { return 0; }
+ offset += n;
+
+ }
+
+ return 1;
+
+}
+
+int write_all(int fd, uint8_t *buf, size_t buf_size) {
+
+ int n;
+ size_t offset = 0;
+ while (offset < buf_size) {
+
+ n = write(fd, buf + offset, buf_size - offset);
+ if (n == -1) { return 0; }
+ offset += n;
+
+ }
+
+ return 1;
+
+}
+
+void put_uint32(uint8_t *buf, uint32_t val) {
+
+ buf[0] = (uint8_t)(val >> 24);
+ buf[1] = (uint8_t)((val & 0x00ff0000) >> 16);
+ buf[2] = (uint8_t)((val & 0x0000ff00) >> 8);
+ buf[3] = (uint8_t)(val & 0x000000ff);
+
+}
+
+uint32_t to_uint32(uint8_t *buf) {
+
+ uint32_t val = 0;
+ val |= (((uint32_t)buf[0]) << 24);
+ val |= (((uint32_t)buf[1]) << 16);
+ val |= (((uint32_t)buf[2]) << 8);
+ val |= ((uint32_t)buf[3]);
+ return val;
+
+}
+
+void put_uint64(uint8_t *buf, uint64_t val) {
+
+ buf[0] = (uint8_t)(val >> 56);
+ buf[1] = (uint8_t)((val & 0x00ff000000000000) >> 48);
+ buf[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40);
+ buf[3] = (uint8_t)((val & 0x000000ff00000000) >> 32);
+ buf[4] = (uint8_t)((val & 0x00000000ff000000) >> 24);
+ buf[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16);
+ buf[6] = (uint8_t)((val & 0x000000000000ff00) >> 8);
+ buf[7] = (uint8_t)(val & 0x00000000000000ff);
+
+}
+
+/**
+ * Initialize this custom mutator
+ *
+ * @param[in] afl a pointer to the internal state object. Can be ignored for
+ * now.
+ * @param[in] seed A seed for this mutator - the same seed should always mutate
+ * in the same way.
+ * @return Pointer to the data object this custom mutator instance should use.
+ * There may be multiple instances of this mutator in one afl-fuzz run!
+ * Return NULL on error.
+ */
+atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
+
+ srand(seed);
+ atnwalk_mutator_t *data =
+ (atnwalk_mutator_t *)malloc(sizeof(atnwalk_mutator_t));
+ if (!data) {
+
+ perror("afl_custom_init alloc");
+ return NULL;
+
+ }
+
+ data->afl = afl;
+ data->prev_hits = 0;
+ data->fuzz_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
+ data->fuzz_size = BUF_SIZE_INIT;
+ data->post_process_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
+ data->post_process_size = BUF_SIZE_INIT;
+ return data;
+
+}
+
+unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data,
+ const unsigned char *buf, size_t buf_size) {
+
+ // afl_custom_fuzz_count is called exactly once before entering the
+ // 'stage-loop' for the current queue entry thus, we use it to reset the error
+ // count and to initialize stage variables (somewhat not intended by the API,
+ // but still better than rewriting the whole thing to have a custom mutator
+ // stage)
+ data->atnwalk_error_count = 0;
+ data->prev_timeouts = data->afl->total_tmouts;
+
+ // it might happen that on the last execution of the splice stage a new path
+ // is found we need to fix that here and count it
+ if (data->prev_hits) {
+
+ data->afl->stage_finds[STAGE_SPLICE] +=
+ data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
+
+ }
+
+ data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
+ data->stage_havoc_cur = 0;
+ data->stage_splice_cur = 0;
+
+ // 50% havoc, 50% splice
+ data->stage_havoc_max = data->afl->stage_max >> 1;
+ if (data->stage_havoc_max < HAVOC_MIN) { data->stage_havoc_max = HAVOC_MIN; }
+ data->stage_splice_max = data->stage_havoc_max;
+ return data->stage_havoc_max + data->stage_splice_max;
+
+}
+
+size_t fail_fatal(int fd_socket, uint8_t **out_buf) {
+
+ if (fd_socket != -1) { close(fd_socket); }
+ *out_buf = NULL;
+ return 0;
+
+}
+
+size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf,
+ size_t buf_size, uint8_t **out_buf) {
+
+ if (fd_socket != -1) { close(fd_socket); }
+ data->atnwalk_error_count++;
+ if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) {
+
+ data->afl->stage_max = data->afl->stage_cur;
+
+ }
+
+ *out_buf = buf;
+ return buf_size;
+
+}
+
+/**
+ * Perform custom mutations on a given input
+ *
+ * (Optional for now. Required in the future)
+ *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
+ * @param[in] buf Pointer to input data to be mutated
+ * @param[in] buf_size Size of input data
+ * @param[out] out_buf the buffer we will work on. we can reuse *buf. NULL on
+ * error.
+ * @param[in] add_buf Buffer containing the additional test case
+ * @param[in] add_buf_size Size of the additional test case
+ * @param[in] max_size Maximum size of the mutated output. The mutation must not
+ * produce data larger than max_size.
+ * @return Size of the mutated output.
+ */
+size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size,
+ uint8_t **out_buf, uint8_t *add_buf, size_t add_buf_size,
+ size_t max_size) {
+
+ struct sockaddr_un addr;
+ int fd_socket;
+ uint8_t ctrl_buf[8];
+ uint8_t wanted;
+
+ // let's display what's going on in a nice way
+ if (data->stage_havoc_cur == 0) {
+
+ data->afl->stage_name = (uint8_t *)"atnwalk - havoc";
+
+ }
+
+ if (data->stage_havoc_cur == data->stage_havoc_max) {
+
+ data->afl->stage_name = (uint8_t *)"atnwalk - splice";
+
+ }
+
+ // increase the respective havoc or splice counters
+ if (data->stage_havoc_cur < data->stage_havoc_max) {
+
+ data->stage_havoc_cur++;
+ data->afl->stage_cycles[STAGE_HAVOC]++;
+
+ } else {
+
+ // if there is nothing to splice, continue with havoc and skip splicing this
+ // time
+ if (data->afl->ready_for_splicing_count < 1) {
+
+ data->stage_havoc_max = data->afl->stage_max;
+ data->stage_havoc_cur++;
+ data->afl->stage_cycles[STAGE_HAVOC]++;
+
+ } else {
+
+ data->stage_splice_cur++;
+ data->afl->stage_cycles[STAGE_SPLICE]++;
+
+ }
+
+ }
+
+ // keep track of found new corpus seeds per stage
+ if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) {
+
+ if (data->stage_splice_cur <= 1) {
+
+ data->afl->stage_finds[STAGE_HAVOC] +=
+ data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
+
+ } else {
+
+ data->afl->stage_finds[STAGE_SPLICE] +=
+ data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
+
+ }
+
+ }
+
+ data->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
+
+ // check whether this input produces a lot of timeouts, if it does then
+ // abandon this queue entry
+ if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) {
+
+ data->afl->stage_max = data->afl->stage_cur;
+ return fail_gracefully(-1, data, buf, buf_size, out_buf);
+
+ }
+
+ // initialize the socket
+ fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
+ if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
+
+ return fail_fatal(fd_socket, out_buf);
+
+ }
+
+ // ask whether the server is alive
+ ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
+ if (!write_all(fd_socket, ctrl_buf, 1)) {
+
+ return fail_fatal(fd_socket, out_buf);
+
+ }
+
+ // see whether the server replies as expected
+ if (!read_all(fd_socket, ctrl_buf, 1) ||
+ ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
+
+ return fail_fatal(fd_socket, out_buf);
+
+ }
+
+ // tell the server what we want to do
+ wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT;
+
+ // perform a crossover if we are splicing
+ if (data->stage_splice_cur > 0) { wanted |= SERVER_CROSSOVER_BIT; }
+
+ // tell the server what we want and how much data will be sent
+ ctrl_buf[0] = wanted;
+ put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
+ if (!write_all(fd_socket, ctrl_buf, 5)) {
+
+ return fail_fatal(fd_socket, out_buf);
+
+ }
+
+ // send the data to mutate and encode
+ if (!write_all(fd_socket, buf, buf_size)) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ if (wanted & SERVER_CROSSOVER_BIT) {
+
+ // since we requested crossover, we will first tell how much additional data
+ // is to be expected
+ put_uint32(ctrl_buf, (uint32_t)add_buf_size);
+ if (!write_all(fd_socket, ctrl_buf, 4)) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ // send the additional data for crossover
+ if (!write_all(fd_socket, add_buf, add_buf_size)) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ // lastly, a seed is required for crossover so send one
+ put_uint64(ctrl_buf, (uint64_t)rand());
+ if (!write_all(fd_socket, ctrl_buf, 8)) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ }
+
+ // since we requested mutation, we need to provide a seed for that
+ put_uint64(ctrl_buf, (uint64_t)rand());
+ if (!write_all(fd_socket, ctrl_buf, 8)) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ // obtain the required buffer size for the data that will be returned
+ if (!read_all(fd_socket, ctrl_buf, 4)) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ size_t new_size = (size_t)to_uint32(ctrl_buf);
+
+ // if the data is too large then we ignore this round
+ if (new_size > max_size) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ if (new_size > buf_size) {
+
+ // buf is too small, need to use data->fuzz_buf, let's see whether we need
+ // to reallocate
+ if (new_size > data->fuzz_size) {
+
+ data->fuzz_size = new_size << 1;
+ data->fuzz_buf = (uint8_t *)realloc(data->fuzz_buf, data->fuzz_size);
+
+ }
+
+ *out_buf = data->fuzz_buf;
+
+ } else {
+
+ // new_size fits into buf, so re-use it
+ *out_buf = buf;
+
+ }
+
+ // obtain the encoded data
+ if (!read_all(fd_socket, *out_buf, new_size)) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ close(fd_socket);
+ return new_size;
+
+}
+
+/**
+ * A post-processing function to use right before AFL writes the test case to
+ * disk in order to execute the target.
+ *
+ * (Optional) If this functionality is not needed, simply don't define this
+ * function.
+ *
+ * @param[in] data pointer returned in afl_custom_init for this fuzz case
+ * @param[in] buf Buffer containing the test case to be executed
+ * @param[in] buf_size Size of the test case
+ * @param[out] out_buf Pointer to the buffer containing the test case after
+ * processing. External library should allocate memory for out_buf.
+ * The buf pointer may be reused (up to the given buf_size);
+ * @return Size of the output buffer after processing or the needed amount.
+ * A return of 0 indicates an error.
+ */
+size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf,
+ size_t buf_size, uint8_t **out_buf) {
+
+ struct sockaddr_un addr;
+ int fd_socket;
+ uint8_t ctrl_buf[8];
+
+ // initialize the socket
+ fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
+ if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
+
+ return fail_fatal(fd_socket, out_buf);
+
+ }
+
+ // ask whether the server is alive
+ ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
+ if (!write_all(fd_socket, ctrl_buf, 1)) {
+
+ return fail_fatal(fd_socket, out_buf);
+
+ }
+
+ // see whether the server replies as expected
+ if (!read_all(fd_socket, ctrl_buf, 1) ||
+ ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
+
+ return fail_fatal(fd_socket, out_buf);
+
+ }
+
+ // tell the server what we want and how much data will be sent
+ ctrl_buf[0] = SERVER_DECODE_BIT;
+ put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
+ if (!write_all(fd_socket, ctrl_buf, 5)) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ // send the data to decode
+ if (!write_all(fd_socket, buf, buf_size)) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ // obtain the required buffer size for the data that will be returned
+ if (!read_all(fd_socket, ctrl_buf, 4)) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ size_t new_size = (size_t)to_uint32(ctrl_buf);
+
+ // need to use data->post_process_buf, let's see whether we need to reallocate
+ if (new_size > data->post_process_size) {
+
+ data->post_process_size = new_size << 1;
+ data->post_process_buf =
+ (uint8_t *)realloc(data->post_process_buf, data->post_process_size);
+
+ }
+
+ *out_buf = data->post_process_buf;
+
+ // obtain the decoded data
+ if (!read_all(fd_socket, *out_buf, new_size)) {
+
+ return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
+
+ }
+
+ close(fd_socket);
+ return new_size;
+
+}
+
+/**
+ * Deinitialize everything
+ *
+ * @param data The data ptr from afl_custom_init
+ */
+void afl_custom_deinit(atnwalk_mutator_t *data) {
+
+ free(data->fuzz_buf);
+ free(data->post_process_buf);
+ free(data);
+
+}
+
diff --git a/custom_mutators/autotokens/Makefile b/custom_mutators/autotokens/Makefile
new file mode 100644
index 00000000..0daba17d
--- /dev/null
+++ b/custom_mutators/autotokens/Makefile
@@ -0,0 +1,26 @@
+ifdef debug
+ CPPLAGS += -fsanitize=address
+ CXXFLAGS += -Wall
+ CC := clang
+ CXX := clang++
+endif
+ifdef DEBUG
+ CPPFLAGS += -fsanitize=address
+ CXXFLAGS += -Wall
+ CC := clang
+ CXX := clang++
+endif
+
+all: autotokens.so
+
+afl-fuzz-queue.o: ../../src/afl-fuzz-queue.c
+ $(CC) -D_STANDALONE_MODULE=1 -I../../include -g -O3 $(CPPFLAGS) -fPIC -c -o ./afl-fuzz-queue.o ../../src/afl-fuzz-queue.c
+
+afl-common.o: ../../src/afl-common.c
+ $(CC) -I../../include -g -O3 $(CPPFLAGS) -DBIN_PATH=\"dummy\" -Wno-pointer-sign -fPIC -c -o ./afl-common.o ../../src/afl-common.c
+
+autotokens.so: afl-fuzz-queue.o afl-common.o autotokens.cpp
+ $(CXX) -Wno-deprecated -g -O3 $(CXXFLAGS) $(CPPFLAGS) -shared -fPIC -o autotokens.so -I../../include autotokens.cpp ./afl-fuzz-queue.o ../../src/afl-performance.o ./afl-common.o
+
+clean:
+ rm -f autotokens.so *.o *~ core
diff --git a/custom_mutators/autotokens/README b/custom_mutators/autotokens/README
new file mode 100644
index 00000000..cca168fd
--- /dev/null
+++ b/custom_mutators/autotokens/README
@@ -0,0 +1,34 @@
+# Autotokens
+
+This implements an improved autotoken grammar fuzzing idea presented in
+[Token-Level Fuzzing][https://www.usenix.org/system/files/sec21-salls.pdf].
+It is a grammar fuzzer without actually knowing the grammar, but only works
+with text based inputs.
+
+It is recommended to run with together in an instance with `CMPLOG`.
+
+If you have a dictionary (`-x`) this improves this custom grammar mutator.
+
+If **not** running with `CMPLOG`, it is possible to set
+`AFL_CUSTOM_MUTATOR_ONLY` to concentrate on grammar bug classes.
+
+Do **not** set `AFL_DISABLE_TRIM` with this custom mutator!
+
+## Configuration via environment variables
+
+`AUTOTOKENS_ONLY_FAV` - only use this mutator on favorite queue items
+`AUTOTOKENS_COMMENT` - what character or string starts a comment which will be
+ removed. Default: `/* ... */`
+`AUTOTOKENS_FUZZ_COUNT_SHIFT` - reduce the number of fuzzing performed, shifting
+ the value by this number, e.g. 1.
+`AUTOTOKENS_AUTO_DISABLE` - disable this module if the seeds are not ascii
+ (or no input and no (ascii) dictionary)
+`AUTOTOKENS_LEARN_DICT` - learn from dictionaries?
+ 0 = none
+ 1 = only -x or autodict
+ 2 = -x, autodict and `CMPLOG`
+`AUTOTOKENS_CHANGE_MIN` - minimum number of mutations (1-256, default 8)
+`AUTOTOKENS_CHANGE_MAX` - maximum number of mutations (1-4096, default 64)
+`AUTOTOKENS_CREATE_FROM_THIN_AIR` - if only one small start file is present and
+ a dictionary loaded then create one initial
+ structure based on the dictionary.
diff --git a/custom_mutators/autotokens/autotokens.cpp b/custom_mutators/autotokens/autotokens.cpp
new file mode 100644
index 00000000..8135aba1
--- /dev/null
+++ b/custom_mutators/autotokens/autotokens.cpp
@@ -0,0 +1,1101 @@
+/*
+ token level fuzzing custom mutator for afl++
+ (c) by Marc Heuse <mh@mh-sec.de>
+ License: Apache 2.0
+*/
+
+extern "C" {
+
+#include "afl-fuzz.h"
+
+}
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <iostream>
+#include <fstream>
+#include <unordered_map>
+#include <vector>
+#include <regex>
+
+#define AUTOTOKENS_DEBUG 0
+#define AUTOTOKENS_ONLY_FAV 0
+#define AUTOTOKENS_CHANGE_MIN 8
+#define AUTOTOKENS_CHANGE_MAX 64
+#define AUTOTOKENS_SIZE_MIN 8
+#define AUTOTOKENS_SIZE_MAX 65535
+#define AUTOTOKENS_SPLICE_MIN 4
+#define AUTOTOKENS_SPLICE_MAX 64
+#define AUTOTOKENS_CREATE_FROM_THIN_AIR 0
+#define AUTOTOKENS_FUZZ_COUNT_SHIFT 0
+#define AUTOTOKENS_AUTO_DISABLE 0
+// 0 = no learning, 1 only from -x dict/autodict, 2 also from cmplog
+#define AUTOTOKENS_LEARN_DICT 1
+#ifndef AUTOTOKENS_SPLICE_DISABLE
+ #define AUTOTOKENS_SPLICE_DISABLE 0
+#endif
+#ifndef AFL_TXT_MAX_LEN
+ #define AFL_TXT_MAX_LEN 65535
+#endif
+
+#if AUTOTOKENS_SPLICE_MIN >= AUTOTOKENS_SIZE_MIN
+ #error SPLICE_MIN must be lower than SIZE_MIN
+#endif
+
+using namespace std;
+
+typedef struct my_mutator {
+
+ afl_state *afl;
+
+} my_mutator_t;
+
+#undef DEBUGF
+#define DEBUGF \
+ if (unlikely(debug)) fprintf
+#define IFDEBUG if (unlikely(debug))
+
+static afl_state *afl_ptr;
+static int module_disabled = 0;
+static int auto_disable = AUTOTOKENS_AUTO_DISABLE;
+static int debug = AUTOTOKENS_DEBUG;
+static int only_fav = AUTOTOKENS_ONLY_FAV;
+static int learn_dictionary_tokens = AUTOTOKENS_LEARN_DICT;
+static int fuzz_count_shift = AUTOTOKENS_FUZZ_COUNT_SHIFT;
+static int create_from_thin_air = AUTOTOKENS_CREATE_FROM_THIN_AIR;
+static int change_min = AUTOTOKENS_CHANGE_MIN;
+static int change_max = AUTOTOKENS_CHANGE_MAX;
+static u32 current_id;
+static u32 valid_structures;
+static u32 whitespace_ids;
+static u32 extras_cnt, a_extras_cnt;
+static u64 all_spaces, all_tabs, all_lf, all_ws;
+static u64 all_structure_items;
+static u64 fuzz_count;
+static unordered_map<string, vector<u32> *> file_mapping;
+static unordered_map<u32, vector<u32> *> id_mapping;
+static unordered_map<string, u32> token_to_id;
+static unordered_map<u32, string> id_to_token;
+static string output;
+static regex *regex_comment_custom;
+// multiline requires g++-11 libs :(
+static regex regex_comment_star(
+ "/\\*([:print:]|\n)*?\\*/",
+ regex_constants::optimize /* | regex_constants::multiline */);
+static regex regex_word("[A-Za-z0-9_$.-]+", regex::optimize);
+static regex regex_whitespace(R"([ \t]+)", regex::optimize);
+static vector<u32> *s; // the structure of the currently selected input
+
+// FUNCTIONS
+
+/* This function is called once after everything is set up but before
+ any fuzzing attempt has been performed.
+ This is called in afl_custom_queue_get() */
+static void first_run(void *data) {
+
+ (void)(data);
+
+ /* For auto-loading this module we check here if we can analyze from the
+ input if the inputs look like text inputs and disable the module if
+ not. */
+
+ if (afl_ptr->custom_only || !auto_disable) { return; }
+
+ if (unlikely(afl_ptr->active_items == 1 &&
+ afl_ptr->queue_cur->len < AFL_TXT_MIN_LEN)) {
+
+ if (afl_ptr->extras_cnt > 8) {
+
+ u32 valid = 0;
+
+ while (extras_cnt < afl_ptr->extras_cnt) {
+
+ u32 ok = 1, l = afl_ptr->extras[extras_cnt].len;
+ u8 *buf, *ptr = afl_ptr->extras[extras_cnt].data;
+
+ for (u32 i = 0; i < l; ++i) {
+
+ if (!isascii((int)ptr[i]) && !isprint((int)ptr[i])) {
+
+ ok = 0;
+ break;
+
+ }
+
+ }
+
+ if (ok) {
+
+ buf = (u8 *)malloc(afl_ptr->extras[extras_cnt].len + 1);
+ memcpy(buf, afl_ptr->extras[extras_cnt].data,
+ afl_ptr->extras[extras_cnt].len);
+ buf[afl_ptr->extras[extras_cnt].len] = 0;
+ token_to_id[(char *)buf] = current_id;
+ id_to_token[current_id] = (char *)buf;
+ ++current_id;
+ ++valid;
+
+ }
+
+ ++extras_cnt;
+
+ }
+
+ if ((valid * 100) / afl_ptr->extras_cnt <= 70) { module_disabled = 1; }
+
+ DEBUGF(stderr, "DICT: total %u, valid %u, %u <= 70 == disable\n",
+ afl_ptr->extras_cnt, valid,
+ (u32)((valid * 100) / afl_ptr->extras_cnt));
+
+ } else {
+
+ module_disabled = 1;
+
+ }
+
+ return;
+
+ }
+
+ u32 is_ascii = 0, valid = 0;
+
+ for (u32 i = 0; i < afl_ptr->queued_items; ++i) {
+
+ struct queue_entry *q;
+
+ q = afl_ptr->queue_buf[i];
+
+ if (!q->disabled && q->len >= AUTOTOKENS_SIZE_MIN &&
+ q->len <= AFL_TXT_MAX_LEN) {
+
+ ++valid;
+ u8 *input = queue_testcase_get(afl_ptr, q);
+
+ u32 valid_chars = 0;
+ for (u32 i = 0; i < q->len; ++i) {
+
+ if (isascii((int)input[i]) || isprint((int)input[i])) { ++valid_chars; }
+
+ }
+
+ // we want at least 99% of text characters ...
+ if (((q->len * AFL_TXT_MIN_PERCENT) / 100) <= valid_chars) {
+
+ ++is_ascii;
+ q->is_ascii = 1;
+
+ }
+
+ }
+
+ }
+
+ if ((is_ascii * 100) / valid <= 70) { module_disabled = 1; }
+
+ DEBUGF(stderr, "seeds: total %u, valid %u, ascii %u, %u <= 70 == disabled\n",
+ afl_ptr->active_items, valid, is_ascii,
+ (u32)((is_ascii * 100) / valid));
+
+}
+
+static u32 good_whitespace_or_singleval() {
+
+ u32 i = rand_below(afl_ptr, current_id);
+ if (id_to_token[i].size() == 1) { return i; }
+ i = rand_below(afl_ptr, all_ws);
+ if (i < all_spaces) {
+
+ return 0;
+
+ } else if (i < all_tabs) {
+
+ return 1;
+
+ } else
+
+ return 2; // linefeed
+
+}
+
+extern "C" u32 afl_custom_fuzz_count(void *data, const u8 *buf,
+ size_t buf_size) {
+
+ (void)(data);
+
+ if (s == NULL) return 0;
+
+ u32 shift = unlikely(afl_ptr->custom_only) ? 7 : 8;
+ u32 stage_max = (u32)((HAVOC_CYCLES * afl_ptr->queue_cur->perf_score) /
+ afl_ptr->havoc_div) >>
+ shift;
+ if (fuzz_count_shift) { stage_max >>= (u32)fuzz_count_shift; };
+ DEBUGF(stderr, "fuzz count: %u\n", stage_max);
+
+ return stage_max;
+
+}
+
+extern "C" size_t afl_custom_fuzz(my_mutator_t *data, u8 *buf, size_t buf_size,
+ u8 **out_buf, u8 *add_buf,
+ size_t add_buf_size, size_t max_size) {
+
+ (void)(data);
+
+ if (unlikely(s == NULL)) {
+
+ *out_buf = NULL;
+ return 0;
+
+ }
+
+ vector<u32> m = *s; // copy of the structure we will modify
+ u32 i, m_size = (u32)m.size();
+
+ u32 rounds =
+ MIN(change_max,
+ MAX(change_min,
+ MIN(m_size >> 3, HAVOC_CYCLES * afl_ptr->queue_cur->perf_score *
+ afl_ptr->havoc_div / 256)));
+ // DEBUGF(stderr, "structure size: %lu, rounds: %u \n", m.size(), rounds);
+
+#if AUTOTOKENS_SPLICE_DISABLE == 1
+ #define AUTOTOKENS_MUT_MAX 18
+#else
+ #define AUTOTOKENS_MUT_MAX 27
+#endif
+
+ u32 max_rand = AUTOTOKENS_MUT_MAX, new_item, pos;
+
+ for (i = 0; i < rounds; ++i) {
+
+ switch (rand_below(afl_ptr, max_rand)) {
+
+ /* CHANGE/MUTATE single item */
+ case 0 ... 9: {
+
+ pos = rand_below(afl_ptr, m_size);
+ u32 cur_item = m[pos];
+ do {
+
+ new_item = rand_below(afl_ptr, current_id);
+
+ } while (unlikely(
+
+ new_item == cur_item ||
+ ((whitespace_ids < new_item && whitespace_ids >= cur_item) ||
+ (whitespace_ids >= new_item && whitespace_ids < cur_item))));
+
+ // DEBUGF(stderr, "MUT: %u -> %u\n", cur_item, new_item);
+ m[pos] = new_item;
+ break;
+
+ }
+
+ /* INSERT (m_size +1 so we insert also after last place) */
+ case 10 ... 13: {
+
+ do {
+
+ new_item = rand_below(afl_ptr, current_id);
+
+ } while (unlikely(new_item >= whitespace_ids));
+
+ u32 pos = rand_below(afl_ptr, m_size + 1);
+ m.insert(m.begin() + pos, new_item);
+ ++m_size;
+ // DEBUGF(stderr, "INS: %u at %u\n", new_item, pos);
+
+ break;
+
+ }
+
+#if AUTOTOKENS_SPLICE_DISABLE != 1
+ /* SPLICING */
+ case 14 ... 22: {
+
+ u32 strategy = rand_below(afl_ptr, 4), dst_off, n;
+ auto src = id_mapping[rand_below(afl_ptr, valid_structures)];
+ u32 src_size = src->size();
+ u32 src_off = rand_below(afl_ptr, src_size - AUTOTOKENS_SPLICE_MIN);
+ u32 rand_r = 1 + MAX(AUTOTOKENS_SPLICE_MIN,
+ MIN(AUTOTOKENS_SPLICE_MAX, src_size - src_off));
+
+ switch (strategy) {
+
+ // insert
+ case 0: {
+
+ dst_off = rand_below(afl_ptr, m_size);
+ n = AUTOTOKENS_SPLICE_MIN +
+ rand_below(afl_ptr, MIN(AUTOTOKENS_SPLICE_MAX,
+ rand_r - AUTOTOKENS_SPLICE_MIN));
+ m.insert(m.begin() + dst_off, src->begin() + src_off,
+ src->begin() + src_off + n);
+ m_size += n;
+ // DEBUGF(stderr, "SPLICE-INS: %u at %u\n", n, dst_off);
+
+ break;
+
+ }
+
+ // overwrite
+ default: {
+
+ dst_off = rand_below(afl_ptr, m_size - AUTOTOKENS_SPLICE_MIN);
+ n = AUTOTOKENS_SPLICE_MIN +
+ rand_below(
+ afl_ptr,
+ MIN(AUTOTOKENS_SPLICE_MAX - AUTOTOKENS_SPLICE_MIN,
+ MIN(m_size - dst_off - AUTOTOKENS_SPLICE_MIN,
+ src_size - src_off - AUTOTOKENS_SPLICE_MIN)));
+
+ copy(src->begin() + src_off, src->begin() + src_off + n,
+ m.begin() + dst_off);
+
+ // DEBUGF(stderr, "SPLICE-MUT: %u at %u\n", n, dst_off);
+ break;
+
+ }
+
+ }
+
+ break;
+
+ }
+
+#endif
+
+ /* ERASE - only if large enough */
+ default: {
+
+ if (m_size > 8) {
+
+ do {
+
+ pos = rand_below(afl_ptr, m_size);
+
+ } while (unlikely(m[pos] < whitespace_ids));
+
+ m.erase(m.begin() + pos);
+ --m_size;
+
+ } else {
+
+ // if the data is already too small do not try to make it smaller
+ // again this run.
+
+ max_rand -= 4;
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ /* Now we create the output */
+
+ output = "";
+ u32 prev_size = 1, was_whitespace = 1;
+
+ for (i = 0; i < m_size; ++i) {
+
+ if (likely(i + 1 < m_size)) {
+
+ u32 this_size = id_to_token[m[i]].size();
+ u32 is_whitespace = m[i] < whitespace_ids;
+
+ /* The output we are generating might need repairing.
+ General rule: two items that have a size larger than 2 are strings
+ or identifizers and need a whitespace or an item of length 1 in
+ between. */
+ if (unlikely(!(prev_size == 1 || was_whitespace || this_size == 1 ||
+ is_whitespace))) {
+
+ output += id_to_token[good_whitespace_or_singleval()];
+
+ }
+
+ prev_size = this_size;
+ was_whitespace = is_whitespace;
+
+ }
+
+ output += id_to_token[m[i]];
+
+ }
+
+ u32 mutated_size = (u32)output.size();
+ u8 *mutated_out = (u8 *)output.data();
+
+ if (unlikely(mutated_size > max_size)) { mutated_size = max_size; }
+
+ /*
+ IFDEBUG {
+
+ DEBUGF(stderr, "MUTATED to %u bytes:\n", mutated_size);
+ fwrite(output.data(), 1, mutated_size, stderr);
+ DEBUGF(stderr, "\n---\n");
+
+ }
+
+ */
+
+ *out_buf = mutated_out;
+ ++fuzz_count;
+ return mutated_size;
+
+}
+
+/* I get f*cking stack overflow using C++ regex with a regex of
+ "\"[[:print:]]*?\"" if this matches a long string even with regex::optimize
+ enabled :-( */
+static u8 my_search_string(string::const_iterator cur,
+ string::const_iterator ende,
+ string::const_iterator *match_begin,
+ string::const_iterator *match_end) {
+
+ string::const_iterator start = cur, found_begin;
+ u8 quote_type = 0;
+
+ while (cur < ende) {
+
+ switch (*cur) {
+
+ case '"': {
+
+ if (cur == start || *(cur - 1) != '\\') {
+
+ if (!quote_type) {
+
+ found_begin = cur;
+ quote_type = 1;
+
+ } else if (quote_type == 1) {
+
+ *match_begin = found_begin;
+ *match_end = cur + 1;
+ return 1;
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ case '\'': {
+
+ if (cur == start || *(cur - 1) != '\\') {
+
+ if (!quote_type) {
+
+ found_begin = cur;
+ quote_type = 2;
+
+ } else if (quote_type == 2) {
+
+ *match_begin = found_begin;
+ *match_end = cur + 1;
+ return 1;
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ case '\n':
+ case '\r':
+ case 0: {
+
+ quote_type = 0;
+ break;
+
+ }
+
+ default:
+ if (unlikely(quote_type && !isprint(*cur))) { quote_type = 0; }
+ break;
+
+ }
+
+ ++cur;
+
+ }
+
+ return 0;
+
+}
+
+/* We are not using afl_custom_queue_new_entry() because not every corpus entry
+ will be necessarily fuzzed with this custom mutator.
+ So we use afl_custom_queue_get() instead. */
+
+extern "C" unsigned char afl_custom_queue_get(void *data,
+ const unsigned char *filename) {
+
+ static int learn_state = 0;
+ static int is_first_run = 1;
+ (void)(data);
+
+ if (unlikely(is_first_run)) {
+
+ is_first_run = 0;
+ first_run(data);
+
+ if (module_disabled) {
+
+ WARNF("Autotokens custom module is disabled.");
+
+ } else if (auto_disable) {
+
+ OKF("Autotokens custom module is enabled.");
+
+ }
+
+ }
+
+ if (likely(module_disabled) ||
+ (unlikely(!afl_ptr->custom_only) && !create_from_thin_air &&
+ ((afl_ptr->shm.cmplog_mode && !afl_ptr->queue_cur->is_ascii) ||
+ (only_fav && !afl_ptr->queue_cur->favored)))) {
+
+ s = NULL;
+ DEBUGF(stderr,
+ "cmplog not ascii or only_fav and not favorite or disabled\n");
+ return 1;
+
+ }
+
+ // check if there are new dictionary entries and add them to the tokens
+ if (unlikely(learn_state < learn_dictionary_tokens) &&
+ likely(valid_structures || create_from_thin_air)) {
+
+ if (unlikely(!learn_state)) { learn_state = 1; }
+
+ while (extras_cnt < afl_ptr->extras_cnt) {
+
+ u32 ok = 1, l = afl_ptr->extras[extras_cnt].len;
+ u8 *buf, *ptr = afl_ptr->extras[extras_cnt].data;
+
+ for (u32 i = 0; i < l; ++i) {
+
+ if (!isascii((int)ptr[i]) && !isprint((int)ptr[i])) {
+
+ ok = 0;
+ break;
+
+ }
+
+ }
+
+ if (ok) {
+
+ buf = (u8 *)malloc(afl_ptr->extras[extras_cnt].len + 1);
+ memcpy(buf, afl_ptr->extras[extras_cnt].data,
+ afl_ptr->extras[extras_cnt].len);
+ buf[afl_ptr->extras[extras_cnt].len] = 0;
+ token_to_id[(char *)buf] = current_id;
+ id_to_token[current_id] = (char *)buf;
+ ++current_id;
+
+ }
+
+ ++extras_cnt;
+
+ }
+
+ while (a_extras_cnt < afl_ptr->a_extras_cnt) {
+
+ u32 ok = 1, l = afl_ptr->a_extras[a_extras_cnt].len;
+ u8 *ptr = afl_ptr->a_extras[a_extras_cnt].data;
+
+ for (u32 i = 0; i < l; ++i) {
+
+ if (!isascii((int)ptr[i]) && !isprint((int)ptr[i])) {
+
+ ok = 0;
+ break;
+
+ }
+
+ }
+
+ if (ok) {
+
+ token_to_id[(char *)ptr] = current_id;
+ id_to_token[current_id] = (char *)ptr;
+ ++current_id;
+
+ }
+
+ ++a_extras_cnt;
+
+ }
+
+ }
+
+ vector<u32> *structure = NULL;
+ string fn = (char *)filename;
+ auto entry = file_mapping.find(fn);
+
+ // if there is only one active queue item at start and it is very small
+ // the we create once a structure randomly.
+ if (unlikely(create_from_thin_air)) {
+
+ if (current_id > whitespace_ids + 6 && afl_ptr->active_items == 1 &&
+ afl_ptr->queue_cur->len < AFL_TXT_MIN_LEN) {
+
+ DEBUGF(stderr, "Creating an entry from thin air...\n");
+ structure = new vector<u32>();
+ u32 item, prev, cnt = current_id >> 1;
+ structure->reserve(cnt + 4);
+ for (u32 i = 0; i < cnt; i++) {
+
+ item = rand_below(afl_ptr, current_id);
+ if (i && id_to_token[item].length() > 1 &&
+ id_to_token[prev].length() > 1) {
+
+ structure->push_back(good_whitespace_or_singleval());
+
+ }
+
+ structure->push_back(item);
+ prev = item;
+
+ }
+
+ s = structure;
+ file_mapping[fn] = structure;
+ id_mapping[valid_structures] = structure;
+ ++valid_structures;
+ all_structure_items += structure->size();
+
+ return 1;
+
+ }
+
+ create_from_thin_air = 0;
+
+ }
+
+ if (entry == file_mapping.end()) {
+
+ // this input file was not analyzed for tokens yet, so let's do it!
+ size_t len = afl_ptr->queue_cur->len;
+
+ if (len < AFL_TXT_MIN_LEN) {
+
+ file_mapping[fn] = structure; // NULL ptr so we don't read the file again
+ s = NULL;
+ DEBUGF(stderr, "Too short (%lu) %s\n", len, filename);
+ return 1;
+
+ } else if (len > AFL_TXT_MAX_LEN) {
+
+ file_mapping[fn] = structure; // NULL ptr so we don't read the file again
+ s = NULL;
+ DEBUGF(stderr, "Too long (%lu) %s\n", len, filename);
+ return 1;
+
+ }
+
+ u8 *input_buf = queue_testcase_get(afl_ptr, afl_ptr->queue_cur);
+ string input((char *)input_buf, afl_ptr->queue_cur->len);
+
+ if (!afl_ptr->shm.cmplog_mode) {
+
+ // not running with CMPLOG? bad choice, but whatever ...
+ // we only want text inputs, so we have to check it ourselves.
+
+ u32 valid_chars = 0;
+ for (u32 i = 0; i < len; ++i) {
+
+ if (isascii((int)input[i]) || isprint((int)input[i])) { ++valid_chars; }
+
+ }
+
+ // we want at least 95% of text characters ...
+ if (((len * AFL_TXT_MIN_PERCENT) / 100) > valid_chars) {
+
+ file_mapping[fn] = NULL;
+ s = NULL;
+ DEBUGF(stderr, "Not text (%lu) %s\n", len, filename);
+ return 1;
+
+ }
+
+ }
+
+ // DEBUGF(stderr, "Read %lu bytes for %s\nBefore comment trim:\n%s\n",
+ // input.size(), filename, input.c_str());
+
+ if (regex_comment_custom) {
+
+ input = regex_replace(input, *regex_comment_custom, "$2");
+
+ } else {
+
+ input = regex_replace(input, regex_comment_star, "");
+
+ }
+
+ DEBUGF(stderr, "After replace %lu bytes for %s\n%s\n", input.size(),
+ filename, input.c_str());
+
+ u32 spaces = count(input.begin(), input.end(), ' ');
+ u32 tabs = count(input.begin(), input.end(), '\t');
+ u32 linefeeds = count(input.begin(), input.end(), '\n');
+ bool ends_with_linefeed = input[input.length() - 1] == '\n';
+
+ DEBUGF(stderr, "spaces=%u tabs=%u linefeeds=%u ends=%u\n", spaces, tabs,
+ linefeeds, ends_with_linefeed);
+
+ all_spaces += spaces;
+ all_tabs += tabs;
+ all_lf += linefeeds;
+ all_ws = all_spaces + all_tabs + all_lf;
+
+ // now extract all tokens
+ vector<string> tokens;
+ string::const_iterator cur = input.begin(), ende = input.end(), found, prev,
+ match_begin, match_end;
+
+ DEBUGF(stderr, "START!\n");
+
+ while (my_search_string(cur, ende, &match_begin, &match_end)) {
+
+ prev = cur;
+ found = match_begin;
+ cur = match_end;
+
+ IFDEBUG {
+
+ string foo(match_begin, match_end);
+ DEBUGF(stderr,
+ "string %s found at start %lu offset %lu continue at %lu\n",
+ foo.c_str(), prev - input.begin(), found - prev,
+ cur - input.begin());
+
+ }
+
+ if (prev < found) { // there are items between search start and find
+ while (prev < found) {
+
+ if (isspace(*prev)) {
+
+ auto start = prev;
+ while (isspace(*prev)) {
+
+ ++prev;
+
+ }
+
+ tokens.push_back(std::string(start, prev));
+ DEBUGF(stderr, "WHITESPACE %ld \"%s\"\n", prev - start,
+ tokens[tokens.size() - 1].c_str());
+
+ } else if (isalnum(*prev) || *prev == '$' || *prev == '_') {
+
+ auto start = prev;
+ while (isalnum(*prev) || *prev == '$' || *prev == '_' ||
+ *prev == '.' || *prev == '/') {
+
+ ++prev;
+
+ }
+
+ tokens.push_back(string(start, prev));
+ DEBUGF(stderr, "IDENTIFIER %ld \"%s\"\n", prev - start,
+ tokens[tokens.size() - 1].c_str());
+
+ } else {
+
+ tokens.push_back(string(prev, prev + 1));
+ DEBUGF(stderr, "OTHER \"%c\"\n", *prev);
+ ++prev;
+
+ }
+
+ }
+
+ }
+
+ tokens.push_back(string(match_begin, match_end));
+ DEBUGF(stderr, "TOK: %s\n", tokens[tokens.size() - 1].c_str());
+
+ }
+
+ DEBUGF(stderr, "AFTER all strings\n");
+
+ if (cur < ende) {
+
+ while (cur < ende) {
+
+ if (isspace(*cur)) {
+
+ auto start = cur;
+ while (isspace(*cur)) {
+
+ ++cur;
+
+ }
+
+ tokens.push_back(std::string(start, cur));
+ DEBUGF(stderr, "WHITESPACE %ld \"%s\"\n", cur - start,
+ tokens[tokens.size() - 1].c_str());
+
+ } else if (isalnum(*cur) || *cur == '$' || *cur == '_') {
+
+ auto start = cur;
+ while (isalnum(*cur) || *cur == '$' || *cur == '_' || *cur == '.' ||
+ *cur == '/') {
+
+ ++cur;
+
+ }
+
+ tokens.push_back(std::string(start, cur));
+ DEBUGF(stderr, "IDENTIFIER %ld \"%s\"\n", cur - start,
+ tokens[tokens.size() - 1].c_str());
+
+ } else {
+
+ tokens.push_back(std::string(cur, cur + 1));
+ DEBUGF(stderr, "OTHER \"%c\"\n", *cur);
+ ++cur;
+
+ }
+
+ }
+
+ }
+
+ IFDEBUG {
+
+ DEBUGF(stderr, "DUMPING TOKENS:\n");
+ for (u32 i = 0; i < tokens.size(); ++i) {
+
+ DEBUGF(stderr, "%s", tokens[i].c_str());
+
+ }
+
+ DEBUGF(stderr, "---------------------------\n");
+
+ }
+
+ if (tokens.size() < AUTOTOKENS_SIZE_MIN) {
+
+ file_mapping[fn] = NULL;
+ s = NULL;
+ DEBUGF(stderr, "too few tokens\n");
+ return 1;
+
+ }
+
+ /* Now we transform the tokens into an ID list and saved that */
+
+ structure = new vector<u32>();
+ u32 id;
+
+ for (u32 i = 0; i < tokens.size(); ++i) {
+
+ if ((id = token_to_id[tokens[i]]) == 0) {
+
+ // First time we see this token, add it to the list
+ token_to_id[tokens[i]] = current_id;
+ id_to_token[current_id] = tokens[i];
+ structure->push_back(current_id);
+ ++current_id;
+
+ } else {
+
+ structure->push_back(id);
+
+ }
+
+ }
+
+ // save the token structure to the file mapping
+ file_mapping[fn] = structure;
+ id_mapping[valid_structures] = structure;
+ ++valid_structures;
+ s = structure;
+ all_structure_items += structure->size();
+
+ // we are done!
+ DEBUGF(stderr, "DONE! We have %lu tokens in the structure\n",
+ structure->size());
+
+ } else {
+
+ if (entry->second == NULL) {
+
+ DEBUGF(stderr, "Skipping %s\n", filename);
+ s = NULL;
+ return 1;
+
+ }
+
+ s = entry->second;
+ DEBUGF(stderr, "OK %s\n", filename);
+
+ }
+
+ return 1; // we always fuzz unless non-ascii or too small
+
+}
+
+extern "C" my_mutator_t *afl_custom_init(afl_state *afl, unsigned int seed) {
+
+ (void)(seed);
+ my_mutator_t *data = (my_mutator_t *)calloc(1, sizeof(my_mutator_t));
+ if (!data) {
+
+ perror("afl_custom_init alloc");
+ return NULL;
+
+ }
+
+ if (getenv("AUTOTOKENS_DEBUG")) { debug = 1; }
+ if (getenv("AUTOTOKENS_AUTO_DISABLE")) { auto_disable = 1; }
+ if (getenv("AUTOTOKENS_ONLY_FAV")) { only_fav = 1; }
+ if (getenv("AUTOTOKENS_CREATE_FROM_THIN_AIR")) { create_from_thin_air = 1; }
+
+ if (getenv("AUTOTOKENS_LEARN_DICT")) {
+
+ learn_dictionary_tokens = atoi(getenv("AUTOTOKENS_LEARN_DICT"));
+ if (learn_dictionary_tokens < 0 || learn_dictionary_tokens > 2) {
+
+ learn_dictionary_tokens = AUTOTOKENS_LEARN_DICT;
+
+ }
+
+ }
+
+ if (getenv("AUTOTOKENS_FUZZ_COUNT_SHIFT")) {
+
+ fuzz_count_shift = atoi(getenv("AUTOTOKENS_FUZZ_COUNT_SHIFT"));
+ if (fuzz_count_shift < 0 || fuzz_count_shift > 16) { fuzz_count_shift = 0; }
+
+ }
+
+ if (getenv("AUTOTOKENS_CHANGE_MIN")) {
+
+ change_min = atoi(getenv("AUTOTOKENS_CHANGE_MIN"));
+ if (change_min < 1 || change_min > 256) {
+
+ change_min = AUTOTOKENS_CHANGE_MIN;
+
+ }
+
+ }
+
+ if (getenv("AUTOTOKENS_CHANGE_MAX")) {
+
+ change_max = atoi(getenv("AUTOTOKENS_CHANGE_MAX"));
+ if (change_max < 1 || change_max > 4096) {
+
+ change_max = AUTOTOKENS_CHANGE_MAX;
+
+ }
+
+ }
+
+ if (change_max < change_min) { change_max = change_min + 1; }
+
+ if (getenv("AUTOTOKENS_COMMENT")) {
+
+ char buf[256];
+ snprintf(buf, sizeof(buf), "(%s.*)([\r\n]?)", getenv("AUTOTOKENS_COMMENT"));
+ regex_comment_custom = new regex(buf, regex::optimize);
+
+ }
+
+ data->afl = afl_ptr = afl;
+
+ // set common whitespace tokens
+ // we deliberately do not put uncommon ones here to these will count as
+ // identifier tokens.
+ token_to_id[" "] = current_id;
+ id_to_token[current_id] = " ";
+ ++current_id;
+ token_to_id["\t"] = current_id;
+ id_to_token[current_id] = "\t";
+ ++current_id;
+ token_to_id["\n"] = current_id;
+ id_to_token[current_id] = "\n";
+ ++current_id;
+ token_to_id["\r\n"] = current_id;
+ id_to_token[current_id] = "\r\n";
+ ++current_id;
+ token_to_id[" \n"] = current_id;
+ id_to_token[current_id] = " \n";
+ ++current_id;
+ token_to_id[" "] = current_id;
+ id_to_token[current_id] = " ";
+ ++current_id;
+ token_to_id["\t\t"] = current_id;
+ id_to_token[current_id] = "\t\t";
+ ++current_id;
+ token_to_id["\n\n"] = current_id;
+ id_to_token[current_id] = "\n\n";
+ ++current_id;
+ token_to_id["\r\n\r\n"] = current_id;
+ id_to_token[current_id] = "\r\n\r\n";
+ ++current_id;
+ token_to_id[" "] = current_id;
+ id_to_token[current_id] = " ";
+ ++current_id;
+ token_to_id["\t\t\t\t"] = current_id;
+ id_to_token[current_id] = "\t\t\t\t";
+ ++current_id;
+ token_to_id["\n\n\n\n"] = current_id;
+ id_to_token[current_id] = "\n\n\n\n";
+ ++current_id;
+ whitespace_ids = current_id;
+ token_to_id["\""] = current_id;
+ id_to_token[current_id] = "\"";
+ ++current_id;
+ token_to_id["'"] = current_id;
+ id_to_token[current_id] = "'";
+ ++current_id;
+
+ return data;
+
+}
+
+extern "C" void afl_custom_splice_optout(my_mutator_t *data) {
+
+ (void)(data);
+
+}
+
+extern "C" void afl_custom_deinit(my_mutator_t *data) {
+
+ /* we use this to print statistics at exit :-)
+ needs to be stderr as stdout is filtered */
+
+ if (module_disabled) { return; }
+
+ fprintf(stderr,
+ "\n\nAutotoken mutator statistics:\n"
+ " Number of all seen tokens: %u\n"
+ " Number of input structures: %u\n"
+ " Number of all items in structures: %llu\n"
+ " Number of total fuzzes: %llu\n\n",
+ current_id - 1, valid_structures, all_structure_items, fuzz_count);
+
+ free(data);
+
+}
+
diff --git a/custom_mutators/examples/custom_mutator_helpers.h b/custom_mutators/examples/custom_mutator_helpers.h
deleted file mode 100644
index 62e6efba..00000000
--- a/custom_mutators/examples/custom_mutator_helpers.h
+++ /dev/null
@@ -1,342 +0,0 @@
-#ifndef CUSTOM_MUTATOR_HELPERS
-#define CUSTOM_MUTATOR_HELPERS
-
-#include "config.h"
-#include "types.h"
-#include <stdlib.h>
-
-#define INITIAL_GROWTH_SIZE (64)
-
-#define RAND_BELOW(limit) (rand() % (limit))
-
-/* Use in a struct: creates a name_buf and a name_size variable. */
-#define BUF_VAR(type, name) \
- type * name##_buf; \
- size_t name##_size;
-/* this fills in `&structptr->something_buf, &structptr->something_size`. */
-#define BUF_PARAMS(struct, name) \
- (void **)&struct->name##_buf, &struct->name##_size
-
-typedef struct {
-
-} afl_t;
-
-static void surgical_havoc_mutate(u8 *out_buf, s32 begin, s32 end) {
-
- static s8 interesting_8[] = {INTERESTING_8};
- static s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
- static s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
-
- switch (RAND_BELOW(12)) {
-
- case 0: {
-
- /* Flip a single bit somewhere. Spooky! */
-
- s32 bit_idx = ((RAND_BELOW(end - begin) + begin) << 3) + RAND_BELOW(8);
-
- out_buf[bit_idx >> 3] ^= 128 >> (bit_idx & 7);
-
- break;
-
- }
-
- case 1: {
-
- /* Set byte to interesting value. */
-
- u8 val = interesting_8[RAND_BELOW(sizeof(interesting_8))];
- out_buf[(RAND_BELOW(end - begin) + begin)] = val;
-
- break;
-
- }
-
- case 2: {
-
- /* Set word to interesting value, randomly choosing endian. */
-
- if (end - begin < 2) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 1) break;
-
- switch (RAND_BELOW(2)) {
-
- case 0:
- *(u16 *)(out_buf + byte_idx) =
- interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)];
- break;
- case 1:
- *(u16 *)(out_buf + byte_idx) =
- SWAP16(interesting_16[RAND_BELOW(sizeof(interesting_16) >> 1)]);
- break;
-
- }
-
- break;
-
- }
-
- case 3: {
-
- /* Set dword to interesting value, randomly choosing endian. */
-
- if (end - begin < 4) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 3) break;
-
- switch (RAND_BELOW(2)) {
-
- case 0:
- *(u32 *)(out_buf + byte_idx) =
- interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
- break;
- case 1:
- *(u32 *)(out_buf + byte_idx) =
- SWAP32(interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
- break;
-
- }
-
- break;
-
- }
-
- case 4: {
-
- /* Set qword to interesting value, randomly choosing endian. */
-
- if (end - begin < 8) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 7) break;
-
- switch (RAND_BELOW(2)) {
-
- case 0:
- *(u64 *)(out_buf + byte_idx) =
- (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)];
- break;
- case 1:
- *(u64 *)(out_buf + byte_idx) = SWAP64(
- (s64)interesting_32[RAND_BELOW(sizeof(interesting_32) >> 2)]);
- break;
-
- }
-
- break;
-
- }
-
- case 5: {
-
- /* Randomly subtract from byte. */
-
- out_buf[(RAND_BELOW(end - begin) + begin)] -= 1 + RAND_BELOW(ARITH_MAX);
-
- break;
-
- }
-
- case 6: {
-
- /* Randomly add to byte. */
-
- out_buf[(RAND_BELOW(end - begin) + begin)] += 1 + RAND_BELOW(ARITH_MAX);
-
- break;
-
- }
-
- case 7: {
-
- /* Randomly subtract from word, random endian. */
-
- if (end - begin < 2) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 1) break;
-
- if (RAND_BELOW(2)) {
-
- *(u16 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
-
- } else {
-
- u16 num = 1 + RAND_BELOW(ARITH_MAX);
-
- *(u16 *)(out_buf + byte_idx) =
- SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) - num);
-
- }
-
- break;
-
- }
-
- case 8: {
-
- /* Randomly add to word, random endian. */
-
- if (end - begin < 2) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 1) break;
-
- if (RAND_BELOW(2)) {
-
- *(u16 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
-
- } else {
-
- u16 num = 1 + RAND_BELOW(ARITH_MAX);
-
- *(u16 *)(out_buf + byte_idx) =
- SWAP16(SWAP16(*(u16 *)(out_buf + byte_idx)) + num);
-
- }
-
- break;
-
- }
-
- case 9: {
-
- /* Randomly subtract from dword, random endian. */
-
- if (end - begin < 4) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 3) break;
-
- if (RAND_BELOW(2)) {
-
- *(u32 *)(out_buf + byte_idx) -= 1 + RAND_BELOW(ARITH_MAX);
-
- } else {
-
- u32 num = 1 + RAND_BELOW(ARITH_MAX);
-
- *(u32 *)(out_buf + byte_idx) =
- SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) - num);
-
- }
-
- break;
-
- }
-
- case 10: {
-
- /* Randomly add to dword, random endian. */
-
- if (end - begin < 4) break;
-
- s32 byte_idx = (RAND_BELOW(end - begin) + begin);
-
- if (byte_idx >= end - 3) break;
-
- if (RAND_BELOW(2)) {
-
- *(u32 *)(out_buf + byte_idx) += 1 + RAND_BELOW(ARITH_MAX);
-
- } else {
-
- u32 num = 1 + RAND_BELOW(ARITH_MAX);
-
- *(u32 *)(out_buf + byte_idx) =
- SWAP32(SWAP32(*(u32 *)(out_buf + byte_idx)) + num);
-
- }
-
- break;
-
- }
-
- case 11: {
-
- /* Just set a random byte to a random value. Because,
- why not. We use XOR with 1-255 to eliminate the
- possibility of a no-op. */
-
- out_buf[(RAND_BELOW(end - begin) + begin)] ^= 1 + RAND_BELOW(255);
-
- break;
-
- }
-
- }
-
-}
-
-/* This function calculates the next power of 2 greater or equal its argument.
- @return The rounded up power of 2 (if no overflow) or 0 on overflow.
-*/
-static inline size_t next_pow2(size_t in) {
-
- if (in == 0 || in > (size_t)-1)
- return 0; /* avoid undefined behaviour under-/overflow */
- size_t out = in - 1;
- out |= out >> 1;
- out |= out >> 2;
- out |= out >> 4;
- out |= out >> 8;
- out |= out >> 16;
- return out + 1;
-
-}
-
-/* This function makes sure *size is > size_needed after call.
- It will realloc *buf otherwise.
- *size will grow exponentially as per:
- https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially/
- Will return NULL and free *buf if size_needed is <1 or realloc failed.
- @return For convenience, this function returns *buf.
- */
-static inline void *maybe_grow(void **buf, size_t *size, size_t size_needed) {
-
- /* No need to realloc */
- if (likely(size_needed && *size >= size_needed)) return *buf;
-
- /* No initial size was set */
- if (size_needed < INITIAL_GROWTH_SIZE) size_needed = INITIAL_GROWTH_SIZE;
-
- /* grow exponentially */
- size_t next_size = next_pow2(size_needed);
-
- /* handle overflow */
- if (!next_size) { next_size = size_needed; }
-
- /* alloc */
- *buf = realloc(*buf, next_size);
- *size = *buf ? next_size : 0;
-
- return *buf;
-
-}
-
-/* Swaps buf1 ptr and buf2 ptr, as well as their sizes */
-static inline void afl_swap_bufs(void **buf1, size_t *size1, void **buf2,
- size_t *size2) {
-
- void * scratch_buf = *buf1;
- size_t scratch_size = *size1;
- *buf1 = *buf2;
- *size1 = *size2;
- *buf2 = scratch_buf;
- *size2 = scratch_size;
-
-}
-
-#undef INITIAL_GROWTH_SIZE
-
-#endif
-
diff --git a/custom_mutators/examples/custom_send.c b/custom_mutators/examples/custom_send.c
index ffea927e..9cc4b160 100644
--- a/custom_mutators/examples/custom_send.c
+++ b/custom_mutators/examples/custom_send.c
@@ -1,9 +1,14 @@
+//
+// This is an example on how to use afl_custom_send
+// It writes each mutated data set to /tmp/foo
+// You can modify this to send to IPC, shared memory, etc.
+//
// cc -O3 -fPIC -shared -g -o custom_send.so -I../../include custom_send.c
// cd ../..
// afl-cc -o test-instr test-instr.c
-// afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
-
-#include "custom_mutator_helpers.h"
+// AFL_CUSTOM_MUTATOR_LIBRARY=custom_mutators/examples/custom_send.so \
+// afl-fuzz -i in -o out -- ./test-instr -f /tmp/foo
+//
#include <stdio.h>
#include <stdint.h>
@@ -11,13 +16,15 @@
#include <unistd.h>
#include <fcntl.h>
+#include "afl-fuzz.h"
+
typedef struct my_mutator {
- afl_t *afl;
+ afl_state_t *afl;
} my_mutator_t;
-my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
if (!data) {
diff --git a/custom_mutators/examples/example.c b/custom_mutators/examples/example.c
index 3f299508..42c7469c 100644
--- a/custom_mutators/examples/example.c
+++ b/custom_mutators/examples/example.c
@@ -6,8 +6,8 @@
Dominik Maier <mail@dmnk.co>
*/
-// You need to use -I /path/to/AFLplusplus/include
-#include "custom_mutator_helpers.h"
+// You need to use -I/path/to/AFLplusplus/include -I.
+#include "afl-fuzz.h"
#include <stdint.h>
#include <stdlib.h>
@@ -26,19 +26,14 @@ static const char *commands[] = {
typedef struct my_mutator {
- afl_t *afl;
+ afl_state_t *afl;
// any additional data here!
size_t trim_size_current;
int trimmming_steps;
int cur_step;
- // Reused buffers:
- BUF_VAR(u8, fuzz);
- BUF_VAR(u8, data);
- BUF_VAR(u8, havoc);
- BUF_VAR(u8, trim);
- BUF_VAR(u8, post_process);
+ u8 *mutated_out, *post_process_buf, *trim_buf;
} my_mutator_t;
@@ -53,7 +48,7 @@ typedef struct my_mutator {
* There may be multiple instances of this mutator in one afl-fuzz run!
* Return NULL on error.
*/
-my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
srand(seed); // needed also by surgical_havoc_mutate()
@@ -65,6 +60,27 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
}
+ if ((data->mutated_out = (u8 *)malloc(MAX_FILE)) == NULL) {
+
+ perror("afl_custom_init malloc");
+ return NULL;
+
+ }
+
+ if ((data->post_process_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
+
+ perror("afl_custom_init malloc");
+ return NULL;
+
+ }
+
+ if ((data->trim_buf = (u8 *)malloc(MAX_FILE)) == NULL) {
+
+ perror("afl_custom_init malloc");
+ return NULL;
+
+ }
+
data->afl = afl;
return data;
@@ -96,29 +112,14 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
// the fuzzer
size_t mutated_size = DATA_SIZE <= max_size ? DATA_SIZE : max_size;
- // maybe_grow is optimized to be quick for reused buffers.
- u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), mutated_size);
- if (!mutated_out) {
-
- *out_buf = NULL;
- perror("custom mutator allocation (maybe_grow)");
- return 0; /* afl-fuzz will very likely error out after this. */
-
- }
+ memcpy(data->mutated_out, buf, buf_size);
// Randomly select a command string to add as a header to the packet
- memcpy(mutated_out, commands[rand() % 3], 3);
+ memcpy(data->mutated_out, commands[rand() % 3], 3);
- // Mutate the payload of the packet
- int i;
- for (i = 0; i < 8; ++i) {
+ if (mutated_size > max_size) { mutated_size = max_size; }
- // Randomly perform one of the (no len modification) havoc mutations
- surgical_havoc_mutate(mutated_out, 3, mutated_size);
-
- }
-
- *out_buf = mutated_out;
+ *out_buf = data->mutated_out;
return mutated_size;
}
@@ -142,24 +143,16 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
size_t afl_custom_post_process(my_mutator_t *data, uint8_t *buf,
size_t buf_size, uint8_t **out_buf) {
- uint8_t *post_process_buf =
- maybe_grow(BUF_PARAMS(data, post_process), buf_size + 5);
- if (!post_process_buf) {
+ if (buf_size + 5 > MAX_FILE) { buf_size = MAX_FILE - 5; }
- perror("custom mutator realloc failed.");
- *out_buf = NULL;
- return 0;
-
- }
+ memcpy(data->post_process_buf + 5, buf, buf_size);
+ data->post_process_buf[0] = 'A';
+ data->post_process_buf[1] = 'F';
+ data->post_process_buf[2] = 'L';
+ data->post_process_buf[3] = '+';
+ data->post_process_buf[4] = '+';
- memcpy(post_process_buf + 5, buf, buf_size);
- post_process_buf[0] = 'A';
- post_process_buf[1] = 'F';
- post_process_buf[2] = 'L';
- post_process_buf[3] = '+';
- post_process_buf[4] = '+';
-
- *out_buf = post_process_buf;
+ *out_buf = data->post_process_buf;
return buf_size + 5;
@@ -195,13 +188,6 @@ int32_t afl_custom_init_trim(my_mutator_t *data, uint8_t *buf,
data->cur_step = 0;
- if (!maybe_grow(BUF_PARAMS(data, trim), buf_size)) {
-
- perror("init_trim grow");
- return -1;
-
- }
-
memcpy(data->trim_buf, buf, buf_size);
data->trim_size_current = buf_size;
@@ -282,27 +268,11 @@ int32_t afl_custom_post_trim(my_mutator_t *data, int success) {
size_t afl_custom_havoc_mutation(my_mutator_t *data, u8 *buf, size_t buf_size,
u8 **out_buf, size_t max_size) {
- if (buf_size == 0) {
-
- *out_buf = maybe_grow(BUF_PARAMS(data, havoc), 1);
- if (!*out_buf) {
-
- perror("custom havoc: maybe_grow");
- return 0;
-
- }
+ *out_buf = buf; // in-place mutation
- **out_buf = rand() % 256;
- buf_size = 1;
-
- } else {
-
- // We reuse buf here. It's legal and faster.
- *out_buf = buf;
-
- }
+ if (buf_size <= sizeof(size_t)) { return buf_size; }
- size_t victim = rand() % buf_size;
+ size_t victim = rand() % (buf_size - sizeof(size_t));
(*out_buf)[victim] += rand() % 10;
return buf_size;
@@ -369,9 +339,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t *data,
void afl_custom_deinit(my_mutator_t *data) {
free(data->post_process_buf);
- free(data->havoc_buf);
- free(data->data_buf);
- free(data->fuzz_buf);
+ free(data->mutated_out);
free(data->trim_buf);
free(data);
diff --git a/custom_mutators/examples/post_library_gif.so.c b/custom_mutators/examples/post_library_gif.so.c
index 9cd224f4..6737c627 100644
--- a/custom_mutators/examples/post_library_gif.so.c
+++ b/custom_mutators/examples/post_library_gif.so.c
@@ -45,9 +45,8 @@
1) If you don't want to modify the test case, simply set `*out_buf = in_buf`
and return the original `len`.
- NOTE: the following is currently NOT true, we abort in this case!
2) If you want to skip this test case altogether and have AFL generate a
- new one, return 0 or set `*out_buf = NULL`.
+ new one, return 0.
Use this sparingly - it's faster than running the target program
with patently useless inputs, but still wastes CPU time.
@@ -59,8 +58,6 @@
Note that the buffer will *not* be freed for you. To avoid memory leaks,
you need to free it or reuse it on subsequent calls (as shown below).
- *** Feel free to reuse the original 'in_buf' BUFFER and return it. ***
-
Alright. The example below shows a simple postprocessor that tries to make
sure that all input files start with "GIF89a".
@@ -72,7 +69,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "alloc-inl.h"
+#include "afl-fuzz.h"
/* Header that must be present at the beginning of every test case: */
@@ -80,8 +77,7 @@
typedef struct post_state {
- unsigned char *buf;
- size_t size;
+ size_t size;
} post_state_t;
@@ -95,15 +91,6 @@ void *afl_custom_init(void *afl) {
}
- state->buf = calloc(sizeof(unsigned char), 4096);
- if (!state->buf) {
-
- free(state);
- perror("calloc");
- return NULL;
-
- }
-
return state;
}
@@ -113,6 +100,10 @@ void *afl_custom_init(void *afl) {
size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
unsigned int len, unsigned char **out_buf) {
+ /* we do in-place modification as we do not increase the size */
+
+ *out_buf = in_buf;
+
/* Skip execution altogether for buffers shorter than 6 bytes (just to
show how it's done). We can trust len to be sane. */
@@ -120,34 +111,7 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
/* Do nothing for buffers that already start with the expected header. */
- if (!memcmp(in_buf, HEADER, strlen(HEADER))) {
-
- *out_buf = in_buf;
- return len;
-
- }
-
- /* Allocate memory for new buffer, reusing previous allocation if
- possible. Note we have to use afl-fuzz's own realloc!
- Note that you should only do this if you need to grow the buffer,
- otherwise work with in_buf, and assign it to *out_buf instead. */
-
- *out_buf = afl_realloc(out_buf, len);
-
- /* If we're out of memory, the most graceful thing to do is to return the
- original buffer and give up on modifying it. Let AFL handle OOM on its
- own later on. */
-
- if (!*out_buf) {
-
- *out_buf = in_buf;
- return len;
-
- }
-
- if (len > strlen(HEADER))
- memcpy(*out_buf + strlen(HEADER), in_buf + strlen(HEADER),
- len - strlen(HEADER));
+ if (!memcmp(in_buf, HEADER, strlen(HEADER))) { return len; }
/* Insert the new header. */
@@ -162,7 +126,6 @@ size_t afl_custom_post_process(post_state_t *data, unsigned char *in_buf,
/* Gets called afterwards */
void afl_custom_deinit(post_state_t *data) {
- free(data->buf);
free(data);
}
diff --git a/custom_mutators/examples/post_library_png.so.c b/custom_mutators/examples/post_library_png.so.c
index cd65b1bc..652da497 100644
--- a/custom_mutators/examples/post_library_png.so.c
+++ b/custom_mutators/examples/post_library_png.so.c
@@ -30,7 +30,7 @@
#include <string.h>
#include <zlib.h>
#include <arpa/inet.h>
-#include "alloc-inl.h"
+#include "afl-fuzz.h"
/* A macro to round an integer up to 4 kB. */
@@ -53,7 +53,7 @@ void *afl_custom_init(void *afl) {
}
- state->buf = calloc(sizeof(unsigned char), 4096);
+ state->buf = calloc(sizeof(unsigned char), MAX_FILE);
if (!state->buf) {
free(state);
@@ -80,21 +80,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
}
- /* This is not a good way to do it, if you do not need to grow the buffer
- then just work with in_buf instead for speed reasons.
- But we want to show how to grow a buffer, so this is how it's done: */
-
- unsigned int pos = 8;
- unsigned char *new_buf = afl_realloc(out_buf, UP4K(len));
-
- if (!new_buf) {
-
- *out_buf = in_buf;
- return len;
-
- }
-
- memcpy(new_buf, in_buf, len);
+ unsigned int pos = 8;
/* Minimum size of a zero-length PNG chunk is 12 bytes; if we
don't have that, we can bail out. */
@@ -124,7 +110,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
if (real_cksum != file_cksum) {
- *(uint32_t *)(new_buf + pos + 8 + chunk_len) = real_cksum;
+ *(uint32_t *)(data->buf + pos + 8 + chunk_len) = real_cksum;
}
@@ -134,7 +120,7 @@ size_t afl_custom_post_process(post_state_t *data, const unsigned char *in_buf,
}
- *out_buf = new_buf;
+ *out_buf = data->buf;
return len;
}
diff --git a/custom_mutators/examples/simple_example.c b/custom_mutators/examples/simple_example.c
index d888ec1f..2c0abe29 100644
--- a/custom_mutators/examples/simple_example.c
+++ b/custom_mutators/examples/simple_example.c
@@ -1,6 +1,6 @@
// This simple example just creates random buffer <= 100 filled with 'A'
// needs -I /path/to/AFLplusplus/include
-#include "custom_mutator_helpers.h"
+#include "afl-fuzz.h"
#include <stdint.h>
#include <stdlib.h>
@@ -13,14 +13,14 @@
typedef struct my_mutator {
- afl_t *afl;
+ afl_state_t *afl;
// Reused buffers:
- BUF_VAR(u8, fuzz);
+ u8 *fuzz_buf;
} my_mutator_t;
-my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
srand(seed);
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
@@ -31,6 +31,14 @@ my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
}
+ data->fuzz_buf = (u8 *)malloc(MAX_FILE);
+ if (!data->fuzz_buf) {
+
+ perror("afl_custom_init malloc");
+ return NULL;
+
+ }
+
data->afl = afl;
return data;
@@ -44,18 +52,10 @@ size_t afl_custom_fuzz(my_mutator_t *data, uint8_t *buf, size_t buf_size,
int size = (rand() % 100) + 1;
if (size > max_size) size = max_size;
- u8 *mutated_out = maybe_grow(BUF_PARAMS(data, fuzz), size);
- if (!mutated_out) {
-
- *out_buf = NULL;
- perror("custom mutator allocation (maybe_grow)");
- return 0; /* afl-fuzz will very likely error out after this. */
-
- }
- memset(mutated_out, _FIXED_CHAR, size);
+ memset(data->fuzz_buf, _FIXED_CHAR, size);
- *out_buf = mutated_out;
+ *out_buf = data->fuzz_buf;
return size;
}
diff --git a/custom_mutators/gramatron/build_gramatron_mutator.sh b/custom_mutators/gramatron/build_gramatron_mutator.sh
index ff88ff26..c830329e 100755
--- a/custom_mutators/gramatron/build_gramatron_mutator.sh
+++ b/custom_mutators/gramatron/build_gramatron_mutator.sh
@@ -11,7 +11,7 @@
# Adapted for AFLplusplus by Dominik Maier <mail@dmnk.co>
#
# Copyright 2017 Battelle Memorial Institute. All rights reserved.
-# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/custom_mutators/grammar_mutator/build_grammar_mutator.sh b/custom_mutators/grammar_mutator/build_grammar_mutator.sh
index 74cae8aa..593cd2dc 100755
--- a/custom_mutators/grammar_mutator/build_grammar_mutator.sh
+++ b/custom_mutators/grammar_mutator/build_grammar_mutator.sh
@@ -14,7 +14,7 @@
# <andreafioraldi@gmail.com>
#
# Copyright 2017 Battelle Memorial Institute. All rights reserved.
-# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
+# Copyright 2019-2023 AFLplusplus Project. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/custom_mutators/honggfuzz/custom_mutator_helpers.h b/custom_mutators/honggfuzz/custom_mutator_helpers.h
deleted file mode 100644
index 57754697..00000000
--- a/custom_mutators/honggfuzz/custom_mutator_helpers.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef CUSTOM_MUTATOR_HELPERS
-#define CUSTOM_MUTATOR_HELPERS
-
-#include "config.h"
-#include "types.h"
-#include "afl-fuzz.h"
-#include <stdlib.h>
-
-#define INITIAL_GROWTH_SIZE (64)
-
-/* Use in a struct: creates a name_buf and a name_size variable. */
-#define BUF_VAR(type, name) \
- type * name##_buf; \
- size_t name##_size;
-/* this filles in `&structptr->something_buf, &structptr->something_size`. */
-#define BUF_PARAMS(struct, name) \
- (void **)&struct->name##_buf, &struct->name##_size
-
-#undef INITIAL_GROWTH_SIZE
-
-#endif
-
diff --git a/custom_mutators/honggfuzz/honggfuzz.c b/custom_mutators/honggfuzz/honggfuzz.c
index d7b3c9c5..0dd59aee 100644
--- a/custom_mutators/honggfuzz/honggfuzz.c
+++ b/custom_mutators/honggfuzz/honggfuzz.c
@@ -3,14 +3,14 @@
#include <stdlib.h>
#include <string.h>
-#include "custom_mutator_helpers.h"
+#include "afl-fuzz.h"
#include "mangle.h"
#define NUMBER_OF_MUTATIONS 5
-uint8_t * queue_input;
+uint8_t *queue_input;
size_t queue_input_size;
-afl_state_t * afl_struct;
+afl_state_t *afl_struct;
run_t run;
honggfuzz_t global;
struct _dynfile_t dynfile;
@@ -18,8 +18,8 @@ struct _dynfile_t dynfile;
typedef struct my_mutator {
afl_state_t *afl;
- run_t * run;
- u8 * mutator_buf;
+ run_t *run;
+ u8 *mutator_buf;
unsigned int seed;
unsigned int extras_cnt, a_extras_cnt;
@@ -65,9 +65,9 @@ my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
/* When a new queue entry is added we check if there are new dictionary
entries to add to honggfuzz structure */
-uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
- const uint8_t *filename_new_queue,
- const uint8_t *filename_orig_queue) {
+void afl_custom_queue_new_entry(my_mutator_t *data,
+ const uint8_t *filename_new_queue,
+ const uint8_t *filename_orig_queue) {
if (run.global->mutate.dictionaryCnt >= 1024) return;
@@ -97,7 +97,7 @@ uint8_t afl_custom_queue_new_entry(my_mutator_t * data,
}
- return 0;
+ return;
}
diff --git a/custom_mutators/honggfuzz/mangle.c b/custom_mutators/honggfuzz/mangle.c
index 637d428d..7b7ccb91 100644
--- a/custom_mutators/honggfuzz/mangle.c
+++ b/custom_mutators/honggfuzz/mangle.c
@@ -39,11 +39,16 @@
#include "libhfcommon/log.h"
#include "libhfcommon/util.h"
-static inline size_t mangle_LenLeft(run_t* run, size_t off) {
- if (off >= run->dynfile->size) {
- LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size);
- }
- return (run->dynfile->size - off - 1);
+static inline size_t mangle_LenLeft(run_t *run, size_t off) {
+
+ if (off >= run->dynfile->size) {
+
+ LOG_F("Offset is too large: off:%zu >= len:%zu", off, run->dynfile->size);
+
+ }
+
+ return (run->dynfile->size - off - 1);
+
}
/*
@@ -51,196 +56,233 @@ static inline size_t mangle_LenLeft(run_t* run, size_t off) {
* Based on an idea by https://twitter.com/gamozolabs
*/
static inline size_t mangle_getLen(size_t max) {
- if (max > _HF_INPUT_MAX_SIZE) {
- LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max, (size_t)_HF_INPUT_MAX_SIZE);
- }
- if (max == 0) {
- LOG_F("max == 0");
- }
- if (max == 1) {
- return 1;
- }
- /* Give 50% chance the the uniform distribution */
- if (util_rnd64() & 1) {
- return (size_t)util_rndGet(1, max);
- }
+ if (max > _HF_INPUT_MAX_SIZE) {
+
+ LOG_F("max (%zu) > _HF_INPUT_MAX_SIZE (%zu)", max,
+ (size_t)_HF_INPUT_MAX_SIZE);
+
+ }
+
+ if (max == 0) { LOG_F("max == 0"); }
+ if (max == 1) { return 1; }
+
+ /* Give 50% chance the the uniform distribution */
+ if (util_rnd64() & 1) { return (size_t)util_rndGet(1, max); }
+
+ /* effectively exprand() */
+ return (size_t)util_rndGet(1, util_rndGet(1, max));
- /* effectively exprand() */
- return (size_t)util_rndGet(1, util_rndGet(1, max));
}
/* Prefer smaller values here, so use mangle_getLen() */
-static inline size_t mangle_getOffSet(run_t* run) {
- return mangle_getLen(run->dynfile->size) - 1;
+static inline size_t mangle_getOffSet(run_t *run) {
+
+ return mangle_getLen(run->dynfile->size) - 1;
+
}
/* Offset which can be equal to the file size */
-static inline size_t mangle_getOffSetPlus1(run_t* run) {
- size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE);
- return mangle_getLen(reqlen) - 1;
+static inline size_t mangle_getOffSetPlus1(run_t *run) {
+
+ size_t reqlen = HF_MIN(run->dynfile->size + 1, _HF_INPUT_MAX_SIZE);
+ return mangle_getLen(reqlen) - 1;
+
}
-static inline void mangle_Move(run_t* run, size_t off_from, size_t off_to, size_t len) {
- if (off_from >= run->dynfile->size) {
- return;
- }
- if (off_to >= run->dynfile->size) {
- return;
- }
- if (off_from == off_to) {
- return;
- }
+static inline void mangle_Move(run_t *run, size_t off_from, size_t off_to,
+ size_t len) {
+
+ if (off_from >= run->dynfile->size) { return; }
+ if (off_to >= run->dynfile->size) { return; }
+ if (off_from == off_to) { return; }
- size_t len_from = run->dynfile->size - off_from;
- len = HF_MIN(len, len_from);
+ size_t len_from = run->dynfile->size - off_from;
+ len = HF_MIN(len, len_from);
- size_t len_to = run->dynfile->size - off_to;
- len = HF_MIN(len, len_to);
+ size_t len_to = run->dynfile->size - off_to;
+ len = HF_MIN(len, len_to);
+
+ memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len);
- memmove(&run->dynfile->data[off_to], &run->dynfile->data[off_from], len);
}
-static inline void mangle_Overwrite(
- run_t* run, size_t off, const uint8_t* src, size_t len, bool printable) {
- if (len == 0) {
- return;
- }
- size_t maxToCopy = run->dynfile->size - off;
- if (len > maxToCopy) {
- len = maxToCopy;
- }
+static inline void mangle_Overwrite(run_t *run, size_t off, const uint8_t *src,
+ size_t len, bool printable) {
+
+ if (len == 0) { return; }
+ size_t maxToCopy = run->dynfile->size - off;
+ if (len > maxToCopy) { len = maxToCopy; }
+
+ memmove(&run->dynfile->data[off], src, len);
+ if (printable) { util_turnToPrintable(&run->dynfile->data[off], len); }
- memmove(&run->dynfile->data[off], src, len);
- if (printable) {
- util_turnToPrintable(&run->dynfile->data[off], len);
- }
}
-static inline size_t mangle_Inflate(run_t* run, size_t off, size_t len, bool printable) {
- if (run->dynfile->size >= run->global->mutate.maxInputSz) {
- return 0;
- }
- if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) {
- len = run->global->mutate.maxInputSz - run->dynfile->size;
- }
+static inline size_t mangle_Inflate(run_t *run, size_t off, size_t len,
+ bool printable) {
- input_setSize(run, run->dynfile->size + len);
- mangle_Move(run, off, off + len, run->dynfile->size);
- if (printable) {
- memset(&run->dynfile->data[off], ' ', len);
- }
+ if (run->dynfile->size >= run->global->mutate.maxInputSz) { return 0; }
+ if (len > (run->global->mutate.maxInputSz - run->dynfile->size)) {
+
+ len = run->global->mutate.maxInputSz - run->dynfile->size;
+
+ }
+
+ input_setSize(run, run->dynfile->size + len);
+ mangle_Move(run, off, off + len, run->dynfile->size);
+ if (printable) { memset(&run->dynfile->data[off], ' ', len); }
+
+ return len;
- return len;
}
-static inline void mangle_Insert(
- run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
- len = mangle_Inflate(run, off, len, printable);
- mangle_Overwrite(run, off, val, len, printable);
+static inline void mangle_Insert(run_t *run, size_t off, const uint8_t *val,
+ size_t len, bool printable) {
+
+ len = mangle_Inflate(run, off, len, printable);
+ mangle_Overwrite(run, off, val, len, printable);
+
}
-static inline void mangle_UseValue(run_t* run, const uint8_t* val, size_t len, bool printable) {
- if (util_rnd64() & 1) {
- mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable);
- } else {
- mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable);
- }
+static inline void mangle_UseValue(run_t *run, const uint8_t *val, size_t len,
+ bool printable) {
+
+ if (util_rnd64() & 1) {
+
+ mangle_Overwrite(run, mangle_getOffSet(run), val, len, printable);
+
+ } else {
+
+ mangle_Insert(run, mangle_getOffSetPlus1(run), val, len, printable);
+
+ }
+
}
-static inline void mangle_UseValueAt(
- run_t* run, size_t off, const uint8_t* val, size_t len, bool printable) {
- if (util_rnd64() & 1) {
- mangle_Overwrite(run, off, val, len, printable);
- } else {
- mangle_Insert(run, off, val, len, printable);
- }
+static inline void mangle_UseValueAt(run_t *run, size_t off, const uint8_t *val,
+ size_t len, bool printable) {
+
+ if (util_rnd64() & 1) {
+
+ mangle_Overwrite(run, off, val, len, printable);
+
+ } else {
+
+ mangle_Insert(run, off, val, len, printable);
+
+ }
+
}
-static void mangle_MemSwap(run_t* run, bool printable HF_ATTR_UNUSED) {
- /* No big deal if those two are overlapping */
- size_t off1 = mangle_getOffSet(run);
- size_t maxlen1 = run->dynfile->size - off1;
- size_t off2 = mangle_getOffSet(run);
- size_t maxlen2 = run->dynfile->size - off2;
- size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2));
+static void mangle_MemSwap(run_t *run, bool printable HF_ATTR_UNUSED) {
- if (off1 == off2) {
- return;
- }
+ /* No big deal if those two are overlapping */
+ size_t off1 = mangle_getOffSet(run);
+ size_t maxlen1 = run->dynfile->size - off1;
+ size_t off2 = mangle_getOffSet(run);
+ size_t maxlen2 = run->dynfile->size - off2;
+ size_t len = mangle_getLen(HF_MIN(maxlen1, maxlen2));
+
+ if (off1 == off2) { return; }
+
+ for (size_t i = 0; i < (len / 2); i++) {
+
+ /*
+ * First - from the head, next from the tail. Don't worry about layout of
+ * the overlapping part - there's no good solution to that, and it can be
+ * left somewhat scrambled, while still preserving the entropy
+ */
+ const uint8_t tmp1 = run->dynfile->data[off2 + i];
+ run->dynfile->data[off2 + i] = run->dynfile->data[off1 + i];
+ run->dynfile->data[off1 + i] = tmp1;
+ const uint8_t tmp2 = run->dynfile->data[off2 + (len - 1) - i];
+ run->dynfile->data[off2 + (len - 1) - i] =
+ run->dynfile->data[off1 + (len - 1) - i];
+ run->dynfile->data[off1 + (len - 1) - i] = tmp2;
+
+ }
- for (size_t i = 0; i < (len / 2); i++) {
- /*
- * First - from the head, next from the tail. Don't worry about layout of the overlapping
- * part - there's no good solution to that, and it can be left somewhat scrambled,
- * while still preserving the entropy
- */
- const uint8_t tmp1 = run->dynfile->data[off2 + i];
- run->dynfile->data[off2 + i] = run->dynfile->data[off1 + i];
- run->dynfile->data[off1 + i] = tmp1;
- const uint8_t tmp2 = run->dynfile->data[off2 + (len - 1) - i];
- run->dynfile->data[off2 + (len - 1) - i] = run->dynfile->data[off1 + (len - 1) - i];
- run->dynfile->data[off1 + (len - 1) - i] = tmp2;
- }
}
-static void mangle_MemCopy(run_t* run, bool printable HF_ATTR_UNUSED) {
- size_t off = mangle_getOffSet(run);
- size_t len = mangle_getLen(run->dynfile->size - off);
+static void mangle_MemCopy(run_t *run, bool printable HF_ATTR_UNUSED) {
+
+ size_t off = mangle_getOffSet(run);
+ size_t len = mangle_getLen(run->dynfile->size - off);
- /* Use a temp buf, as Insert/Inflate can change source bytes */
- uint8_t* tmpbuf = (uint8_t*)util_Malloc(len);
- defer {
- free(tmpbuf);
- };
- memmove(tmpbuf, &run->dynfile->data[off], len);
+ /* Use a temp buf, as Insert/Inflate can change source bytes */
+ uint8_t *tmpbuf = (uint8_t *)util_Malloc(len);
+ defer {
+
+ free(tmpbuf);
+
+ };
+
+ memmove(tmpbuf, &run->dynfile->data[off], len);
+
+ mangle_UseValue(run, tmpbuf, len, printable);
- mangle_UseValue(run, tmpbuf, len, printable);
}
-static void mangle_Bytes(run_t* run, bool printable) {
- uint16_t buf;
- if (printable) {
- util_rndBufPrintable((uint8_t*)&buf, sizeof(buf));
- } else {
- buf = util_rnd64();
- }
+static void mangle_Bytes(run_t *run, bool printable) {
+
+ uint16_t buf;
+ if (printable) {
+
+ util_rndBufPrintable((uint8_t *)&buf, sizeof(buf));
+
+ } else {
+
+ buf = util_rnd64();
+
+ }
+
+ /* Overwrite with random 1-2-byte values */
+ size_t toCopy = util_rndGet(1, 2);
+ mangle_UseValue(run, (const uint8_t *)&buf, toCopy, printable);
- /* Overwrite with random 1-2-byte values */
- size_t toCopy = util_rndGet(1, 2);
- mangle_UseValue(run, (const uint8_t*)&buf, toCopy, printable);
}
-static void mangle_ByteRepeat(run_t* run, bool printable) {
- size_t off = mangle_getOffSet(run);
- size_t destOff = off + 1;
- size_t maxSz = run->dynfile->size - destOff;
+static void mangle_ByteRepeat(run_t *run, bool printable) {
- /* No space to repeat */
- if (!maxSz) {
- mangle_Bytes(run, printable);
- return;
- }
+ size_t off = mangle_getOffSet(run);
+ size_t destOff = off + 1;
+ size_t maxSz = run->dynfile->size - destOff;
+
+ /* No space to repeat */
+ if (!maxSz) {
+
+ mangle_Bytes(run, printable);
+ return;
+
+ }
+
+ size_t len = mangle_getLen(maxSz);
+ if (util_rnd64() & 0x1) {
+
+ len = mangle_Inflate(run, destOff, len, printable);
+
+ }
+
+ memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
- size_t len = mangle_getLen(maxSz);
- if (util_rnd64() & 0x1) {
- len = mangle_Inflate(run, destOff, len, printable);
- }
- memset(&run->dynfile->data[destOff], run->dynfile->data[off], len);
}
-static void mangle_Bit(run_t* run, bool printable) {
- size_t off = mangle_getOffSet(run);
- run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7));
- if (printable) {
- util_turnToPrintable(&(run->dynfile->data[off]), 1);
- }
+static void mangle_Bit(run_t *run, bool printable) {
+
+ size_t off = mangle_getOffSet(run);
+ run->dynfile->data[off] ^= (uint8_t)(1U << util_rndGet(0, 7));
+ if (printable) { util_turnToPrintable(&(run->dynfile->data[off]), 1); }
+
}
static const struct {
- const uint8_t val[8];
- const size_t size;
+
+ const uint8_t val[8];
+ const size_t size;
+
} mangleMagicVals[] = {
+
/* 1B - No endianness */
{"\x00\x00\x00\x00\x00\x00\x00\x00", 1},
{"\x01\x00\x00\x00\x00\x00\x00\x00", 1},
@@ -472,436 +514,543 @@ static const struct {
{"\x00\x00\x00\x00\x00\x00\x00\x80", 8},
{"\x01\x00\x00\x00\x00\x00\x00\x80", 8},
{"\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8},
+
};
-static void mangle_Magic(run_t* run, bool printable) {
- uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1);
- mangle_UseValue(run, mangleMagicVals[choice].val, mangleMagicVals[choice].size, printable);
+static void mangle_Magic(run_t *run, bool printable) {
+
+ uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleMagicVals) - 1);
+ mangle_UseValue(run, mangleMagicVals[choice].val,
+ mangleMagicVals[choice].size, printable);
+
}
-static void mangle_StaticDict(run_t* run, bool printable) {
- if (run->global->mutate.dictionaryCnt == 0) {
- mangle_Bytes(run, printable);
- return;
- }
- uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1);
- mangle_UseValue(run, run->global->mutate.dictionary[choice].val,
- run->global->mutate.dictionary[choice].len, printable);
+static void mangle_StaticDict(run_t *run, bool printable) {
+
+ if (run->global->mutate.dictionaryCnt == 0) {
+
+ mangle_Bytes(run, printable);
+ return;
+
+ }
+
+ uint64_t choice = util_rndGet(0, run->global->mutate.dictionaryCnt - 1);
+ mangle_UseValue(run, run->global->mutate.dictionary[choice].val,
+ run->global->mutate.dictionary[choice].len, printable);
+
}
-static inline const uint8_t* mangle_FeedbackDict(run_t* run, size_t* len) {
- if (!run->global->feedback.cmpFeedback) {
- return NULL;
- }
- cmpfeedback_t* cmpf = run->global->feedback.cmpFeedbackMap;
- uint32_t cnt = ATOMIC_GET(cmpf->cnt);
- if (cnt == 0) {
- return NULL;
- }
- if (cnt > ARRAYSIZE(cmpf->valArr)) {
- cnt = ARRAYSIZE(cmpf->valArr);
- }
- uint32_t choice = util_rndGet(0, cnt - 1);
- *len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
- if (*len == 0) {
- return NULL;
- }
- return cmpf->valArr[choice].val;
+static inline const uint8_t *mangle_FeedbackDict(run_t *run, size_t *len) {
+
+ if (!run->global->feedback.cmpFeedback) { return NULL; }
+ cmpfeedback_t *cmpf = run->global->feedback.cmpFeedbackMap;
+ uint32_t cnt = ATOMIC_GET(cmpf->cnt);
+ if (cnt == 0) { return NULL; }
+ if (cnt > ARRAYSIZE(cmpf->valArr)) { cnt = ARRAYSIZE(cmpf->valArr); }
+ uint32_t choice = util_rndGet(0, cnt - 1);
+ *len = (size_t)ATOMIC_GET(cmpf->valArr[choice].len);
+ if (*len == 0) { return NULL; }
+ return cmpf->valArr[choice].val;
+
}
-static void mangle_ConstFeedbackDict(run_t* run, bool printable) {
- size_t len;
- const uint8_t* val = mangle_FeedbackDict(run, &len);
- if (val == NULL) {
- mangle_Bytes(run, printable);
- return;
- }
- mangle_UseValue(run, val, len, printable);
+static void mangle_ConstFeedbackDict(run_t *run, bool printable) {
+
+ size_t len;
+ const uint8_t *val = mangle_FeedbackDict(run, &len);
+ if (val == NULL) {
+
+ mangle_Bytes(run, printable);
+ return;
+
+ }
+
+ mangle_UseValue(run, val, len, printable);
+
}
-static void mangle_MemSet(run_t* run, bool printable) {
- size_t off = mangle_getOffSet(run);
- size_t len = mangle_getLen(run->dynfile->size - off);
- int val = printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX);
+static void mangle_MemSet(run_t *run, bool printable) {
- if (util_rnd64() & 1) {
- len = mangle_Inflate(run, off, len, printable);
- }
+ size_t off = mangle_getOffSet(run);
+ size_t len = mangle_getLen(run->dynfile->size - off);
+ int val =
+ printable ? (int)util_rndPrintable() : (int)util_rndGet(0, UINT8_MAX);
+
+ if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); }
+
+ memset(&run->dynfile->data[off], val, len);
- memset(&run->dynfile->data[off], val, len);
}
-static void mangle_MemClr(run_t* run, bool printable) {
- size_t off = mangle_getOffSet(run);
- size_t len = mangle_getLen(run->dynfile->size - off);
- int val = printable ? ' ' : 0;
+static void mangle_MemClr(run_t *run, bool printable) {
- if (util_rnd64() & 1) {
- len = mangle_Inflate(run, off, len, printable);
- }
+ size_t off = mangle_getOffSet(run);
+ size_t len = mangle_getLen(run->dynfile->size - off);
+ int val = printable ? ' ' : 0;
+
+ if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); }
+
+ memset(&run->dynfile->data[off], val, len);
- memset(&run->dynfile->data[off], val, len);
}
-static void mangle_RandomBuf(run_t* run, bool printable) {
- size_t off = mangle_getOffSet(run);
- size_t len = mangle_getLen(run->dynfile->size - off);
+static void mangle_RandomBuf(run_t *run, bool printable) {
+
+ size_t off = mangle_getOffSet(run);
+ size_t len = mangle_getLen(run->dynfile->size - off);
+
+ if (util_rnd64() & 1) { len = mangle_Inflate(run, off, len, printable); }
+
+ if (printable) {
+
+ util_rndBufPrintable(&run->dynfile->data[off], len);
+
+ } else {
+
+ util_rndBuf(&run->dynfile->data[off], len);
+
+ }
+
+}
+
+static inline void mangle_AddSubWithRange(run_t *run, size_t off, size_t varLen,
+ uint64_t range, bool printable) {
+
+ int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range;
+
+ switch (varLen) {
+
+ case 1: {
+
+ run->dynfile->data[off] += delta;
+ break;
- if (util_rnd64() & 1) {
- len = mangle_Inflate(run, off, len, printable);
}
- if (printable) {
- util_rndBufPrintable(&run->dynfile->data[off], len);
- } else {
- util_rndBuf(&run->dynfile->data[off], len);
+ case 2: {
+
+ int16_t val;
+ memcpy(&val, &run->dynfile->data[off], sizeof(val));
+ if (util_rnd64() & 0x1) {
+
+ val += delta;
+
+ } else {
+
+ /* Foreign endianess */
+ val = __builtin_bswap16(val);
+ val += delta;
+ val = __builtin_bswap16(val);
+
+ }
+
+ mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
+ break;
+
}
-}
-static inline void mangle_AddSubWithRange(
- run_t* run, size_t off, size_t varLen, uint64_t range, bool printable) {
- int64_t delta = (int64_t)util_rndGet(0, range * 2) - (int64_t)range;
-
- switch (varLen) {
- case 1: {
- run->dynfile->data[off] += delta;
- break;
- }
- case 2: {
- int16_t val;
- memcpy(&val, &run->dynfile->data[off], sizeof(val));
- if (util_rnd64() & 0x1) {
- val += delta;
- } else {
- /* Foreign endianess */
- val = __builtin_bswap16(val);
- val += delta;
- val = __builtin_bswap16(val);
- }
- mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
- break;
- }
- case 4: {
- int32_t val;
- memcpy(&val, &run->dynfile->data[off], sizeof(val));
- if (util_rnd64() & 0x1) {
- val += delta;
- } else {
- /* Foreign endianess */
- val = __builtin_bswap32(val);
- val += delta;
- val = __builtin_bswap32(val);
- }
- mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
- break;
- }
- case 8: {
- int64_t val;
- memcpy(&val, &run->dynfile->data[off], sizeof(val));
- if (util_rnd64() & 0x1) {
- val += delta;
- } else {
- /* Foreign endianess */
- val = __builtin_bswap64(val);
- val += delta;
- val = __builtin_bswap64(val);
- }
- mangle_Overwrite(run, off, (uint8_t*)&val, varLen, printable);
- break;
- }
- default: {
- LOG_F("Unknown variable length size: %zu", varLen);
- }
+ case 4: {
+
+ int32_t val;
+ memcpy(&val, &run->dynfile->data[off], sizeof(val));
+ if (util_rnd64() & 0x1) {
+
+ val += delta;
+
+ } else {
+
+ /* Foreign endianess */
+ val = __builtin_bswap32(val);
+ val += delta;
+ val = __builtin_bswap32(val);
+
+ }
+
+ mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
+ break;
+
}
-}
-static void mangle_AddSub(run_t* run, bool printable) {
- size_t off = mangle_getOffSet(run);
+ case 8: {
+
+ int64_t val;
+ memcpy(&val, &run->dynfile->data[off], sizeof(val));
+ if (util_rnd64() & 0x1) {
+
+ val += delta;
+
+ } else {
+
+ /* Foreign endianess */
+ val = __builtin_bswap64(val);
+ val += delta;
+ val = __builtin_bswap64(val);
+
+ }
+
+ mangle_Overwrite(run, off, (uint8_t *)&val, varLen, printable);
+ break;
- /* 1,2,4,8 */
- size_t varLen = 1U << util_rndGet(0, 3);
- if ((run->dynfile->size - off) < varLen) {
- varLen = 1;
}
- uint64_t range;
- switch (varLen) {
- case 1:
- range = 16;
- break;
- case 2:
- range = 4096;
- break;
- case 4:
- range = 1048576;
- break;
- case 8:
- range = 268435456;
- break;
- default:
- LOG_F("Invalid operand size: %zu", varLen);
+ default: {
+
+ LOG_F("Unknown variable length size: %zu", varLen);
+
}
- mangle_AddSubWithRange(run, off, varLen, range, printable);
+ }
+
}
-static void mangle_IncByte(run_t* run, bool printable) {
- size_t off = mangle_getOffSet(run);
- if (printable) {
- run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32;
- } else {
- run->dynfile->data[off] += (uint8_t)1UL;
- }
+static void mangle_AddSub(run_t *run, bool printable) {
+
+ size_t off = mangle_getOffSet(run);
+
+ /* 1,2,4,8 */
+ size_t varLen = 1U << util_rndGet(0, 3);
+ if ((run->dynfile->size - off) < varLen) { varLen = 1; }
+
+ uint64_t range;
+ switch (varLen) {
+
+ case 1:
+ range = 16;
+ break;
+ case 2:
+ range = 4096;
+ break;
+ case 4:
+ range = 1048576;
+ break;
+ case 8:
+ range = 268435456;
+ break;
+ default:
+ LOG_F("Invalid operand size: %zu", varLen);
+
+ }
+
+ mangle_AddSubWithRange(run, off, varLen, range, printable);
+
}
-static void mangle_DecByte(run_t* run, bool printable) {
- size_t off = mangle_getOffSet(run);
- if (printable) {
- run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32;
- } else {
- run->dynfile->data[off] -= (uint8_t)1UL;
- }
+static void mangle_IncByte(run_t *run, bool printable) {
+
+ size_t off = mangle_getOffSet(run);
+ if (printable) {
+
+ run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 1) % 95 + 32;
+
+ } else {
+
+ run->dynfile->data[off] += (uint8_t)1UL;
+
+ }
+
}
-static void mangle_NegByte(run_t* run, bool printable) {
- size_t off = mangle_getOffSet(run);
- if (printable) {
- run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32;
- } else {
- run->dynfile->data[off] = ~(run->dynfile->data[off]);
- }
+static void mangle_DecByte(run_t *run, bool printable) {
+
+ size_t off = mangle_getOffSet(run);
+ if (printable) {
+
+ run->dynfile->data[off] = (run->dynfile->data[off] - 32 + 94) % 95 + 32;
+
+ } else {
+
+ run->dynfile->data[off] -= (uint8_t)1UL;
+
+ }
+
}
-static void mangle_Expand(run_t* run, bool printable) {
- size_t off = mangle_getOffSet(run);
- size_t len;
- if (util_rnd64() % 16) {
- len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off));
- } else {
- len = mangle_getLen(run->global->mutate.maxInputSz - off);
- }
+static void mangle_NegByte(run_t *run, bool printable) {
+
+ size_t off = mangle_getOffSet(run);
+ if (printable) {
+
+ run->dynfile->data[off] = 94 - (run->dynfile->data[off] - 32) + 32;
+
+ } else {
+
+ run->dynfile->data[off] = ~(run->dynfile->data[off]);
+
+ }
- mangle_Inflate(run, off, len, printable);
}
-static void mangle_Shrink(run_t* run, bool printable HF_ATTR_UNUSED) {
- if (run->dynfile->size <= 2U) {
- return;
- }
+static void mangle_Expand(run_t *run, bool printable) {
- size_t off_start = mangle_getOffSet(run);
- size_t len = mangle_LenLeft(run, off_start);
- if (len == 0) {
- return;
- }
- if (util_rnd64() % 16) {
- len = mangle_getLen(HF_MIN(16, len));
- } else {
- len = mangle_getLen(len);
- }
- size_t off_end = off_start + len;
- size_t len_to_move = run->dynfile->size - off_end;
+ size_t off = mangle_getOffSet(run);
+ size_t len;
+ if (util_rnd64() % 16) {
+
+ len = mangle_getLen(HF_MIN(16, run->global->mutate.maxInputSz - off));
+
+ } else {
+
+ len = mangle_getLen(run->global->mutate.maxInputSz - off);
+
+ }
+
+ mangle_Inflate(run, off, len, printable);
- mangle_Move(run, off_end, off_start, len_to_move);
- input_setSize(run, run->dynfile->size - len);
}
-static void mangle_ASCIINum(run_t* run, bool printable) {
- size_t len = util_rndGet(2, 8);
- char buf[20];
- snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64());
+static void mangle_Shrink(run_t *run, bool printable HF_ATTR_UNUSED) {
+
+ if (run->dynfile->size <= 2U) { return; }
+
+ size_t off_start = mangle_getOffSet(run);
+ size_t len = mangle_LenLeft(run, off_start);
+ if (len == 0) { return; }
+ if (util_rnd64() % 16) {
+
+ len = mangle_getLen(HF_MIN(16, len));
+
+ } else {
+
+ len = mangle_getLen(len);
+
+ }
+
+ size_t off_end = off_start + len;
+ size_t len_to_move = run->dynfile->size - off_end;
+
+ mangle_Move(run, off_end, off_start, len_to_move);
+ input_setSize(run, run->dynfile->size - len);
- mangle_UseValue(run, (const uint8_t*)buf, len, printable);
}
-static void mangle_ASCIINumChange(run_t* run, bool printable) {
- size_t off = mangle_getOffSet(run);
+static void mangle_ASCIINum(run_t *run, bool printable) {
- /* Find a digit */
- for (; off < run->dynfile->size; off++) {
- if (isdigit(run->dynfile->data[off])) {
- break;
- }
- }
- size_t left = run->dynfile->size - off;
- if (left == 0) {
- return;
- }
+ size_t len = util_rndGet(2, 8);
- size_t len = 0;
- uint64_t val = 0;
- /* 20 is maximum lenght of a string representing a 64-bit unsigned value */
- for (len = 0; (len < 20) && (len < left); len++) {
- char c = run->dynfile->data[off + len];
- if (!isdigit(c)) {
- break;
- }
- val *= 10;
- val += (c - '0');
- }
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%-19" PRId64, (int64_t)util_rnd64());
- switch (util_rndGet(0, 7)) {
- case 0:
- val++;
- break;
- case 1:
- val--;
- break;
- case 2:
- val *= 2;
- break;
- case 3:
- val /= 2;
- break;
- case 4:
- val = util_rnd64();
- break;
- case 5:
- val += util_rndGet(1, 256);
- break;
- case 6:
- val -= util_rndGet(1, 256);
- break;
- case 7:
- val = ~(val);
- break;
- default:
- LOG_F("Invalid choice");
- };
-
- char buf[20];
- snprintf(buf, sizeof(buf), "%-19" PRIu64, val);
-
- mangle_UseValueAt(run, off, (const uint8_t*)buf, len, printable);
-}
-
-static void mangle_Splice(run_t* run, bool printable) {
- if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) {
- mangle_Bytes(run, printable);
- return;
- }
+ mangle_UseValue(run, (const uint8_t *)buf, len, printable);
- size_t sz = 0;
- const uint8_t* buf = input_getRandomInputAsBuf(run, &sz);
- if (!buf) {
- LOG_E("input_getRandomInputAsBuf() returned no input");
- mangle_Bytes(run, printable);
- return;
- }
- if (!sz) {
- mangle_Bytes(run, printable);
- return;
- }
+}
- size_t remoteOff = mangle_getLen(sz) - 1;
- size_t len = mangle_getLen(sz - remoteOff);
- mangle_UseValue(run, &buf[remoteOff], len, printable);
-}
-
-static void mangle_Resize(run_t* run, bool printable) {
- ssize_t oldsz = run->dynfile->size;
- ssize_t newsz = 0;
-
- uint64_t choice = util_rndGet(0, 32);
- switch (choice) {
- case 0: /* Set new size arbitrarily */
- newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz);
- break;
- case 1 ... 4: /* Increase size by a small value */
- newsz = oldsz + (ssize_t)util_rndGet(0, 8);
- break;
- case 5: /* Increase size by a larger value */
- newsz = oldsz + (ssize_t)util_rndGet(9, 128);
- break;
- case 6 ... 9: /* Decrease size by a small value */
- newsz = oldsz - (ssize_t)util_rndGet(0, 8);
- break;
- case 10: /* Decrease size by a larger value */
- newsz = oldsz - (ssize_t)util_rndGet(9, 128);
- break;
- case 11 ... 32: /* Do nothing */
- newsz = oldsz;
- break;
- default:
- LOG_F("Illegal value from util_rndGet: %" PRIu64, choice);
- break;
- }
- if (newsz < 1) {
- newsz = 1;
- }
- if (newsz > (ssize_t)run->global->mutate.maxInputSz) {
- newsz = run->global->mutate.maxInputSz;
- }
+static void mangle_ASCIINumChange(run_t *run, bool printable) {
+
+ size_t off = mangle_getOffSet(run);
+
+ /* Find a digit */
+ for (; off < run->dynfile->size; off++) {
+
+ if (isdigit(run->dynfile->data[off])) { break; }
+
+ }
+
+ size_t left = run->dynfile->size - off;
+ if (left == 0) { return; }
+
+ size_t len = 0;
+ uint64_t val = 0;
+ /* 20 is maximum lenght of a string representing a 64-bit unsigned value */
+ for (len = 0; (len < 20) && (len < left); len++) {
+
+ char c = run->dynfile->data[off + len];
+ if (!isdigit(c)) { break; }
+ val *= 10;
+ val += (c - '0');
+
+ }
+
+ switch (util_rndGet(0, 7)) {
+
+ case 0:
+ val++;
+ break;
+ case 1:
+ val--;
+ break;
+ case 2:
+ val *= 2;
+ break;
+ case 3:
+ val /= 2;
+ break;
+ case 4:
+ val = util_rnd64();
+ break;
+ case 5:
+ val += util_rndGet(1, 256);
+ break;
+ case 6:
+ val -= util_rndGet(1, 256);
+ break;
+ case 7:
+ val = ~(val);
+ break;
+ default:
+ LOG_F("Invalid choice");
+
+ };
+
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%-19" PRIu64, val);
+
+ mangle_UseValueAt(run, off, (const uint8_t *)buf, len, printable);
- input_setSize(run, (size_t)newsz);
- if (newsz > oldsz) {
- if (printable) {
- memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz);
- }
- }
}
-void mangle_mangleContent(run_t* run, int speed_factor) {
- static void (*const mangleFuncs[])(run_t * run, bool printable) = {
- mangle_Shrink,
- mangle_Expand,
- mangle_Bit,
- mangle_IncByte,
- mangle_DecByte,
- mangle_NegByte,
- mangle_AddSub,
- mangle_MemSet,
- mangle_MemClr,
- mangle_MemSwap,
- mangle_MemCopy,
- mangle_Bytes,
- mangle_ASCIINum,
- mangle_ASCIINumChange,
- mangle_ByteRepeat,
- mangle_Magic,
- mangle_StaticDict,
- mangle_ConstFeedbackDict,
- mangle_RandomBuf,
- mangle_Splice,
- };
-
- if (run->mutationsPerRun == 0U) {
- return;
- }
- if (run->dynfile->size == 0U) {
- mangle_Resize(run, /* printable= */ run->global->cfg.only_printable);
+static void mangle_Splice(run_t *run, bool printable) {
+
+ if (run->global->feedback.dynFileMethod == _HF_DYNFILE_NONE) {
+
+ mangle_Bytes(run, printable);
+ return;
+
+ }
+
+ size_t sz = 0;
+ const uint8_t *buf = input_getRandomInputAsBuf(run, &sz);
+ if (!buf) {
+
+ LOG_E("input_getRandomInputAsBuf() returned no input");
+ mangle_Bytes(run, printable);
+ return;
+
+ }
+
+ if (!sz) {
+
+ mangle_Bytes(run, printable);
+ return;
+
+ }
+
+ size_t remoteOff = mangle_getLen(sz) - 1;
+ size_t len = mangle_getLen(sz - remoteOff);
+ mangle_UseValue(run, &buf[remoteOff], len, printable);
+
+}
+
+static void mangle_Resize(run_t *run, bool printable) {
+
+ ssize_t oldsz = run->dynfile->size;
+ ssize_t newsz = 0;
+
+ uint64_t choice = util_rndGet(0, 32);
+ switch (choice) {
+
+ case 0: /* Set new size arbitrarily */
+ newsz = (ssize_t)util_rndGet(1, run->global->mutate.maxInputSz);
+ break;
+ case 1 ... 4: /* Increase size by a small value */
+ newsz = oldsz + (ssize_t)util_rndGet(0, 8);
+ break;
+ case 5: /* Increase size by a larger value */
+ newsz = oldsz + (ssize_t)util_rndGet(9, 128);
+ break;
+ case 6 ... 9: /* Decrease size by a small value */
+ newsz = oldsz - (ssize_t)util_rndGet(0, 8);
+ break;
+ case 10: /* Decrease size by a larger value */
+ newsz = oldsz - (ssize_t)util_rndGet(9, 128);
+ break;
+ case 11 ... 32: /* Do nothing */
+ newsz = oldsz;
+ break;
+ default:
+ LOG_F("Illegal value from util_rndGet: %" PRIu64, choice);
+ break;
+
+ }
+
+ if (newsz < 1) { newsz = 1; }
+ if (newsz > (ssize_t)run->global->mutate.maxInputSz) {
+
+ newsz = run->global->mutate.maxInputSz;
+
+ }
+
+ input_setSize(run, (size_t)newsz);
+ if (newsz > oldsz) {
+
+ if (printable) { memset(&run->dynfile->data[oldsz], ' ', newsz - oldsz); }
+
+ }
+
+}
+
+void mangle_mangleContent(run_t *run, int speed_factor) {
+
+ static void (*const mangleFuncs[])(run_t * run, bool printable) = {
+
+ mangle_Shrink, mangle_Expand, mangle_Bit,
+ mangle_IncByte, mangle_DecByte, mangle_NegByte,
+ mangle_AddSub, mangle_MemSet, mangle_MemClr,
+ mangle_MemSwap, mangle_MemCopy, mangle_Bytes,
+ mangle_ASCIINum, mangle_ASCIINumChange, mangle_ByteRepeat,
+ mangle_Magic, mangle_StaticDict, mangle_ConstFeedbackDict,
+ mangle_RandomBuf, mangle_Splice,
+
+ };
+
+ if (run->mutationsPerRun == 0U) { return; }
+ if (run->dynfile->size == 0U) {
+
+ mangle_Resize(run, /* printable= */ run->global->cfg.only_printable);
+
+ }
+
+ uint64_t changesCnt = run->global->mutate.mutationsPerRun;
+
+ if (speed_factor < 5) {
+
+ changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun);
+
+ } else if (speed_factor < 10) {
+
+ changesCnt = run->global->mutate.mutationsPerRun;
+
+ } else {
+
+ changesCnt = HF_MIN(speed_factor, 10);
+ changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5));
+
+ }
+
+ /* If last coverage acquisition was more than 5 secs ago, use splicing more
+ * frequently */
+ if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) {
+
+ if (util_rnd64() & 0x1) {
+
+ mangle_Splice(run, run->global->cfg.only_printable);
+
}
- uint64_t changesCnt = run->global->mutate.mutationsPerRun;
+ }
+
+ for (uint64_t x = 0; x < changesCnt; x++) {
+
+ if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) {
+
+ /*
+ * mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback
+ * dictionary exists. If so, give it 50% chance of being used among all
+ * mangling functions.
+ */
+ mangle_ConstFeedbackDict(
+ run, /* printable= */ run->global->cfg.only_printable);
- if (speed_factor < 5) {
- changesCnt = util_rndGet(1, run->global->mutate.mutationsPerRun);
- } else if (speed_factor < 10) {
- changesCnt = run->global->mutate.mutationsPerRun;
} else {
- changesCnt = HF_MIN(speed_factor, 10);
- changesCnt = HF_MAX(changesCnt, (run->global->mutate.mutationsPerRun * 5));
- }
- /* If last coverage acquisition was more than 5 secs ago, use splicing more frequently */
- if ((time(NULL) - ATOMIC_GET(run->global->timing.lastCovUpdate)) > 5) {
- if (util_rnd64() & 0x1) {
- mangle_Splice(run, run->global->cfg.only_printable);
- }
- }
+ uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1);
+ mangleFuncs[choice](run,
+ /* printable= */ run->global->cfg.only_printable);
- for (uint64_t x = 0; x < changesCnt; x++) {
- if (run->global->feedback.cmpFeedback && (util_rnd64() & 0x1)) {
- /*
- * mangle_ConstFeedbackDict() is quite powerful if the dynamic feedback dictionary
- * exists. If so, give it 50% chance of being used among all mangling functions.
- */
- mangle_ConstFeedbackDict(run, /* printable= */ run->global->cfg.only_printable);
- } else {
- uint64_t choice = util_rndGet(0, ARRAYSIZE(mangleFuncs) - 1);
- mangleFuncs[choice](run, /* printable= */ run->global->cfg.only_printable);
- }
}
- wmb();
+ }
+
+ wmb();
+
}
+
diff --git a/custom_mutators/libafl_base/Cargo.toml b/custom_mutators/libafl_base/Cargo.toml
index 6e40fc39..ac6b0c8f 100644
--- a/custom_mutators/libafl_base/Cargo.toml
+++ b/custom_mutators/libafl_base/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "62614ce1016c86e3f00f35b56399292ceabd486b" }
+libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "266677bb88abe75165430f34e7de897c35560504" }
custom_mutator = { path = "../rust/custom_mutator", features = ["afl_internals"] }
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
diff --git a/custom_mutators/libafl_base/src/lib.rs b/custom_mutators/libafl_base/src/lib.rs
index 6f2db8ca..bae11e1f 100644
--- a/custom_mutators/libafl_base/src/lib.rs
+++ b/custom_mutators/libafl_base/src/lib.rs
@@ -1,5 +1,4 @@
#![cfg(unix)]
-#![allow(unused_variables)]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
@@ -18,10 +17,12 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
Mutator,
},
- state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State},
+ prelude::UsesInput,
+ state::{HasCorpus, HasMaxSize, HasMetadata, HasRand, State, UsesState},
Error,
};
+#[allow(clippy::identity_op)]
const MAX_FILE: usize = 1 * 1024 * 1024;
static mut AFL: Option<&'static afl_state> = None;
@@ -64,24 +65,32 @@ impl<'de> Deserialize<'de> for AFLCorpus {
}
}
-impl Corpus<BytesInput> for AFLCorpus {
+impl UsesState for AFLCorpus {
+ type State = AFLState;
+}
+
+impl Corpus for AFLCorpus {
#[inline]
fn count(&self) -> usize {
afl().queued_items as usize
}
#[inline]
- fn add(&mut self, testcase: Testcase<BytesInput>) -> Result<usize, Error> {
+ fn add(&mut self, _testcase: Testcase<BytesInput>) -> Result<usize, Error> {
unimplemented!();
}
#[inline]
- fn replace(&mut self, idx: usize, testcase: Testcase<BytesInput>) -> Result<(), Error> {
+ fn replace(
+ &mut self,
+ _idx: usize,
+ _testcase: Testcase<BytesInput>,
+ ) -> Result<Testcase<Self::Input>, Error> {
unimplemented!();
}
#[inline]
- fn remove(&mut self, idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
+ fn remove(&mut self, _idx: usize) -> Result<Option<Testcase<BytesInput>>, Error> {
unimplemented!();
}
@@ -92,7 +101,7 @@ impl Corpus<BytesInput> for AFLCorpus {
entries.entry(idx).or_insert_with(|| {
let queue_buf = std::slice::from_raw_parts_mut(afl().queue_buf, self.count());
let entry = queue_buf[idx].as_mut().unwrap();
- let fname = CStr::from_ptr((entry.fname as *mut i8).as_ref().unwrap())
+ let fname = CStr::from_ptr((entry.fname.cast::<i8>()).as_ref().unwrap())
.to_str()
.unwrap()
.to_owned();
@@ -127,9 +136,10 @@ pub struct AFLState {
}
impl AFLState {
+ #[must_use]
pub fn new(seed: u32) -> Self {
Self {
- rand: StdRand::with_seed(seed as u64),
+ rand: StdRand::with_seed(u64::from(seed)),
corpus: AFLCorpus::default(),
metadata: SerdeAnyMap::new(),
max_size: MAX_FILE,
@@ -153,7 +163,11 @@ impl HasRand for AFLState {
}
}
-impl HasCorpus<BytesInput> for AFLState {
+impl UsesInput for AFLState {
+ type Input = BytesInput;
+}
+
+impl HasCorpus for AFLState {
type Corpus = AFLCorpus;
#[inline]
@@ -208,7 +222,7 @@ impl CustomMutator for LibAFLBaseCustomMutator {
tokens.push(data.to_vec());
}
if !tokens.is_empty() {
- state.add_metadata(Tokens::new(tokens));
+ state.add_metadata(Tokens::from(tokens));
}
Ok(Self {
state,
@@ -220,7 +234,7 @@ impl CustomMutator for LibAFLBaseCustomMutator {
fn fuzz<'b, 's: 'b>(
&'s mut self,
buffer: &'b mut [u8],
- add_buff: Option<&[u8]>,
+ _add_buff: Option<&[u8]>,
max_size: usize,
) -> Result<Option<&'b [u8]>, Self::Error> {
self.state.set_max_size(max_size);
diff --git a/custom_mutators/radamsa/custom_mutator_helpers.h b/custom_mutators/radamsa/custom_mutator_helpers.h
deleted file mode 120000
index f7532ef9..00000000
--- a/custom_mutators/radamsa/custom_mutator_helpers.h
+++ /dev/null
@@ -1 +0,0 @@
-../examples/custom_mutator_helpers.h \ No newline at end of file
diff --git a/custom_mutators/radamsa/radamsa-mutator.c b/custom_mutators/radamsa/radamsa-mutator.c
index 624ace3d..466bb5c3 100644
--- a/custom_mutators/radamsa/radamsa-mutator.c
+++ b/custom_mutators/radamsa/radamsa-mutator.c
@@ -1,6 +1,5 @@
// This simple example just creates random buffer <= 100 filled with 'A'
// needs -I /path/to/AFLplusplus/include
-//#include "custom_mutator_helpers.h"
#include <stdint.h>
#include <stdlib.h>
@@ -8,19 +7,17 @@
#include <stdio.h>
#include "radamsa.h"
-#include "custom_mutator_helpers.h"
+#include "afl-fuzz.h"
typedef struct my_mutator {
- afl_t *afl;
-
- u8 *mutator_buf;
-
+ afl_state_t *afl;
+ u8 *mutator_buf;
unsigned int seed;
} my_mutator_t;
-my_mutator_t *afl_custom_init(afl_t *afl, unsigned int seed) {
+my_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
srand(seed);
my_mutator_t *data = calloc(1, sizeof(my_mutator_t));
diff --git a/custom_mutators/rust/custom_mutator-sys/Cargo.toml b/custom_mutators/rust/custom_mutator-sys/Cargo.toml
index 104f7df0..e38c972e 100644
--- a/custom_mutators/rust/custom_mutator-sys/Cargo.toml
+++ b/custom_mutators/rust/custom_mutator-sys/Cargo.toml
@@ -1,12 +1,12 @@
[package]
name = "custom_mutator-sys"
-version = "0.1.0"
+version = "0.1.1"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
-edition = "2018"
+edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[build-dependencies]
-bindgen = "0.56"
+bindgen = "0.63"
diff --git a/custom_mutators/rust/custom_mutator-sys/build.rs b/custom_mutators/rust/custom_mutator-sys/build.rs
index 3c88a90d..ba4390ff 100644
--- a/custom_mutators/rust/custom_mutator-sys/build.rs
+++ b/custom_mutators/rust/custom_mutator-sys/build.rs
@@ -15,8 +15,8 @@ fn main() {
// The input header we would like to generate
// bindings for.
.header("wrapper.h")
- .whitelist_type("afl_state_t")
- .blacklist_type(r"u\d+")
+ .allowlist_type("afl_state_t")
+ .blocklist_type(r"u\d+")
.opaque_type(r"_.*")
.opaque_type("FILE")
.opaque_type("in_addr(_t)?")
diff --git a/custom_mutators/rust/custom_mutator-sys/src/lib.rs b/custom_mutators/rust/custom_mutator-sys/src/lib.rs
index a38a13a8..719ac994 100644
--- a/custom_mutators/rust/custom_mutator-sys/src/lib.rs
+++ b/custom_mutators/rust/custom_mutator-sys/src/lib.rs
@@ -1,5 +1,7 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
+#![allow(clippy::too_many_lines)]
+#![allow(clippy::used_underscore_binding)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
diff --git a/custom_mutators/rust/custom_mutator/Cargo.toml b/custom_mutators/rust/custom_mutator/Cargo.toml
index 2d3cdbfa..30f764dc 100644
--- a/custom_mutators/rust/custom_mutator/Cargo.toml
+++ b/custom_mutators/rust/custom_mutator/Cargo.toml
@@ -2,7 +2,7 @@
name = "custom_mutator"
version = "0.1.0"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
-edition = "2018"
+edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/custom_mutators/rust/custom_mutator/src/lib.rs b/custom_mutators/rust/custom_mutator/src/lib.rs
index f872241e..3b635eb5 100644
--- a/custom_mutators/rust/custom_mutator/src/lib.rs
+++ b/custom_mutators/rust/custom_mutator/src/lib.rs
@@ -20,7 +20,7 @@
//! This binding is panic-safe in that it will prevent panics from unwinding into AFL++. Any panic will `abort` at the boundary between the custom mutator and AFL++.
//!
//! # Access to AFL++ internals
-//! This crate has an optional feature "afl_internals", which gives access to AFL++'s internal state.
+//! This crate has an optional feature "`afl_internals`", which gives access to AFL++'s internal state.
//! The state is passed to [`CustomMutator::init`], when the feature is activated.
//!
//! _This is completely unsafe and uses automatically generated types extracted from the AFL++ source._
@@ -115,7 +115,7 @@ pub mod wrappers {
impl<M: RawCustomMutator> FFIContext<M> {
fn from(ptr: *mut c_void) -> ManuallyDrop<Box<Self>> {
assert!(!ptr.is_null());
- ManuallyDrop::new(unsafe { Box::from_raw(ptr as *mut Self) })
+ ManuallyDrop::new(unsafe { Box::from_raw(ptr.cast::<Self>()) })
}
fn into_ptr(self: Box<Self>) -> *const c_void {
@@ -141,27 +141,28 @@ pub mod wrappers {
}
/// panic handler called for every panic
- fn panic_handler(method: &str, panic_info: Box<dyn Any + Send + 'static>) -> ! {
+ fn panic_handler(method: &str, panic_info: &Box<dyn Any + Send + 'static>) -> ! {
use std::ops::Deref;
- let cause = panic_info
- .downcast_ref::<String>()
- .map(String::deref)
- .unwrap_or_else(|| {
+ let cause = panic_info.downcast_ref::<String>().map_or_else(
+ || {
panic_info
.downcast_ref::<&str>()
.copied()
.unwrap_or("<cause unknown>")
- });
- eprintln!("A panic occurred at {}: {}", method, cause);
+ },
+ String::deref,
+ );
+ eprintln!("A panic occurred at {method}: {cause}");
abort()
}
/// Internal function used in the macro
#[cfg(not(feature = "afl_internals"))]
+ #[must_use]
pub fn afl_custom_init_<M: RawCustomMutator>(seed: u32) -> *const c_void {
match catch_unwind(|| FFIContext::<M>::new(seed).into_ptr()) {
Ok(ret) => ret,
- Err(err) => panic_handler("afl_custom_init", err),
+ Err(err) => panic_handler("afl_custom_init", &err),
}
}
@@ -176,7 +177,7 @@ pub mod wrappers {
FFIContext::<M>::new(afl, seed).into_ptr()
}) {
Ok(ret) => ret,
- Err(err) => panic_handler("afl_custom_init", err),
+ Err(err) => panic_handler("afl_custom_init", &err),
}
}
@@ -196,32 +197,27 @@ pub mod wrappers {
) -> usize {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
- if buf.is_null() {
- panic!("null buf passed to afl_custom_fuzz")
- }
- if out_buf.is_null() {
- panic!("null out_buf passed to afl_custom_fuzz")
- }
+
+ assert!(!buf.is_null(), "null buf passed to afl_custom_fuzz");
+ assert!(!out_buf.is_null(), "null out_buf passed to afl_custom_fuzz");
+
let buff_slice = slice::from_raw_parts_mut(buf, buf_size);
let add_buff_slice = if add_buf.is_null() {
None
} else {
Some(slice::from_raw_parts(add_buf, add_buf_size))
};
- match context.mutator.fuzz(buff_slice, add_buff_slice, max_size) {
- Some(buffer) => {
- *out_buf = buffer.as_ptr();
- buffer.len()
- }
- None => {
- // return the input buffer with 0-length to let AFL skip this mutation attempt
- *out_buf = buf;
- 0
- }
+ if let Some(buffer) = context.mutator.fuzz(buff_slice, add_buff_slice, max_size) {
+ *out_buf = buffer.as_ptr();
+ buffer.len()
+ } else {
+ // return the input buffer with 0-length to let AFL skip this mutation attempt
+ *out_buf = buf;
+ 0
}
}) {
Ok(ret) => ret,
- Err(err) => panic_handler("afl_custom_fuzz", err),
+ Err(err) => panic_handler("afl_custom_fuzz", &err),
}
}
@@ -237,9 +233,8 @@ pub mod wrappers {
) -> u32 {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
- if buf.is_null() {
- panic!("null buf passed to afl_custom_fuzz")
- }
+ assert!(!buf.is_null(), "null buf passed to afl_custom_fuzz");
+
let buf_slice = slice::from_raw_parts(buf, buf_size);
// see https://doc.rust-lang.org/nomicon/borrow-splitting.html
let ctx = &mut **context;
@@ -247,37 +242,39 @@ pub mod wrappers {
mutator.fuzz_count(buf_slice)
}) {
Ok(ret) => ret,
- Err(err) => panic_handler("afl_custom_fuzz_count", err),
+ Err(err) => panic_handler("afl_custom_fuzz_count", &err),
}
}
/// Internal function used in the macro
- pub fn afl_custom_queue_new_entry_<M: RawCustomMutator>(
+ pub unsafe fn afl_custom_queue_new_entry_<M: RawCustomMutator>(
data: *mut c_void,
filename_new_queue: *const c_char,
filename_orig_queue: *const c_char,
) -> bool {
match catch_unwind(|| {
let mut context = FFIContext::<M>::from(data);
- if filename_new_queue.is_null() {
- panic!("received null filename_new_queue in afl_custom_queue_new_entry");
- }
+ assert!(
+ !filename_new_queue.is_null(),
+ "received null filename_new_queue in afl_custom_queue_new_entry"
+ );
+
let filename_new_queue = Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename_new_queue) }.to_bytes(),
));
- let filename_orig_queue = if !filename_orig_queue.is_null() {
+ let filename_orig_queue = if filename_orig_queue.is_null() {
+ None
+ } else {
Some(Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename_orig_queue) }.to_bytes(),
)))
- } else {
- None
};
context
.mutator
.queue_new_entry(filename_new_queue, filename_orig_queue)
}) {
Ok(ret) => ret,
- Err(err) => panic_handler("afl_custom_queue_new_entry", err),
+ Err(err) => panic_handler("afl_custom_queue_new_entry", &err),
}
}
@@ -292,7 +289,7 @@ pub mod wrappers {
ManuallyDrop::into_inner(FFIContext::<M>::from(data));
}) {
Ok(ret) => ret,
- Err(err) => panic_handler("afl_custom_deinit", err),
+ Err(err) => panic_handler("afl_custom_deinit", &err),
}
}
@@ -306,13 +303,13 @@ pub mod wrappers {
buf.extend_from_slice(res.as_bytes());
buf.push(0);
// unwrapping here, as the error case should be extremely rare
- CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
+ CStr::from_bytes_with_nul(buf).unwrap().as_ptr()
} else {
null()
}
}) {
Ok(ret) => ret,
- Err(err) => panic_handler("afl_custom_introspection", err),
+ Err(err) => panic_handler("afl_custom_introspection", &err),
}
}
@@ -329,18 +326,18 @@ pub mod wrappers {
buf.extend_from_slice(res.as_bytes());
buf.push(0);
// unwrapping here, as the error case should be extremely rare
- CStr::from_bytes_with_nul(&buf).unwrap().as_ptr()
+ CStr::from_bytes_with_nul(buf).unwrap().as_ptr()
} else {
null()
}
}) {
Ok(ret) => ret,
- Err(err) => panic_handler("afl_custom_describe", err),
+ Err(err) => panic_handler("afl_custom_describe", &err),
}
}
/// Internal function used in the macro
- pub fn afl_custom_queue_get_<M: RawCustomMutator>(
+ pub unsafe fn afl_custom_queue_get_<M: RawCustomMutator>(
data: *mut c_void,
filename: *const c_char,
) -> u8 {
@@ -348,12 +345,12 @@ pub mod wrappers {
let mut context = FFIContext::<M>::from(data);
assert!(!filename.is_null());
- context.mutator.queue_get(Path::new(OsStr::from_bytes(
+ u8::from(context.mutator.queue_get(Path::new(OsStr::from_bytes(
unsafe { CStr::from_ptr(filename) }.to_bytes(),
- ))) as u8
+ ))))
}) {
Ok(ret) => ret,
- Err(err) => panic_handler("afl_custom_queue_get", err),
+ Err(err) => panic_handler("afl_custom_queue_get", &err),
}
}
}
@@ -373,7 +370,7 @@ macro_rules! _define_afl_custom_init {
};
}
-/// An exported macro to defined afl_custom_init meant for insternal usage
+/// An exported macro to defined `afl_custom_init` meant for internal usage
#[cfg(not(feature = "afl_internals"))]
#[macro_export]
macro_rules! _define_afl_custom_init {
@@ -444,7 +441,7 @@ macro_rules! export_mutator {
}
#[no_mangle]
- pub extern "C" fn afl_custom_queue_new_entry(
+ pub unsafe extern "C" fn afl_custom_queue_new_entry(
data: *mut ::std::os::raw::c_void,
filename_new_queue: *const ::std::os::raw::c_char,
filename_orig_queue: *const ::std::os::raw::c_char,
@@ -457,7 +454,7 @@ macro_rules! export_mutator {
}
#[no_mangle]
- pub extern "C" fn afl_custom_queue_get(
+ pub unsafe extern "C" fn afl_custom_queue_get(
data: *mut ::std::os::raw::c_void,
filename: *const ::std::os::raw::c_char,
) -> u8 {
@@ -520,9 +517,10 @@ mod sanity_test {
export_mutator!(ExampleMutator);
}
-#[allow(unused_variables)]
/// A custom mutator.
/// [`CustomMutator::handle_error`] will be called in case any method returns an [`Result::Err`].
+#[allow(unused_variables)]
+#[allow(clippy::missing_errors_doc)]
pub trait CustomMutator {
/// The error type. All methods must return the same error type.
type Error: Debug;
@@ -537,7 +535,7 @@ pub trait CustomMutator {
.map(|v| !v.is_empty())
.unwrap_or(false)
{
- eprintln!("Error in custom mutator: {:?}", err)
+ eprintln!("Error in custom mutator: {err:?}");
}
}
@@ -759,8 +757,7 @@ mod truncate_test {
let actual_output = truncate_str_unicode_safe(input, *max_len);
assert_eq!(
&actual_output, expected_output,
- "{:#?} truncated to {} bytes should be {:#?}, but is {:#?}",
- input, max_len, expected_output, actual_output
+ "{input:#?} truncated to {max_len} bytes should be {expected_output:#?}, but is {actual_output:#?}"
);
}
}
diff --git a/custom_mutators/rust/example/Cargo.toml b/custom_mutators/rust/example/Cargo.toml
index 070d23b1..9d53ebe5 100644
--- a/custom_mutators/rust/example/Cargo.toml
+++ b/custom_mutators/rust/example/Cargo.toml
@@ -2,7 +2,7 @@
name = "example_mutator"
version = "0.1.0"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
-edition = "2018"
+edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/custom_mutators/rust/example_lain/Cargo.toml b/custom_mutators/rust/example_lain/Cargo.toml
index 29d606a4..c52bf86f 100644
--- a/custom_mutators/rust/example_lain/Cargo.toml
+++ b/custom_mutators/rust/example_lain/Cargo.toml
@@ -2,7 +2,7 @@
name = "example_lain"
version = "0.1.0"
authors = ["Julius Hohnerlein <julihoh@users.noreply.github.com>"]
-edition = "2018"
+edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html