code format

This commit is contained in:
vanhauser-thc
2023-04-22 11:39:44 +02:00
parent c5e5a17d67
commit 6bd48a48cb
4 changed files with 439 additions and 315 deletions

View File

@ -11,29 +11,6 @@ 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`. 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 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:
```sh
git submodule update --init
```
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 ## Production-Ready Custom Mutators
This directory holds ready to use custom mutators. This directory holds ready to use custom mutators.
@ -47,6 +24,42 @@ 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. 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:
```sh
git submodule update --init
```
Read the README in the [Grammar-Mutator] repository on how to use it.
[Grammar-Mutator]: https://github.com/AFLplusplus/Grammar-Mutator
Note that this custom mutator is not very good though!
### Other Mutators
atnwalk and gramatron are grammar custom mutators. Example grammars are
provided.
honggfuzz, libfuzzer and libafl are partial implementations based on the
mutator implementations of the respective fuzzers.
More for playing than serious usage.
radamsa is slow and not very good.
## 3rd Party Custom Mutators ## 3rd Party Custom Mutators
### Superion Mutators ### Superion Mutators

View File

@ -11,10 +11,12 @@
#define BUF_SIZE_INIT 4096 #define BUF_SIZE_INIT 4096
#define SOCKET_NAME "./atnwalk.socket" #define SOCKET_NAME "./atnwalk.socket"
// how many errors (e.g. timeouts) to tolerate until moving on to the next queue entry // how many errors (e.g. timeouts) to tolerate until moving on to the next queue
// entry
#define ATNWALK_ERRORS_MAX 1 #define ATNWALK_ERRORS_MAX 1
// how many execution timeouts to tolerate until moving on to the next queue entry // how many execution timeouts to tolerate until moving on to the next queue
// entry
#define EXEC_TIMEOUT_MAX 2 #define EXEC_TIMEOUT_MAX 2
// handshake constants // handshake constants
@ -27,8 +29,8 @@ const uint8_t SERVER_MUTATE_BIT = 0b00000010;
const uint8_t SERVER_DECODE_BIT = 0b00000100; const uint8_t SERVER_DECODE_BIT = 0b00000100;
const uint8_t SERVER_ENCODE_BIT = 0b00001000; const uint8_t SERVER_ENCODE_BIT = 0b00001000;
typedef struct atnwalk_mutator { typedef struct atnwalk_mutator {
afl_state_t *afl; afl_state_t *afl;
uint8_t atnwalk_error_count; uint8_t atnwalk_error_count;
uint64_t prev_timeouts; uint64_t prev_timeouts;
@ -41,56 +43,63 @@ typedef struct atnwalk_mutator {
size_t fuzz_size; size_t fuzz_size;
uint8_t *post_process_buf; uint8_t *post_process_buf;
size_t post_process_size; size_t post_process_size;
} atnwalk_mutator_t; } atnwalk_mutator_t;
int read_all(int fd, uint8_t *buf, size_t buf_size) { int read_all(int fd, uint8_t *buf, size_t buf_size) {
int n; int n;
size_t offset = 0; size_t offset = 0;
while (offset < buf_size) { while (offset < buf_size) {
n = read(fd, buf + offset, buf_size - offset); n = read(fd, buf + offset, buf_size - offset);
if (n == -1) { if (n == -1) { return 0; }
return 0;
}
offset += n; offset += n;
}
return 1;
} }
return 1;
}
int write_all(int fd, uint8_t *buf, size_t buf_size) { int write_all(int fd, uint8_t *buf, size_t buf_size) {
int n; int n;
size_t offset = 0; size_t offset = 0;
while (offset < buf_size) { while (offset < buf_size) {
n = write(fd, buf + offset, buf_size - offset); n = write(fd, buf + offset, buf_size - offset);
if (n == -1) { if (n == -1) { return 0; }
return 0;
}
offset += n; offset += n;
}
return 1;
} }
return 1;
}
void put_uint32(uint8_t *buf, uint32_t val) { void put_uint32(uint8_t *buf, uint32_t val) {
buf[0] = (uint8_t)(val >> 24); buf[0] = (uint8_t)(val >> 24);
buf[1] = (uint8_t)((val & 0x00ff0000) >> 16); buf[1] = (uint8_t)((val & 0x00ff0000) >> 16);
buf[2] = (uint8_t)((val & 0x0000ff00) >> 8); buf[2] = (uint8_t)((val & 0x0000ff00) >> 8);
buf[3] = (uint8_t)(val & 0x000000ff); buf[3] = (uint8_t)(val & 0x000000ff);
} }
uint32_t to_uint32(uint8_t *buf) { uint32_t to_uint32(uint8_t *buf) {
uint32_t val = 0; uint32_t val = 0;
val |= (((uint32_t)buf[0]) << 24); val |= (((uint32_t)buf[0]) << 24);
val |= (((uint32_t)buf[1]) << 16); val |= (((uint32_t)buf[1]) << 16);
val |= (((uint32_t)buf[2]) << 8); val |= (((uint32_t)buf[2]) << 8);
val |= ((uint32_t)buf[3]); val |= ((uint32_t)buf[3]);
return val; return val;
} }
void put_uint64(uint8_t *buf, uint64_t val) { void put_uint64(uint8_t *buf, uint64_t val) {
buf[0] = (uint8_t)(val >> 56); buf[0] = (uint8_t)(val >> 56);
buf[1] = (uint8_t)((val & 0x00ff000000000000) >> 48); buf[1] = (uint8_t)((val & 0x00ff000000000000) >> 48);
buf[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40); buf[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40);
@ -99,8 +108,8 @@ void put_uint64(uint8_t *buf, uint64_t val) {
buf[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16); buf[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16);
buf[6] = (uint8_t)((val & 0x000000000000ff00) >> 8); buf[6] = (uint8_t)((val & 0x000000000000ff00) >> 8);
buf[7] = (uint8_t)(val & 0x00000000000000ff); buf[7] = (uint8_t)(val & 0x00000000000000ff);
}
}
/** /**
* Initialize this custom mutator * Initialize this custom mutator
@ -114,12 +123,17 @@ void put_uint64(uint8_t *buf, uint64_t val) {
* Return NULL on error. * Return NULL on error.
*/ */
atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) { atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
srand(seed); srand(seed);
atnwalk_mutator_t *data = (atnwalk_mutator_t *) malloc(sizeof(atnwalk_mutator_t)); atnwalk_mutator_t *data =
(atnwalk_mutator_t *)malloc(sizeof(atnwalk_mutator_t));
if (!data) { if (!data) {
perror("afl_custom_init alloc"); perror("afl_custom_init alloc");
return NULL; return NULL;
} }
data->afl = afl; data->afl = afl;
data->prev_hits = 0; data->prev_hits = 0;
data->fuzz_buf = (uint8_t *)malloc(BUF_SIZE_INIT); data->fuzz_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
@ -127,56 +141,64 @@ atnwalk_mutator_t *afl_custom_init(afl_state_t *afl, unsigned int seed) {
data->post_process_buf = (uint8_t *)malloc(BUF_SIZE_INIT); data->post_process_buf = (uint8_t *)malloc(BUF_SIZE_INIT);
data->post_process_size = BUF_SIZE_INIT; data->post_process_size = BUF_SIZE_INIT;
return data; return data;
} }
unsigned int afl_custom_fuzz_count(atnwalk_mutator_t *data,
const unsigned char *buf, size_t buf_size) {
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
// afl_custom_fuzz_count is called exactly once before entering the 'stage-loop' for the current queue entry // 'stage-loop' for the current queue entry thus, we use it to reset the error
// thus, we use it to reset the error count and to initialize stage variables (somewhat not intended by the API, // 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) // but still better than rewriting the whole thing to have a custom mutator
// stage)
data->atnwalk_error_count = 0; data->atnwalk_error_count = 0;
data->prev_timeouts = data->afl->total_tmouts; data->prev_timeouts = data->afl->total_tmouts;
// it might happen that on the last execution of the splice stage a new path is found // it might happen that on the last execution of the splice stage a new path
// we need to fix that here and count it // is found we need to fix that here and count it
if (data->prev_hits) { if (data->prev_hits) {
data->afl->stage_finds[STAGE_SPLICE] += data->afl->queued_items + data->afl->saved_crashes - 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->prev_hits = data->afl->queued_items + data->afl->saved_crashes;
data->stage_havoc_cur = 0; data->stage_havoc_cur = 0;
data->stage_splice_cur = 0; data->stage_splice_cur = 0;
// 50% havoc, 50% splice // 50% havoc, 50% splice
data->stage_havoc_max = data->afl->stage_max >> 1; data->stage_havoc_max = data->afl->stage_max >> 1;
if (data->stage_havoc_max < HAVOC_MIN) { if (data->stage_havoc_max < HAVOC_MIN) { data->stage_havoc_max = HAVOC_MIN; }
data->stage_havoc_max = HAVOC_MIN;
}
data->stage_splice_max = data->stage_havoc_max; data->stage_splice_max = data->stage_havoc_max;
return data->stage_havoc_max + data->stage_splice_max; return data->stage_havoc_max + data->stage_splice_max;
}
}
size_t fail_fatal(int fd_socket, uint8_t **out_buf) { size_t fail_fatal(int fd_socket, uint8_t **out_buf) {
if (fd_socket != -1) {
close(fd_socket); if (fd_socket != -1) { close(fd_socket); }
}
*out_buf = NULL; *out_buf = NULL;
return 0; return 0;
} }
size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf,
size_t buf_size, uint8_t **out_buf) {
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); }
if (fd_socket != -1) {
close(fd_socket);
}
data->atnwalk_error_count++; data->atnwalk_error_count++;
if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) { if (data->atnwalk_error_count > ATNWALK_ERRORS_MAX) {
data->afl->stage_max = data->afl->stage_cur; data->afl->stage_max = data->afl->stage_cur;
}
*out_buf = buf;
return buf_size;
} }
*out_buf = buf;
return buf_size;
}
/** /**
* Perform custom mutations on a given input * Perform custom mutations on a given input
@ -194,8 +216,10 @@ size_t fail_gracefully(int fd_socket, atnwalk_mutator_t *data, uint8_t *buf, siz
* produce data larger than max_size. * produce data larger than max_size.
* @return Size of the mutated output. * @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, size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size,
uint8_t *add_buf, size_t add_buf_size, size_t max_size) { uint8_t **out_buf, uint8_t *add_buf, size_t add_buf_size,
size_t max_size) {
struct sockaddr_un addr; struct sockaddr_un addr;
int fd_socket; int fd_socket;
uint8_t ctrl_buf[8]; uint8_t ctrl_buf[8];
@ -203,43 +227,68 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
// let's display what's going on in a nice way // let's display what's going on in a nice way
if (data->stage_havoc_cur == 0) { if (data->stage_havoc_cur == 0) {
data->afl->stage_name = (uint8_t *)"atnwalk - havoc"; data->afl->stage_name = (uint8_t *)"atnwalk - havoc";
} }
if (data->stage_havoc_cur == data->stage_havoc_max) { if (data->stage_havoc_cur == data->stage_havoc_max) {
data->afl->stage_name = (uint8_t *)"atnwalk - splice"; data->afl->stage_name = (uint8_t *)"atnwalk - splice";
} }
// increase the respective havoc or splice counters // increase the respective havoc or splice counters
if (data->stage_havoc_cur < data->stage_havoc_max) { if (data->stage_havoc_cur < data->stage_havoc_max) {
data->stage_havoc_cur++; data->stage_havoc_cur++;
data->afl->stage_cycles[STAGE_HAVOC]++; data->afl->stage_cycles[STAGE_HAVOC]++;
} else { } else {
// if there is nothing to splice, continue with havoc and skip splicing this time
// if there is nothing to splice, continue with havoc and skip splicing this
// time
if (data->afl->ready_for_splicing_count < 1) { if (data->afl->ready_for_splicing_count < 1) {
data->stage_havoc_max = data->afl->stage_max; data->stage_havoc_max = data->afl->stage_max;
data->stage_havoc_cur++; data->stage_havoc_cur++;
data->afl->stage_cycles[STAGE_HAVOC]++; data->afl->stage_cycles[STAGE_HAVOC]++;
} else { } else {
data->stage_splice_cur++; data->stage_splice_cur++;
data->afl->stage_cycles[STAGE_SPLICE]++; data->afl->stage_cycles[STAGE_SPLICE]++;
} }
} }
// keep track of found new corpus seeds per stage // keep track of found new corpus seeds per stage
if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) { if (data->afl->queued_items + data->afl->saved_crashes > data->prev_hits) {
if (data->stage_splice_cur <= 1) { if (data->stage_splice_cur <= 1) {
data->afl->stage_finds[STAGE_HAVOC] += data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
data->afl->stage_finds[STAGE_HAVOC] +=
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
} else { } else {
data->afl->stage_finds[STAGE_SPLICE] += data->afl->stage_finds[STAGE_SPLICE] +=
data->afl->queued_items + data->afl->saved_crashes - data->prev_hits; data->afl->queued_items + data->afl->saved_crashes - data->prev_hits;
} }
} }
data->prev_hits = data->afl->queued_items + data->afl->saved_crashes; 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 // 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) { if (data->afl->total_tmouts - data->prev_timeouts >= EXEC_TIMEOUT_MAX) {
data->afl->stage_max = data->afl->stage_cur; data->afl->stage_max = data->afl->stage_cur;
return fail_gracefully(-1, data, buf, buf_size, out_buf); return fail_gracefully(-1, data, buf, buf_size, out_buf);
} }
// initialize the socket // initialize the socket
@ -249,97 +298,132 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) { if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
return fail_fatal(fd_socket, out_buf); return fail_fatal(fd_socket, out_buf);
} }
// ask whether the server is alive // ask whether the server is alive
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
if (!write_all(fd_socket, ctrl_buf, 1)) { if (!write_all(fd_socket, ctrl_buf, 1)) {
return fail_fatal(fd_socket, out_buf); return fail_fatal(fd_socket, out_buf);
} }
// see whether the server replies as expected // see whether the server replies as expected
if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { if (!read_all(fd_socket, ctrl_buf, 1) ||
ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
return fail_fatal(fd_socket, out_buf); return fail_fatal(fd_socket, out_buf);
} }
// tell the server what we want to do // tell the server what we want to do
wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT; wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT;
// perform a crossover if we are splicing // perform a crossover if we are splicing
if (data->stage_splice_cur > 0) { if (data->stage_splice_cur > 0) { wanted |= SERVER_CROSSOVER_BIT; }
wanted |= SERVER_CROSSOVER_BIT;
}
// tell the server what we want and how much data will be sent // tell the server what we want and how much data will be sent
ctrl_buf[0] = wanted; ctrl_buf[0] = wanted;
put_uint32(ctrl_buf + 1, (uint32_t)buf_size); put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
if (!write_all(fd_socket, ctrl_buf, 5)) { if (!write_all(fd_socket, ctrl_buf, 5)) {
return fail_fatal(fd_socket, out_buf); return fail_fatal(fd_socket, out_buf);
} }
// send the data to mutate and encode // send the data to mutate and encode
if (!write_all(fd_socket, buf, buf_size)) { if (!write_all(fd_socket, buf, buf_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
if (wanted & SERVER_CROSSOVER_BIT) { if (wanted & SERVER_CROSSOVER_BIT) {
// since we requested crossover, we will first tell how much additional data is to be expected
// 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); put_uint32(ctrl_buf, (uint32_t)add_buf_size);
if (!write_all(fd_socket, ctrl_buf, 4)) { if (!write_all(fd_socket, ctrl_buf, 4)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
// send the additional data for crossover // send the additional data for crossover
if (!write_all(fd_socket, add_buf, add_buf_size)) { if (!write_all(fd_socket, add_buf, add_buf_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
// lastly, a seed is required for crossover so send one // lastly, a seed is required for crossover so send one
put_uint64(ctrl_buf, (uint64_t)rand()); put_uint64(ctrl_buf, (uint64_t)rand());
if (!write_all(fd_socket, ctrl_buf, 8)) { if (!write_all(fd_socket, ctrl_buf, 8)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
} }
// since we requested mutation, we need to provide a seed for that // since we requested mutation, we need to provide a seed for that
put_uint64(ctrl_buf, (uint64_t)rand()); put_uint64(ctrl_buf, (uint64_t)rand());
if (!write_all(fd_socket, ctrl_buf, 8)) { if (!write_all(fd_socket, ctrl_buf, 8)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
// obtain the required buffer size for the data that will be returned // obtain the required buffer size for the data that will be returned
if (!read_all(fd_socket, ctrl_buf, 4)) { if (!read_all(fd_socket, ctrl_buf, 4)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
size_t new_size = (size_t)to_uint32(ctrl_buf); size_t new_size = (size_t)to_uint32(ctrl_buf);
// if the data is too large then we ignore this round // if the data is too large then we ignore this round
if (new_size > max_size) { if (new_size > max_size) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
if (new_size > buf_size) { if (new_size > buf_size) {
// buf is too small, need to use data->fuzz_buf, let's see whether we need to reallocate
// buf is too small, need to use data->fuzz_buf, let's see whether we need
// to reallocate
if (new_size > data->fuzz_size) { if (new_size > data->fuzz_size) {
data->fuzz_size = new_size << 1; data->fuzz_size = new_size << 1;
data->fuzz_buf = (uint8_t *)realloc(data->fuzz_buf, data->fuzz_size); data->fuzz_buf = (uint8_t *)realloc(data->fuzz_buf, data->fuzz_size);
} }
*out_buf = data->fuzz_buf; *out_buf = data->fuzz_buf;
} else { } else {
// new_size fits into buf, so re-use it // new_size fits into buf, so re-use it
*out_buf = buf; *out_buf = buf;
} }
// obtain the encoded data // obtain the encoded data
if (!read_all(fd_socket, *out_buf, new_size)) { if (!read_all(fd_socket, *out_buf, new_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
close(fd_socket); close(fd_socket);
return new_size; return new_size;
}
}
/** /**
* A post-processing function to use right before AFL writes the test case to * A post-processing function to use right before AFL writes the test case to
@ -357,68 +441,88 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
* @return Size of the output buffer after processing or the needed amount. * @return Size of the output buffer after processing or the needed amount.
* A return of 0 indicates an error. * 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) { 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; struct sockaddr_un addr;
int fd_socket; int fd_socket;
uint8_t ctrl_buf[8]; uint8_t ctrl_buf[8];
// initialize the socket // initialize the socket
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd_socket == -1) { if (fd_socket == -1) { return fail_fatal(fd_socket, out_buf); }
return fail_fatal(fd_socket, out_buf);
}
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) { if (connect(fd_socket, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
return fail_fatal(fd_socket, out_buf); return fail_fatal(fd_socket, out_buf);
} }
// ask whether the server is alive // ask whether the server is alive
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE; ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
if (!write_all(fd_socket, ctrl_buf, 1)) { if (!write_all(fd_socket, ctrl_buf, 1)) {
return fail_fatal(fd_socket, out_buf); return fail_fatal(fd_socket, out_buf);
} }
// see whether the server replies as expected // see whether the server replies as expected
if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) { if (!read_all(fd_socket, ctrl_buf, 1) ||
ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
return fail_fatal(fd_socket, out_buf); return fail_fatal(fd_socket, out_buf);
} }
// tell the server what we want and how much data will be sent // tell the server what we want and how much data will be sent
ctrl_buf[0] = SERVER_DECODE_BIT; ctrl_buf[0] = SERVER_DECODE_BIT;
put_uint32(ctrl_buf + 1, (uint32_t)buf_size); put_uint32(ctrl_buf + 1, (uint32_t)buf_size);
if (!write_all(fd_socket, ctrl_buf, 5)) { if (!write_all(fd_socket, ctrl_buf, 5)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
// send the data to decode // send the data to decode
if (!write_all(fd_socket, buf, buf_size)) { if (!write_all(fd_socket, buf, buf_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
// obtain the required buffer size for the data that will be returned // obtain the required buffer size for the data that will be returned
if (!read_all(fd_socket, ctrl_buf, 4)) { if (!read_all(fd_socket, ctrl_buf, 4)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
size_t new_size = (size_t)to_uint32(ctrl_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 // need to use data->post_process_buf, let's see whether we need to reallocate
if (new_size > data->post_process_size) { if (new_size > data->post_process_size) {
data->post_process_size = new_size << 1; data->post_process_size = new_size << 1;
data->post_process_buf = (uint8_t *) realloc(data->post_process_buf, data->post_process_size); data->post_process_buf =
(uint8_t *)realloc(data->post_process_buf, data->post_process_size);
} }
*out_buf = data->post_process_buf; *out_buf = data->post_process_buf;
// obtain the decoded data // obtain the decoded data
if (!read_all(fd_socket, *out_buf, new_size)) { if (!read_all(fd_socket, *out_buf, new_size)) {
return fail_gracefully(fd_socket, data, buf, buf_size, out_buf); return fail_gracefully(fd_socket, data, buf, buf_size, out_buf);
} }
close(fd_socket); close(fd_socket);
return new_size; return new_size;
}
}
/** /**
* Deinitialize everything * Deinitialize everything
@ -426,7 +530,10 @@ size_t afl_custom_post_process(atnwalk_mutator_t *data, uint8_t *buf, size_t buf
* @param data The data ptr from afl_custom_init * @param data The data ptr from afl_custom_init
*/ */
void afl_custom_deinit(atnwalk_mutator_t *data) { void afl_custom_deinit(atnwalk_mutator_t *data) {
free(data->fuzz_buf); free(data->fuzz_buf);
free(data->post_process_buf); free(data->post_process_buf);
free(data); free(data);
} }

View File

@ -4,8 +4,12 @@
release of the tool. See README.md for the general instruction manual. release of the tool. See README.md for the general instruction manual.
### Version ++4.07a (dev) ### Version ++4.07a (dev)
- afl-fuzz:
- new env `AFL_POST_PROCESS_KEEP_ORIGINAL` to keep the orignal
data before post process on finds
- afl-showmap: - afl-showmap:
- added custom mutator post_process and send support - added custom mutator post_process and send support
- a new grammar custom mutator atnwalk was submitted by @voidptr127 !
### Version ++4.06c (release) ### Version ++4.06c (release)

View File

@ -156,8 +156,8 @@ __attribute__((visibility("default"))) void js_api_set_instrument_instructions(
} }
__attribute__((visibility("default"))) void js_api_set_instrument_no_dynamic_load( __attribute__((visibility("default"))) void
void) { js_api_set_instrument_no_dynamic_load(void) {
ranges_inst_dynamic_load = FALSE; ranges_inst_dynamic_load = FALSE;