Finish refactoring APIs for the custom mutator and Python module

- Remove AFL_PYTHON_ONLY (env) and python_only (variable)
- Unify fuzz API of the custom mutator and Python module
- Merge the custom mutator into the old python_stage, which is now renamed to custom_mutator_stage
This commit is contained in:
h1994st
2020-03-03 19:48:13 -05:00
parent 90506479e7
commit df46521658
11 changed files with 115 additions and 232 deletions

2
.gitignore vendored
View File

@ -18,9 +18,11 @@ afl-qemu-trace
afl-showmap afl-showmap
afl-tmin afl-tmin
afl-analyze.8 afl-analyze.8
afl-as.8
afl-clang-fast++.8 afl-clang-fast++.8
afl-clang-fast.8 afl-clang-fast.8
afl-cmin.8 afl-cmin.8
afl-cmin.bash.8
afl-fuzz.8 afl-fuzz.8
afl-gcc.8 afl-gcc.8
afl-gcc-fast.8 afl-gcc-fast.8

View File

@ -13,7 +13,7 @@ a given grammar.
The custom mutator library is passed to afl-fuzz via the The custom mutator library is passed to afl-fuzz via the
AFL_CUSTOM_MUTATOR_LIBRARY environment variable. The library must export AFL_CUSTOM_MUTATOR_LIBRARY environment variable. The library must export
the afl_custom_mutator() function and must be compiled as a shared object. the afl_custom_fuzz() function and must be compiled as a shared object.
For example: For example:
``` ```
$CC -shared -Wall -O3 <lib-name>.c -o <lib-name>.so $CC -shared -Wall -O3 <lib-name>.c -o <lib-name>.so

View File

@ -104,7 +104,7 @@ Then there are a few specific features that are only available in llvm_mode:
- Setting AFL_LLVM_LAF_SPLIT_COMPARES will split all floating point and - Setting AFL_LLVM_LAF_SPLIT_COMPARES will split all floating point and
64, 32 and 16 bit integer CMP instructions 64, 32 and 16 bit integer CMP instructions
See llvm_mode/README.laf-intel.md for more information. See llvm_mode/README.laf-intel.md for more information.
### WHITELIST ### WHITELIST
@ -192,7 +192,7 @@ checks or alter some of the more exotic semantics of the tool:
deciding if a particular test case is a "hang". The default is 1 second deciding if a particular test case is a "hang". The default is 1 second
or the value of the -t parameter, whichever is larger. Dialing the value or the value of the -t parameter, whichever is larger. Dialing the value
down can be useful if you are very concerned about slow inputs, or if you down can be useful if you are very concerned about slow inputs, or if you
don't want AFL to spend too much time classifying that stuff and just don't want AFL to spend too much time classifying that stuff and just
rapidly put all timeouts in that bin. rapidly put all timeouts in that bin.
- AFL_NO_ARITH causes AFL to skip most of the deterministic arithmetics. - AFL_NO_ARITH causes AFL to skip most of the deterministic arithmetics.
@ -223,15 +223,15 @@ checks or alter some of the more exotic semantics of the tool:
for more. for more.
- Setting AFL_CUSTOM_MUTATOR_LIBRARY to a shared library with - Setting AFL_CUSTOM_MUTATOR_LIBRARY to a shared library with
afl_custom_mutator() creates additional mutations through this library. afl_custom_fuzz() creates additional mutations through this library.
If afl-fuzz is compiled with Python (which is autodetected during builing
afl-fuzz), setting AFL_PYTHON_MODULE to a Python module can also provide
additional mutations.
If AFL_CUSTOM_MUTATOR_ONLY is also set, all mutations will solely be If AFL_CUSTOM_MUTATOR_ONLY is also set, all mutations will solely be
performed with/from the library. See [custom_mutator.md](custom_mutator.md) performed with/from the library/Python module.
- For AFL_PYTHON_MODULE and AFL_PYTHON_ONLY - they require afl-fuzz to
be compiled with Python (which is autodetected during builing afl-fuzz).
Please see [python_mutators.md](python_mutators.md).
This feature allows to configure custom mutators which can be very helpful This feature allows to configure custom mutators which can be very helpful
in e.g. fuzzing XML or other highly flexible structured input. in e.g. fuzzing XML or other highly flexible structured input.
Please see [custom_mutator.md](custom_mutator.md) or [python_mutators.md](python_mutators.md).
- AFL_FAST_CAL keeps the calibration stage about 2.5x faster (albeit less - AFL_FAST_CAL keeps the calibration stage about 2.5x faster (albeit less
precise), which can help when starting a session against a slow target. precise), which can help when starting a session against a slow target.
@ -283,7 +283,7 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
- Setting AFL_INST_LIBS causes the translator to also instrument the code - Setting AFL_INST_LIBS causes the translator to also instrument the code
inside any dynamically linked libraries (notably including glibc). inside any dynamically linked libraries (notably including glibc).
- Setting AFL_COMPCOV_LEVEL enables the CompareCoverage tracing of all cmp - Setting AFL_COMPCOV_LEVEL enables the CompareCoverage tracing of all cmp
and sub in x86 and x86_64 and memory comparions functions (e.g. strcmp, and sub in x86 and x86_64 and memory comparions functions (e.g. strcmp,
memcmp, ...) when libcompcov is preloaded using AFL_PRELOAD. memcmp, ...) when libcompcov is preloaded using AFL_PRELOAD.
@ -292,7 +292,7 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
only comparisons with immediate values / read-only memory and only comparisons with immediate values / read-only memory and
AFL_COMPCOV_LEVEL=2 that instruments all the comparions. Level 2 is more AFL_COMPCOV_LEVEL=2 that instruments all the comparions. Level 2 is more
accurate but may need a larger shared memory. accurate but may need a larger shared memory.
- Setting AFL_QEMU_COMPCOV enables the CompareCoverage tracing of all - Setting AFL_QEMU_COMPCOV enables the CompareCoverage tracing of all
cmp and sub in x86 and x86_64. cmp and sub in x86 and x86_64.
This is an alias of AFL_COMPCOV_LEVEL=1 when AFL_COMPCOV_LEVEL is This is an alias of AFL_COMPCOV_LEVEL=1 when AFL_COMPCOV_LEVEL is
@ -304,25 +304,25 @@ The QEMU wrapper used to instrument binary-only code supports several settings:
- AFL_DEBUG will print the found entrypoint for the binary to stderr. - AFL_DEBUG will print the found entrypoint for the binary to stderr.
Use this if you are unsure if the entrypoint might be wrong - but Use this if you are unsure if the entrypoint might be wrong - but
use it directly, e.g. afl-qemu-trace ./program use it directly, e.g. afl-qemu-trace ./program
- AFL_ENTRYPOINT allows you to specify a specific entrypoint into the - AFL_ENTRYPOINT allows you to specify a specific entrypoint into the
binary (this can be very good for the performance!). binary (this can be very good for the performance!).
The entrypoint is specified as hex address, e.g. 0x4004110 The entrypoint is specified as hex address, e.g. 0x4004110
Note that the address must be the address of a basic block. Note that the address must be the address of a basic block.
- When the target is i386/x86_64 you can specify the address of the function - When the target is i386/x86_64 you can specify the address of the function
that has to be the body of the persistent loop using that has to be the body of the persistent loop using
AFL_QEMU_PERSISTENT_ADDR=`start addr`. AFL_QEMU_PERSISTENT_ADDR=`start addr`.
- Another modality to execute the persistent loop is to specify also the - Another modality to execute the persistent loop is to specify also the
AFL_QEMU_PERSISTENT_RET=`end addr` env variable. AFL_QEMU_PERSISTENT_RET=`end addr` env variable.
With this variable assigned, instead of patching the return address, the With this variable assigned, instead of patching the return address, the
specified instruction is transformed to a jump towards `start addr`. specified instruction is transformed to a jump towards `start addr`.
- AFL_QEMU_PERSISTENT_GPR=1 QEMU will save the original value of general - AFL_QEMU_PERSISTENT_GPR=1 QEMU will save the original value of general
purpose registers and restore them in each persistent cycle. purpose registers and restore them in each persistent cycle.
- With AFL_QEMU_PERSISTENT_RETADDR_OFFSET you can specify the offset from the - With AFL_QEMU_PERSISTENT_RETADDR_OFFSET you can specify the offset from the
stack pointer in which QEMU can find the return address when `start addr` is stack pointer in which QEMU can find the return address when `start addr` is
hitted. hitted.
@ -376,7 +376,7 @@ The library honors these environmental variables:
- AFL_LD_NO_CALLOC_OVER inhibits abort() on calloc() overflows. Most - AFL_LD_NO_CALLOC_OVER inhibits abort() on calloc() overflows. Most
of the common allocators check for that internally and return NULL, so of the common allocators check for that internally and return NULL, so
it's a security risk only in more exotic setups. it's a security risk only in more exotic setups.
- AFL_ALIGNED_ALLOC=1 will force the alignment of the allocation size to - AFL_ALIGNED_ALLOC=1 will force the alignment of the allocation size to
max_align_t to be compliant with the C standard. max_align_t to be compliant with the C standard.
@ -410,7 +410,7 @@ optimal values if not already present in the environment:
- In the same vein, by default, MSAN_OPTIONS are set to: - In the same vein, by default, MSAN_OPTIONS are set to:
exit_code=86 (required for legacy reasons) exit_code=86 (required for legacy reasons)
abort_on_error=1 abort_on_error=1
symbolize=0 symbolize=0
msan_track_origins=0 msan_track_origins=0

View File

@ -276,8 +276,7 @@ extern u8 cal_cycles, /* Calibration cycles defaults */
no_unlink, /* do not unlink cur_input */ no_unlink, /* do not unlink cur_input */
use_stdin, /* use stdin for sending data */ use_stdin, /* use stdin for sending data */
debug, /* Debug mode */ debug, /* Debug mode */
custom_only, /* Custom mutator only mode */ custom_only; /* Custom mutator only mode */
python_only; /* Python-only mode */
extern u32 stats_update_freq; /* Stats update frequency (execs) */ extern u32 stats_update_freq; /* Stats update frequency (execs) */
@ -471,6 +470,8 @@ struct custom_mutator {
* Initialize the custom mutator. * Initialize the custom mutator.
* *
* (Optional) * (Optional)
*
* @param seed Seed used for the mutation.
*/ */
void (*afl_custom_init)(unsigned int seed); void (*afl_custom_init)(unsigned int seed);
@ -479,17 +480,18 @@ struct custom_mutator {
* *
* (Optional for now. Required in the future) * (Optional for now. Required in the future)
* *
* @param[in] data Input data to be mutated * @param[in] buf Input data to be mutated
* @param[in] size Size of input data * @param[in] buf_size Size of input data
* @param[in] add_buf Buffer containing the additional test case
* @param[in] add_buf_size Size of the additional test case
* @param[out] mutated_out Buffer to store the mutated input * @param[out] mutated_out Buffer to store the mutated input
* @param[in] max_size Maximum size of the mutated output. The mutation must not * @param[in] max_size Maximum size of the mutated output. The mutation must not
* produce data larger than max_size. * produce data larger than max_size.
* @param[in] seed Seed used for the mutation. The mutation should produce the
* same output given the same seed.
* @return Size of the mutated output. * @return Size of the mutated output.
*/ */
size_t (*afl_custom_fuzz)(u8* data, size_t size, u8* mutated_out, size_t (*afl_custom_fuzz)(u8* buf, size_t buf_size,
size_t max_size, unsigned int seed); u8* add_buf, size_t add_buf_size,
u8* mutated_out, size_t max_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
@ -498,12 +500,14 @@ struct custom_mutator {
* (Optional) If this functionality is not needed, simply don't define this * (Optional) If this functionality is not needed, simply don't define this
* function. * function.
* *
* @param[in] data Buffer containing the test case to be executed * @param[in] buf Buffer containing the test case to be executed
* @param[in] size Size of the test case * @param[in] buf_size Size of the test case
* @param[out] new_data Buffer to store the test case after processing * @param[out] out_buf Pointer to the buffer of storing the test case after
* @return Size of data after processing * processing. External library should allocate memory for out_buf. AFL++
* will release the memory after saving the test case.
* @return Size of the output buffer after processing
*/ */
size_t (*afl_custom_pre_save)(u8* data, size_t size, u8** new_data); size_t (*afl_custom_pre_save)(u8* buf, size_t buf_size, u8** out_buf);
/** /**
* This method is called at the start of each trimming operation and receives * This method is called at the start of each trimming operation and receives
@ -521,11 +525,11 @@ struct custom_mutator {
* *
* (Optional) * (Optional)
* *
* @param data Buffer containing the test case * @param buf Buffer containing the test case
* @param size Size of the test case * @param buf_size Size of the test case
* @return The amount of possible iteration steps to trim the input * @return The amount of possible iteration steps to trim the input
*/ */
u32 (*afl_custom_init_trim)(u8* data, size_t size); u32 (*afl_custom_init_trim)(u8* buf, size_t buf_size);
/** /**
* This method is called for each trimming operation. It doesn't have any * This method is called for each trimming operation. It doesn't have any
@ -538,10 +542,12 @@ struct custom_mutator {
* *
* (Optional) * (Optional)
* *
* @param[out] ret Buffer containing the trimmed test case * @param[out] out_buf Pointer to the buffer containing the trimmed test case.
* @param[out] ret_len Size of the trimmed test case * External library should allocate memory for out_buf. AFL++ will release
* the memory after saving the test case.
* @param[out] out_buf_size Pointer to the size of the trimmed test case
*/ */
void (*afl_custom_trim)(u8** ret, size_t* ret_len); void (*afl_custom_trim)(u8** out_buf, size_t* out_buf_size);
/** /**
* This method is called after each trim operation to inform you if your * This method is called after each trim operation to inform you if your
@ -627,9 +633,9 @@ int init_py_module(u8*);
void finalize_py_module(); void finalize_py_module();
void init_py(unsigned int seed); void init_py(unsigned int seed);
/* TODO: unify fuzz interface for custom mutator and Python mutator */ size_t fuzz_py(u8* buf, size_t buf_size,
size_t fuzz_py(u8*, size_t, u8*, size_t, unsigned int); u8* add_buf, size_t add_buf_size,
void fuzz_py_original(char*, size_t, char*, size_t, char**, size_t*); u8* mutated_out, size_t max_size);
size_t pre_save_py(u8* data, size_t size, u8** new_data); size_t pre_save_py(u8* data, size_t size, u8** new_data);
u32 init_trim_py(u8*, size_t); u32 init_trim_py(u8*, size_t);
u32 post_trim_py(u8); u32 post_trim_py(u8);

View File

@ -24,7 +24,7 @@ const char *afl_environment_variables[] = {
"AFL_NO_X86", // not really an env but we dont want to warn on it "AFL_NO_X86", // not really an env but we dont want to warn on it
"AFL_PATH", "AFL_PERFORMANCE_FILE", "AFL_PATH", "AFL_PERFORMANCE_FILE",
//"AFL_PERSISTENT", // not implemented anymore, so warn additionally //"AFL_PERSISTENT", // not implemented anymore, so warn additionally
"AFL_POST_LIBRARY", "AFL_PRELOAD", "AFL_PYTHON_MODULE", "AFL_PYTHON_ONLY", "AFL_POST_LIBRARY", "AFL_PRELOAD", "AFL_PYTHON_MODULE",
"AFL_QEMU_COMPCOV", "AFL_QEMU_COMPCOV_DEBUG", "AFL_QEMU_DEBUG_MAPS", "AFL_QEMU_COMPCOV", "AFL_QEMU_COMPCOV_DEBUG", "AFL_QEMU_DEBUG_MAPS",
"AFL_QEMU_DISABLE_CACHE", "AFL_QEMU_PERSISTENT_ADDR", "AFL_QEMU_DISABLE_CACHE", "AFL_QEMU_PERSISTENT_ADDR",
"AFL_QEMU_PERSISTENT_CNT", "AFL_QEMU_PERSISTENT_GPR", "AFL_QEMU_PERSISTENT_CNT", "AFL_QEMU_PERSISTENT_GPR",

View File

@ -88,8 +88,7 @@ u8 cal_cycles = CAL_CYCLES, /* Calibration cycles defaults */
no_unlink, /* do not unlink cur_input */ no_unlink, /* do not unlink cur_input */
use_stdin = 1, /* use stdin for sending data */ use_stdin = 1, /* use stdin for sending data */
be_quiet, /* is AFL_QUIET set? */ be_quiet, /* is AFL_QUIET set? */
custom_only, /* Custom mutator only mode */ custom_only; /* Custom mutator only mode */
python_only; /* Python-only mode */
u32 stats_update_freq = 1; /* Stats update frequency (execs) */ u32 stats_update_freq = 1; /* Stats update frequency (execs) */

View File

@ -27,6 +27,7 @@
void setup_custom_mutator(void) { void setup_custom_mutator(void) {
/* Try mutator library first */
u8* fn = getenv("AFL_CUSTOM_MUTATOR_LIBRARY"); u8* fn = getenv("AFL_CUSTOM_MUTATOR_LIBRARY");
if (fn) { if (fn) {
@ -41,6 +42,7 @@ void setup_custom_mutator(void) {
return; return;
} }
/* Try Python module */
#ifdef USE_PYTHON #ifdef USE_PYTHON
u8* module_name = getenv("AFL_PYTHON_MODULE"); u8* module_name = getenv("AFL_PYTHON_MODULE");
@ -286,7 +288,7 @@ void load_custom_mutator_py(const char* module_name) {
/* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator /* "afl_custom_fuzz" should not be NULL, but the interface of Python mutator
is quite different from the custom mutator. */ is quite different from the custom mutator. */
mutator->afl_custom_fuzz = NULL; mutator->afl_custom_fuzz = fuzz_py;
if (py_functions[PY_FUNC_PRE_SAVE]) if (py_functions[PY_FUNC_PRE_SAVE])
mutator->afl_custom_pre_save = pre_save_py; mutator->afl_custom_pre_save = pre_save_py;

View File

@ -482,56 +482,6 @@ u8 fuzz_one_original(char** argv) {
if (use_radamsa > 1) goto radamsa_stage; if (use_radamsa > 1) goto radamsa_stage;
// custom_stage: // not used - yet
if (mutator->afl_custom_fuzz) {
stage_short = "custom";
stage_name = "custom mutator";
stage_max = len << 3;
stage_val_type = STAGE_VAL_NONE;
const u32 max_seed_size = 4096 * 4096;
u8* mutated_buf = ck_alloc(max_seed_size);
orig_hit_cnt = queued_paths + unique_crashes;
for (stage_cur = 0; stage_cur < stage_max; ++stage_cur) {
size_t orig_size = (size_t)len;
size_t mutated_size = mutator->afl_custom_fuzz(in_buf, orig_size,
mutated_buf, max_seed_size,
UR(UINT32_MAX));
if (mutated_size > 0) {
out_buf = ck_realloc(out_buf, mutated_size);
memcpy(out_buf, mutated_buf, mutated_size);
if (common_fuzz_stuff(argv, out_buf, (u32)mutated_size)) {
goto abandon_entry;
}
}
}
ck_free(mutated_buf);
new_hit_cnt = queued_paths + unique_crashes;
stage_finds[STAGE_CUSTOM_MUTATOR] += new_hit_cnt - orig_hit_cnt;
stage_cycles[STAGE_CUSTOM_MUTATOR] += stage_max;
if (custom_only) {
/* Skip other stages */
ret_val = 0;
goto abandon_entry;
}
}
if (cmplog_mode) { if (cmplog_mode) {
if (input_to_state_stage(argv, in_buf, out_buf, len, queue_cur->exec_cksum)) if (input_to_state_stage(argv, in_buf, out_buf, len, queue_cur->exec_cksum))
@ -551,11 +501,7 @@ u8 fuzz_one_original(char** argv) {
: havoc_max_mult * 100)) || : havoc_max_mult * 100)) ||
queue_cur->passed_det) { queue_cur->passed_det) {
#ifdef USE_PYTHON goto custom_mutator_stage;
goto python_stage;
#else
goto havoc_stage;
#endif
} }
@ -564,11 +510,7 @@ u8 fuzz_one_original(char** argv) {
if (master_max && (queue_cur->exec_cksum % master_max) != master_id - 1) { if (master_max && (queue_cur->exec_cksum % master_max) != master_id - 1) {
#ifdef USE_PYTHON goto custom_mutator_stage;
goto python_stage;
#else
goto havoc_stage;
#endif
} }
@ -1583,24 +1525,25 @@ skip_extras:
if (!queue_cur->passed_det) mark_as_det_done(queue_cur); if (!queue_cur->passed_det) mark_as_det_done(queue_cur);
#ifdef USE_PYTHON custom_mutator_stage:
python_stage: /*******************
/********************************** * CUSTOM MUTATORS *
* EXTERNAL MUTATORS (Python API) * *******************/
**********************************/
if (!py_module) goto havoc_stage; if (!mutator) goto havoc_stage;
if (!mutator->afl_custom_fuzz) goto havoc_stage;
stage_name = "python"; stage_name = "custom mutator";
stage_short = "python"; stage_short = "custom";
stage_max = HAVOC_CYCLES * perf_score / havoc_div / 100; stage_max = HAVOC_CYCLES * perf_score / havoc_div / 100;
stage_val_type = STAGE_VAL_NONE;
if (stage_max < HAVOC_MIN) stage_max = HAVOC_MIN; if (stage_max < HAVOC_MIN) stage_max = HAVOC_MIN;
orig_hit_cnt = queued_paths + unique_crashes; const u32 max_seed_size = 4096 * 4096;
u8* mutated_buf = ck_alloc(max_seed_size);
char* retbuf = NULL; orig_hit_cnt = queued_paths + unique_crashes;
size_t retlen = 0;
for (stage_cur = 0; stage_cur < stage_max; ++stage_cur) { for (stage_cur = 0; stage_cur < stage_max; ++stage_cur) {
@ -1647,26 +1590,24 @@ python_stage:
ck_read(fd, new_buf, target->len, target->fname); ck_read(fd, new_buf, target->len, target->fname);
close(fd); close(fd);
fuzz_py_original(out_buf, len, new_buf, target->len, &retbuf, &retlen); size_t mutated_size = mutator->afl_custom_fuzz(out_buf, len,
new_buf, target->len,
mutated_buf, max_seed_size);
ck_free(new_buf); ck_free(new_buf);
if (retbuf) { if (mutated_size > 0) {
if (!retlen) goto abandon_entry; out_buf = ck_realloc(out_buf, mutated_size);
memcpy(out_buf, mutated_buf, mutated_size);
if (common_fuzz_stuff(argv, retbuf, retlen)) { if (common_fuzz_stuff(argv, out_buf, (u32)mutated_size)) {
free(retbuf); ck_free(mutated_buf);
goto abandon_entry; goto abandon_entry;
} }
/* Reset retbuf/retlen */
free(retbuf);
retbuf = NULL;
retlen = 0;
/* If we're finding new stuff, let's run for a bit longer, limits /* If we're finding new stuff, let's run for a bit longer, limits
permitting. */ permitting. */
@ -1687,12 +1628,13 @@ python_stage:
} }
ck_free(mutated_buf);
new_hit_cnt = queued_paths + unique_crashes; new_hit_cnt = queued_paths + unique_crashes;
stage_finds[STAGE_PYTHON] += new_hit_cnt - orig_hit_cnt; stage_finds[STAGE_CUSTOM_MUTATOR] += new_hit_cnt - orig_hit_cnt;
stage_cycles[STAGE_PYTHON] += stage_max; stage_cycles[STAGE_CUSTOM_MUTATOR] += stage_max;
if (python_only) { if (custom_only) {
/* Skip other stages */ /* Skip other stages */
ret_val = 0; ret_val = 0;
@ -1700,8 +1642,6 @@ python_stage:
} }
#endif
/**************** /****************
* RANDOM HAVOC * * RANDOM HAVOC *
****************/ ****************/
@ -2270,11 +2210,10 @@ retry_splicing:
out_buf = ck_alloc_nozero(len); out_buf = ck_alloc_nozero(len);
memcpy(out_buf, in_buf, len); memcpy(out_buf, in_buf, len);
#ifdef USE_PYTHON goto custom_mutator_stage;
goto python_stage; /* ???: While integrating Python module, the author decided to jump to
#else python stage, but the reason behind this is not clear.*/
goto havoc_stage; // goto havoc_stage;
#endif
} }

View File

@ -159,67 +159,16 @@ void init_py(unsigned int seed) {
} }
} }
void fuzz_py_original(char* buf, size_t buflen, size_t fuzz_py(u8* buf, size_t buf_size,
char* add_buf, size_t add_buflen, u8* add_buf, size_t add_buf_size,
char** ret, size_t* retlen) { u8* mutated_out, size_t max_size) {
if (py_module != NULL) { size_t mutated_size;
PyObject *py_args, *py_value;
py_args = PyTuple_New(2);
py_value = PyByteArray_FromStringAndSize(buf, buflen);
if (!py_value) {
Py_DECREF(py_args);
fprintf(stderr, "Cannot convert argument\n");
return;
}
PyTuple_SetItem(py_args, 0, py_value);
py_value = PyByteArray_FromStringAndSize(add_buf, add_buflen);
if (!py_value) {
Py_DECREF(py_args);
fprintf(stderr, "Cannot convert argument\n");
return;
}
PyTuple_SetItem(py_args, 1, py_value);
py_value = PyObject_CallObject(py_functions[PY_FUNC_FUZZ], py_args);
Py_DECREF(py_args);
if (py_value != NULL) {
*retlen = PyByteArray_Size(py_value);
*ret = malloc(*retlen);
memcpy(*ret, PyByteArray_AsString(py_value), *retlen);
Py_DECREF(py_value);
} else {
PyErr_Print();
fprintf(stderr, "Call failed\n");
return;
}
}
}
size_t fuzz_py(u8* data, size_t size, u8* mutated_out, size_t max_size,
unsigned int seed) {
size_t out_size;
PyObject *py_args, *py_value; PyObject *py_args, *py_value;
py_args = PyTuple_New(3); py_args = PyTuple_New(3);
py_value = PyByteArray_FromStringAndSize(data, size); /* buf */
py_value = PyByteArray_FromStringAndSize(buf, buf_size);
if (!py_value) { if (!py_value) {
Py_DECREF(py_args); Py_DECREF(py_args);
@ -229,11 +178,8 @@ size_t fuzz_py(u8* data, size_t size, u8* mutated_out, size_t max_size,
PyTuple_SetItem(py_args, 0, py_value); PyTuple_SetItem(py_args, 0, py_value);
#if PY_MAJOR_VERSION >= 3 /* add_buf */
py_value = PyLong_FromLong(max_size); py_value = PyByteArray_FromStringAndSize(add_buf, add_buf_size);
#else
py_value = PyInt_FromLong(max_size);
#endif
if (!py_value) { if (!py_value) {
Py_DECREF(py_args); Py_DECREF(py_args);
@ -243,10 +189,11 @@ size_t fuzz_py(u8* data, size_t size, u8* mutated_out, size_t max_size,
PyTuple_SetItem(py_args, 1, py_value); PyTuple_SetItem(py_args, 1, py_value);
/* max_size */
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
py_value = PyLong_FromLong(seed); py_value = PyLong_FromLong(max_size);
#else #else
py_value = PyInt_FromLong(seed); py_value = PyInt_FromLong(max_size);
#endif #endif
if (!py_value) { if (!py_value) {
@ -263,11 +210,10 @@ size_t fuzz_py(u8* data, size_t size, u8* mutated_out, size_t max_size,
if (py_value != NULL) { if (py_value != NULL) {
out_size = PyByteArray_Size(py_value); mutated_size = PyByteArray_Size(py_value);
memcpy(mutated_out, PyByteArray_AsString(py_value), out_size); memcpy(mutated_out, PyByteArray_AsString(py_value), mutated_size);
Py_DECREF(py_value); Py_DECREF(py_value);
return mutated_size;
return out_size;
} else { } else {
@ -278,12 +224,12 @@ size_t fuzz_py(u8* data, size_t size, u8* mutated_out, size_t max_size,
} }
size_t pre_save_py(u8* data, size_t size, u8** new_data) { size_t pre_save_py(u8* buf, size_t buf_size, u8** out_buf) {
size_t new_size; size_t out_buf_size;
PyObject *py_args, *py_value; PyObject *py_args, *py_value;
py_args = PyTuple_New(2); py_args = PyTuple_New(2);
py_value = PyByteArray_FromStringAndSize(data, size); py_value = PyByteArray_FromStringAndSize(buf, buf_size);
if (!py_value) { if (!py_value) {
Py_DECREF(py_args); Py_DECREF(py_args);
@ -299,11 +245,11 @@ size_t pre_save_py(u8* data, size_t size, u8** new_data) {
if (py_value != NULL) { if (py_value != NULL) {
new_size = PyByteArray_Size(py_value); out_buf_size = PyByteArray_Size(py_value);
*new_data = malloc(new_size); *out_buf = malloc(out_buf_size);
memcpy(*new_data, PyByteArray_AsString(py_value), new_size); memcpy(*out_buf, PyByteArray_AsString(py_value), out_buf_size);
Py_DECREF(py_value); Py_DECREF(py_value);
return new_size; return out_buf_size;
} else { } else {
@ -314,12 +260,12 @@ size_t pre_save_py(u8* data, size_t size, u8** new_data) {
} }
u32 init_trim_py(u8* buf, size_t buflen) { u32 init_trim_py(u8* buf, size_t buf_size) {
PyObject *py_args, *py_value; PyObject *py_args, *py_value;
py_args = PyTuple_New(1); py_args = PyTuple_New(1);
py_value = PyByteArray_FromStringAndSize(buf, buflen); py_value = PyByteArray_FromStringAndSize(buf, buf_size);
if (!py_value) { if (!py_value) {
Py_DECREF(py_args); Py_DECREF(py_args);
@ -389,7 +335,7 @@ u32 post_trim_py(u8 success) {
} }
void trim_py(u8** ret, size_t* retlen) { void trim_py(u8** out_buf, size_t* out_buf_size) {
PyObject *py_args, *py_value; PyObject *py_args, *py_value;
@ -399,9 +345,9 @@ void trim_py(u8** ret, size_t* retlen) {
if (py_value != NULL) { if (py_value != NULL) {
*retlen = PyByteArray_Size(py_value); *out_buf_size = PyByteArray_Size(py_value);
*ret = malloc(*retlen); *out_buf = malloc(*out_buf_size);
memcpy(*ret, PyByteArray_AsString(py_value), *retlen); memcpy(*out_buf, PyByteArray_AsString(py_value), *out_buf_size);
Py_DECREF(py_value); Py_DECREF(py_value);
} else { } else {

View File

@ -309,11 +309,12 @@ void write_to_testcase(void* mem, u32 len) {
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
if (mutator->afl_custom_pre_save) { if (mutator && mutator->afl_custom_pre_save) {
u8* new_data; u8* new_data;
size_t new_size = mutator->afl_custom_pre_save(mem, len, &new_data); size_t new_size = mutator->afl_custom_pre_save(mem, len, &new_data);
ck_write(fd, new_data, new_size, out_file); ck_write(fd, new_data, new_size, out_file);
ck_free(new_data);
} else { } else {

View File

@ -158,7 +158,6 @@ static void usage(u8* argv0, int more_help) {
"AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n" "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n"
"AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n" "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n"
"AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n" "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
"AFL_PYTHON_ONLY: skip AFL++'s own mutators\n"
"AFL_DEBUG: extra debugging output for Python mode trimming\n" "AFL_DEBUG: extra debugging output for Python mode trimming\n"
"AFL_DISABLE_TRIM: disable the trimming of test cases\n" "AFL_DISABLE_TRIM: disable the trimming of test cases\n"
"AFL_NO_UI: switch status screen off\n" "AFL_NO_UI: switch status screen off\n"
@ -658,11 +657,10 @@ int main(int argc, char** argv, char** envp) {
OKF("afl-tmin fork server patch from github.com/nccgroup/TriforceAFL"); OKF("afl-tmin fork server patch from github.com/nccgroup/TriforceAFL");
OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL"); OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL");
if (sync_id && force_deterministic && if (sync_id && force_deterministic && getenv("AFL_CUSTOM_MUTATOR_ONLY"))
(getenv("AFL_CUSTOM_MUTATOR_ONLY") || getenv("AFL_PYTHON_ONLY")))
WARNF( WARNF(
"Using -M master with the AFL_..._ONLY mutator options will result in " "Using -M master with the AFL_CUSTOM_MUTATOR_ONLY mutator options will "
"no deterministic mutations being done!"); "result in no deterministic mutations being done!");
check_environment_vars(envp); check_environment_vars(envp);
@ -832,16 +830,6 @@ int main(int argc, char** argv, char** envp) {
if (get_afl_env("AFL_DEBUG")) debug = 1; if (get_afl_env("AFL_DEBUG")) debug = 1;
if (get_afl_env("AFL_PYTHON_ONLY")) {
/* This ensures we don't proceed to havoc/splice */
python_only = 1;
/* Ensure we also skip all deterministic steps */
skip_deterministic = 1;
}
if (get_afl_env("AFL_CUSTOM_MUTATOR_ONLY")) { if (get_afl_env("AFL_CUSTOM_MUTATOR_ONLY")) {
/* This ensures we don't proceed to havoc/splice */ /* This ensures we don't proceed to havoc/splice */