mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-15 19:38:09 +00:00
support custom mutator introspection
This commit is contained in:
@ -37,6 +37,7 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
|
|||||||
- added NO_SPLICING compile option and makefile define
|
- added NO_SPLICING compile option and makefile define
|
||||||
- added INTROSPECTION make target that writes all mutations to
|
- added INTROSPECTION make target that writes all mutations to
|
||||||
out/NAME/introspection.txt
|
out/NAME/introspection.txt
|
||||||
|
- added INTROSPECTION support for custom modules
|
||||||
- print special compile time options used in help output
|
- print special compile time options used in help output
|
||||||
- instrumentation
|
- instrumentation
|
||||||
- We received an enhanced gcc_plugin module from AdaCore, thank you
|
- We received an enhanced gcc_plugin module from AdaCore, thank you
|
||||||
|
@ -42,6 +42,7 @@ size_t afl_custom_havoc_mutation(void *data, unsigned char *buf, size_t buf_size
|
|||||||
unsigned char afl_custom_havoc_mutation_probability(void *data);
|
unsigned char afl_custom_havoc_mutation_probability(void *data);
|
||||||
unsigned char afl_custom_queue_get(void *data, const unsigned char *filename);
|
unsigned char afl_custom_queue_get(void *data, const unsigned char *filename);
|
||||||
void afl_custom_queue_new_entry(void *data, const unsigned char *filename_new_queue, const unsigned int *filename_orig_queue);
|
void afl_custom_queue_new_entry(void *data, const unsigned char *filename_new_queue, const unsigned int *filename_orig_queue);
|
||||||
|
const char* afl_custom_introspection(my_mutator_t *data);
|
||||||
void afl_custom_deinit(void *data);
|
void afl_custom_deinit(void *data);
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -81,6 +82,9 @@ def queue_new_entry(filename_new_queue, filename_orig_queue):
|
|||||||
pass
|
pass
|
||||||
```
|
```
|
||||||
|
|
||||||
|
def introspection():
|
||||||
|
return string
|
||||||
|
|
||||||
### Custom Mutation
|
### Custom Mutation
|
||||||
|
|
||||||
- `init`:
|
- `init`:
|
||||||
@ -130,6 +134,12 @@ def queue_new_entry(filename_new_queue, filename_orig_queue):
|
|||||||
|
|
||||||
This methods is called after adding a new test case to the queue.
|
This methods is called after adding a new test case to the queue.
|
||||||
|
|
||||||
|
- `introspection` (optional):
|
||||||
|
|
||||||
|
This method is called after a new queue entry, crash or timeout is
|
||||||
|
discovered if compiled with INTROSPECTION. The custom mutator can then
|
||||||
|
return a string (const char *) that reports the exact mutations used.
|
||||||
|
|
||||||
- `deinit`:
|
- `deinit`:
|
||||||
|
|
||||||
The last method to be called, deinitializing the state.
|
The last method to be called, deinitializing the state.
|
||||||
|
@ -310,6 +310,7 @@ enum {
|
|||||||
/* 09 */ PY_FUNC_HAVOC_MUTATION_PROBABILITY,
|
/* 09 */ PY_FUNC_HAVOC_MUTATION_PROBABILITY,
|
||||||
/* 10 */ PY_FUNC_QUEUE_GET,
|
/* 10 */ PY_FUNC_QUEUE_GET,
|
||||||
/* 11 */ PY_FUNC_QUEUE_NEW_ENTRY,
|
/* 11 */ PY_FUNC_QUEUE_NEW_ENTRY,
|
||||||
|
/* 12 */ PY_FUNC_INTROSPECTION,
|
||||||
PY_FUNC_COUNT
|
PY_FUNC_COUNT
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -684,6 +685,8 @@ typedef struct afl_state {
|
|||||||
|
|
||||||
u32 custom_mutators_count;
|
u32 custom_mutators_count;
|
||||||
|
|
||||||
|
struct custom_mutator *current_custom_fuzz;
|
||||||
|
|
||||||
list_t custom_mutator_list;
|
list_t custom_mutator_list;
|
||||||
|
|
||||||
/* this is a fixed buffer of size map_size that can be used by any function if
|
/* this is a fixed buffer of size map_size that can be used by any function if
|
||||||
@ -747,6 +750,15 @@ struct custom_mutator {
|
|||||||
*/
|
*/
|
||||||
void *(*afl_custom_init)(afl_state_t *afl, unsigned int seed);
|
void *(*afl_custom_init)(afl_state_t *afl, unsigned int seed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When afl-fuzz was compiled with INTROSPECTION=1 then custom mutators can
|
||||||
|
* also give introspection information back with this function.
|
||||||
|
*
|
||||||
|
* @param data pointer returned in afl_custom_init for this fuzz case
|
||||||
|
* @return pointer to a text string (const char*)
|
||||||
|
*/
|
||||||
|
const char *(*afl_custom_introspection)(void *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called just before fuzzing a queue entry with the custom
|
* This method is called just before fuzzing a queue entry with the custom
|
||||||
* mutator, and receives the initial buffer. It should return the number of
|
* mutator, and receives the initial buffer. It should return the number of
|
||||||
@ -961,6 +973,7 @@ size_t trim_py(void *, u8 **);
|
|||||||
size_t havoc_mutation_py(void *, u8 *, size_t, u8 **, size_t);
|
size_t havoc_mutation_py(void *, u8 *, size_t, u8 **, size_t);
|
||||||
u8 havoc_mutation_probability_py(void *);
|
u8 havoc_mutation_probability_py(void *);
|
||||||
u8 queue_get_py(void *, const u8 *);
|
u8 queue_get_py(void *, const u8 *);
|
||||||
|
const char *introspection_py(void *);
|
||||||
void queue_new_entry_py(void *, const u8 *, const u8 *);
|
void queue_new_entry_py(void *, const u8 *, const u8 *);
|
||||||
void deinit_py(void *);
|
void deinit_py(void *);
|
||||||
|
|
||||||
|
@ -588,8 +588,32 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
|||||||
add_to_queue(afl, queue_fn, len, 0);
|
add_to_queue(afl, queue_fn, len, 0);
|
||||||
|
|
||||||
#ifdef INTROSPECTION
|
#ifdef INTROSPECTION
|
||||||
|
if (afl->mutation[0] != 0) {
|
||||||
|
|
||||||
fprintf(afl->introspection_file, "QUEUE %s = %s\n", afl->mutation,
|
fprintf(afl->introspection_file, "QUEUE %s = %s\n", afl->mutation,
|
||||||
afl->queue_top->fname);
|
afl->queue_top->fname);
|
||||||
|
|
||||||
|
} else if (afl->custom_mutators_count && afl->current_custom_fuzz) {
|
||||||
|
|
||||||
|
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
|
||||||
|
|
||||||
|
if (afl->current_custom_fuzz == el && el->afl_custom_introspection) {
|
||||||
|
|
||||||
|
const char *ptr = el->afl_custom_introspection(el->data);
|
||||||
|
|
||||||
|
if (ptr != NULL && *ptr != 0) {
|
||||||
|
|
||||||
|
fprintf(afl->introspection_file, "QUEUE CUSTOM %s = %s\n", ptr,
|
||||||
|
afl->queue_top->fname);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (hnb == 2) {
|
if (hnb == 2) {
|
||||||
@ -665,7 +689,32 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
|||||||
|
|
||||||
++afl->unique_tmouts;
|
++afl->unique_tmouts;
|
||||||
#ifdef INTROSPECTION
|
#ifdef INTROSPECTION
|
||||||
|
if (afl->mutation[0] != 0) {
|
||||||
|
|
||||||
fprintf(afl->introspection_file, "UNIQUE_TIMEOUT %s\n", afl->mutation);
|
fprintf(afl->introspection_file, "UNIQUE_TIMEOUT %s\n", afl->mutation);
|
||||||
|
|
||||||
|
} else if (afl->custom_mutators_count && afl->current_custom_fuzz) {
|
||||||
|
|
||||||
|
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
|
||||||
|
|
||||||
|
if (afl->current_custom_fuzz == el && el->afl_custom_introspection) {
|
||||||
|
|
||||||
|
const char *ptr = el->afl_custom_introspection(el->data);
|
||||||
|
|
||||||
|
if (ptr != NULL && *ptr != 0) {
|
||||||
|
|
||||||
|
fprintf(afl->introspection_file,
|
||||||
|
"UNIQUE_TIMEOUT CUSTOM %s = %s\n", ptr,
|
||||||
|
afl->queue_top->fname);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Before saving, we make sure that it's a genuine hang by re-running
|
/* Before saving, we make sure that it's a genuine hang by re-running
|
||||||
@ -751,7 +800,31 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
|||||||
|
|
||||||
++afl->unique_crashes;
|
++afl->unique_crashes;
|
||||||
#ifdef INTROSPECTION
|
#ifdef INTROSPECTION
|
||||||
|
if (afl->mutation[0] != 0) {
|
||||||
|
|
||||||
fprintf(afl->introspection_file, "UNIQUE_CRASH %s\n", afl->mutation);
|
fprintf(afl->introspection_file, "UNIQUE_CRASH %s\n", afl->mutation);
|
||||||
|
|
||||||
|
} else if (afl->custom_mutators_count && afl->current_custom_fuzz) {
|
||||||
|
|
||||||
|
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
|
||||||
|
|
||||||
|
if (afl->current_custom_fuzz == el && el->afl_custom_introspection) {
|
||||||
|
|
||||||
|
const char *ptr = el->afl_custom_introspection(el->data);
|
||||||
|
|
||||||
|
if (ptr != NULL && *ptr != 0) {
|
||||||
|
|
||||||
|
fprintf(afl->introspection_file, "UNIQUE_CRASH CUSTOM %s = %s\n",
|
||||||
|
ptr, afl->queue_top->fname);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
if (unlikely(afl->infoexec)) {
|
if (unlikely(afl->infoexec)) {
|
||||||
|
|
||||||
|
@ -166,6 +166,13 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* "afl_custom_introspection", optional */
|
||||||
|
#ifdef INTROSPECTION
|
||||||
|
mutator->afl_custom_introspection = dlsym(dh, "afl_custom_introspection");
|
||||||
|
if (!mutator->afl_custom_introspection)
|
||||||
|
ACTF("optional symbol 'afl_custom_introspection' not found.");
|
||||||
|
#endif
|
||||||
|
|
||||||
/* "afl_custom_fuzz_count", optional */
|
/* "afl_custom_fuzz_count", optional */
|
||||||
mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count");
|
mutator->afl_custom_fuzz_count = dlsym(dh, "afl_custom_fuzz_count");
|
||||||
if (!mutator->afl_custom_fuzz_count)
|
if (!mutator->afl_custom_fuzz_count)
|
||||||
|
@ -1780,10 +1780,16 @@ custom_mutator_stage:
|
|||||||
|
|
||||||
orig_hit_cnt = afl->queued_paths + afl->unique_crashes;
|
orig_hit_cnt = afl->queued_paths + afl->unique_crashes;
|
||||||
|
|
||||||
|
#ifdef INTROSPECTION
|
||||||
|
afl->mutation[0] = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
|
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
|
||||||
|
|
||||||
if (el->afl_custom_fuzz) {
|
if (el->afl_custom_fuzz) {
|
||||||
|
|
||||||
|
afl->current_custom_fuzz = el;
|
||||||
|
|
||||||
if (el->afl_custom_fuzz_count)
|
if (el->afl_custom_fuzz_count)
|
||||||
afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len);
|
afl->stage_max = el->afl_custom_fuzz_count(el->data, out_buf, len);
|
||||||
else
|
else
|
||||||
@ -1889,6 +1895,8 @@ custom_mutator_stage:
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afl->current_custom_fuzz = NULL;
|
||||||
|
|
||||||
if (!has_custom_fuzz) goto havoc_stage;
|
if (!has_custom_fuzz) goto havoc_stage;
|
||||||
|
|
||||||
new_hit_cnt = afl->queued_paths + afl->unique_crashes;
|
new_hit_cnt = afl->queued_paths + afl->unique_crashes;
|
||||||
|
@ -163,6 +163,8 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
|
|||||||
PyObject_GetAttrString(py_module, "queue_get");
|
PyObject_GetAttrString(py_module, "queue_get");
|
||||||
py_functions[PY_FUNC_QUEUE_NEW_ENTRY] =
|
py_functions[PY_FUNC_QUEUE_NEW_ENTRY] =
|
||||||
PyObject_GetAttrString(py_module, "queue_new_entry");
|
PyObject_GetAttrString(py_module, "queue_new_entry");
|
||||||
|
py_functions[PY_FUNC_INTROSPECTION] =
|
||||||
|
PyObject_GetAttrString(py_module, "introspection");
|
||||||
py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit");
|
py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit");
|
||||||
if (!py_functions[PY_FUNC_DEINIT])
|
if (!py_functions[PY_FUNC_DEINIT])
|
||||||
FATAL("deinit function not found in python module");
|
FATAL("deinit function not found in python module");
|
||||||
@ -381,6 +383,15 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef INTROSPECTION
|
||||||
|
if (py_functions[PY_FUNC_INTROSPECTION]) {
|
||||||
|
|
||||||
|
mutator->afl_custom_introspection = introspection_py;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
OKF("Python mutator '%s' installed successfully.", module_name);
|
OKF("Python mutator '%s' installed successfully.", module_name);
|
||||||
|
|
||||||
/* Initialize the custom mutator */
|
/* Initialize the custom mutator */
|
||||||
@ -679,6 +690,28 @@ u8 havoc_mutation_probability_py(void *py_mutator) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *introspection_py(void *py_mutator) {
|
||||||
|
|
||||||
|
PyObject *py_args, *py_value;
|
||||||
|
|
||||||
|
py_args = PyTuple_New(0);
|
||||||
|
py_value = PyObject_CallObject(
|
||||||
|
((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_INTROSPECTION],
|
||||||
|
py_args);
|
||||||
|
Py_DECREF(py_args);
|
||||||
|
|
||||||
|
if (py_value == NULL) {
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return PyByteArray_AsString(py_value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
u8 queue_get_py(void *py_mutator, const u8 *filename) {
|
u8 queue_get_py(void *py_mutator, const u8 *filename) {
|
||||||
|
|
||||||
PyObject *py_args, *py_value;
|
PyObject *py_args, *py_value;
|
||||||
|
Reference in New Issue
Block a user