mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-16 03:48:08 +00:00
first version with unix domain sockets is ready for testing
This commit is contained in:
@ -1,5 +1,4 @@
|
||||
#include "../../include/afl-fuzz.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -7,10 +6,10 @@
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#define INIT_BUF_SIZE 4096
|
||||
#define SOCKET_NAME "/tmp/atnwalk.socket"
|
||||
|
||||
|
||||
// handshake constants
|
||||
const uint8_t SERVER_ARE_YOU_ALIVE = 42;
|
||||
const uint8_t SERVER_YES_I_AM_ALIVE = 213;
|
||||
@ -23,8 +22,10 @@ const uint8_t SERVER_ENCODE_BIT = 0b00001000;
|
||||
|
||||
|
||||
typedef struct atnwalk_mutator {
|
||||
uint8_t *decoded_buf;
|
||||
size_t decoded_size;
|
||||
uint8_t *fuzz_buf;
|
||||
size_t fuzz_size;
|
||||
uint8_t *post_process_buf;
|
||||
size_t post_process_size;
|
||||
} atnwalk_mutator_t;
|
||||
|
||||
|
||||
@ -55,6 +56,32 @@ int write_all(int fd, uint8_t *buf, size_t buf_size) {
|
||||
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
|
||||
@ -67,19 +94,21 @@ int write_all(int fd, uint8_t *buf, size_t buf_size) {
|
||||
* 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) {
|
||||
atnwalk_mutator_t *afl_custom_init(void *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->decoded_buf = (uint8_t *) malloc(INIT_BUF_SIZE);
|
||||
data->decoded_size = INIT_BUF_SIZE;
|
||||
data->fuzz_buf = (uint8_t *) malloc(INIT_BUF_SIZE);
|
||||
data->fuzz_size = INIT_BUF_SIZE;
|
||||
data->post_process_buf = (uint8_t *) malloc(INIT_BUF_SIZE);
|
||||
data->post_process_size = INIT_BUF_SIZE;
|
||||
return data;
|
||||
}
|
||||
|
||||
// TODO: implement
|
||||
|
||||
/**
|
||||
* Perform custom mutations on a given input
|
||||
*
|
||||
@ -100,13 +129,12 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
|
||||
uint8_t *add_buf, size_t add_buf_size, size_t max_size) {
|
||||
struct sockaddr_un addr;
|
||||
int fd_socket;
|
||||
ssize_t n;
|
||||
uint8_t buffer[5];
|
||||
uint8_t ctrl_buf[8];
|
||||
uint8_t wanted;
|
||||
|
||||
// initialize the socket
|
||||
fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd_socket == -1) {
|
||||
perror("socket");
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
@ -114,26 +142,127 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
|
||||
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) {
|
||||
perror("atnwalk server is down");
|
||||
close(fd_socket);
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!write_all(fd_socket, buffer, 5)) {
|
||||
perror("write to atnwalk server failed");
|
||||
// TODO: how to set connection deadline? maybe not required if server already closes the connection?
|
||||
|
||||
// TODO: there should be some kind of loop retrying with different seeds and ultimately giving up on that input?
|
||||
// maybe this is not necessary, because we may also just return a single byte in case of failure?
|
||||
|
||||
// ask whether the server is alive
|
||||
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
|
||||
if (!write_all(fd_socket, ctrl_buf, 1)) {
|
||||
close(fd_socket);
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (read_all(fd_socket, buffer, 5)) {
|
||||
perror("read to atnwalk server failed");
|
||||
exit(EXIT_FAILURE);
|
||||
// see whether the server replies as expected
|
||||
if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
|
||||
close(fd_socket);
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// tell the server what we want to do
|
||||
wanted = SERVER_MUTATE_BIT | SERVER_ENCODE_BIT;
|
||||
|
||||
// 50% chance to perform a crossover if there is an additional buffer available
|
||||
if ((add_buf_size > 0) && (rand() % 2)) {
|
||||
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)) {
|
||||
close(fd_socket);
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// send the data to mutate and encode
|
||||
if (!write_all(fd_socket, buf, buf_size)) {
|
||||
close(fd_socket);
|
||||
*out_buf = buf;
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
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)) {
|
||||
close(fd_socket);
|
||||
*out_buf = buf;
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
// send the additional data for crossover
|
||||
if (!write_all(fd_socket, add_buf, add_buf_size)) {
|
||||
close(fd_socket);
|
||||
*out_buf = buf;
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
close(fd_socket);
|
||||
*out_buf = buf;
|
||||
return buf_size;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
close(fd_socket);
|
||||
*out_buf = buf;
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
// obtain the required buffer size for the data that will be returned
|
||||
if (!read_all(fd_socket, ctrl_buf, 4)) {
|
||||
close(fd_socket);
|
||||
*out_buf = buf;
|
||||
return buf_size;
|
||||
}
|
||||
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) {
|
||||
close(fd_socket);
|
||||
*out_buf = buf;
|
||||
return 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
|
||||
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)) {
|
||||
close(fd_socket);
|
||||
*out_buf = buf;
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
close(fd_socket);
|
||||
return new_size;
|
||||
}
|
||||
|
||||
// TODO: implement
|
||||
|
||||
/**
|
||||
* A post-processing function to use right before AFL writes the test case to
|
||||
* disk in order to execute the target.
|
||||
@ -151,23 +280,90 @@ size_t afl_custom_fuzz(atnwalk_mutator_t *data, uint8_t *buf, size_t buf_size, u
|
||||
* 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) {
|
||||
data->decoded_buf[0] = 'p';
|
||||
data->decoded_buf[1] = 'u';
|
||||
data->decoded_buf[2] = 't';
|
||||
data->decoded_buf[3] = 's';
|
||||
data->decoded_buf[4] = ' ';
|
||||
data->decoded_buf[5] = ';';
|
||||
data->decoded_buf[6] = '\n';
|
||||
return 7;
|
||||
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) {
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
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) {
|
||||
close(fd_socket);
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ask whether the server is alive
|
||||
ctrl_buf[0] = SERVER_ARE_YOU_ALIVE;
|
||||
if (!write_all(fd_socket, ctrl_buf, 1)) {
|
||||
close(fd_socket);
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// see whether the server replies as expected
|
||||
if (!read_all(fd_socket, ctrl_buf, 1) || ctrl_buf[0] != SERVER_YES_I_AM_ALIVE) {
|
||||
close(fd_socket);
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
close(fd_socket);
|
||||
*out_buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// send the data to decode
|
||||
if (!write_all(fd_socket, buf, buf_size)) {
|
||||
close(fd_socket);
|
||||
*out_buf = buf;
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
// obtain the required buffer size for the data that will be returned
|
||||
if (!read_all(fd_socket, ctrl_buf, 4)) {
|
||||
close(fd_socket);
|
||||
*out_buf = buf;
|
||||
return buf_size;
|
||||
}
|
||||
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)) {
|
||||
close(fd_socket);
|
||||
*out_buf = buf;
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
close(fd_socket);
|
||||
return new_size;
|
||||
}
|
||||
|
||||
// TODO: implement
|
||||
|
||||
/**
|
||||
* Deinitialize everything
|
||||
*
|
||||
* @param data The data ptr from afl_custom_init
|
||||
*/
|
||||
void afl_custom_deinit(atnwalk_mutator_t *data) {
|
||||
free(data->decoded_buf);
|
||||
free(data->fuzz_buf);
|
||||
free(data->post_process_buf);
|
||||
free(data);
|
||||
}
|
||||
|
@ -130,12 +130,15 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
|
||||
new_size = afl->max_length;
|
||||
|
||||
}
|
||||
|
||||
if (new_mem != *mem) { *mem = new_mem; }
|
||||
// TODO: think about how to enable the change without breaking other implementations
|
||||
// if (new_mem != *mem) { *mem = new_mem; }
|
||||
|
||||
/* everything as planned. use the potentially new data. */
|
||||
afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
|
||||
len = new_size;
|
||||
// TODO: think about how to enable the change without breaking other implementations
|
||||
afl_fsrv_write_to_testcase(&afl->fsrv, new_mem, new_size);
|
||||
|
||||
// TODO: think about how to enable the change without breaking other implementations
|
||||
// len = new_size;
|
||||
|
||||
} else {
|
||||
|
||||
|
Reference in New Issue
Block a user