diff options
-rw-r--r-- | instrumentation/afl-compiler-rt.o.c | 78 | ||||
-rw-r--r-- | instrumentation/split-compares-pass.so.cc | 102 | ||||
-rw-r--r-- | qemu_mode/README.deferred_initialization_example.md | 201 | ||||
-rw-r--r-- | qemu_mode/README.md | 2 | ||||
-rw-r--r-- | src/afl-fuzz-one.c | 4 | ||||
-rw-r--r-- | src/afl-fuzz.c | 57 | ||||
-rw-r--r-- | src/afl-gotcpu.c | 8 |
7 files changed, 355 insertions, 97 deletions
diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index d6d6c38c..9871d7f4 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1518,9 +1518,13 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { _is_sancov = 1; - __afl_auto_first(); - __afl_auto_second(); - __afl_auto_early(); + if (!getenv("AFL_DUMP_MAP_SIZE")) { + + __afl_auto_first(); + __afl_auto_second(); + __afl_auto_early(); + + } if (__afl_debug) { @@ -1534,6 +1538,16 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { if (start == stop || *start) return; + x = getenv("AFL_INST_RATIO"); + if (x) { inst_ratio = (u32)atoi(x); } + + if (!inst_ratio || inst_ratio > 100) { + + fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n"); + abort(); + + } + // If a dlopen of an instrumented library happens after the forkserver then // we have a problem as we cannot increase the coverage map anymore. if (__afl_already_initialized_forkserver) { @@ -1554,74 +1568,34 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { while (start < stop) { - *(start++) = offset; + if (likely(inst_ratio == 100) || R(100) < inst_ratio) + *start = offset; + else + *start = 0; // write to map[0] if (unlikely(++offset >= __afl_final_loc)) { offset = 4; } } } - } - - x = getenv("AFL_INST_RATIO"); - if (x) { inst_ratio = (u32)atoi(x); } - - if (!inst_ratio || inst_ratio > 100) { - - fprintf(stderr, "[-] ERROR: Invalid AFL_INST_RATIO (must be 1-100).\n"); - abort(); - - } - - /* instrumented code is loaded *after* our forkserver is up. this is a - problem. We cannot prevent collisions then :( */ - /* - if (__afl_already_initialized_forkserver && - __afl_final_loc + 1 + stop - start > __afl_map_size) { - - if (__afl_debug) { - - fprintf(stderr, "Warning: new instrumented code after the forkserver!\n"); - - } - - __afl_final_loc = 2; - - if (1 + stop - start > __afl_map_size) { - - *(start++) = ++__afl_final_loc; - - while (start < stop) { - - if (R(100) < inst_ratio) - *start = ++__afl_final_loc % __afl_map_size; - else - *start = 4; - - start++; - - } - - return; - - } + return; // we are done for this special case } - */ - /* Make sure that the first element in the range is always set - we use that to avoid duplicate calls (which can happen as an artifact of the underlying implementation in LLVM). */ + if (__afl_final_loc < 3) __afl_final_loc = 3; // we skip the first 4 entries + *(start++) = ++__afl_final_loc; while (start < stop) { - if (R(100) < inst_ratio) + if (likely(inst_ratio == 100) || R(100) < inst_ratio) *start = ++__afl_final_loc; else - *start = 4; + *start = 0; // write to map[0] start++; diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index dd7b09a6..8a07610c 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -1152,10 +1152,14 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { b_op1 = SelectInst::Create(isMzero_op1, ConstantInt::get(intType, PlusZero), bpre_op1); #if LLVM_MAJOR >= 16 - isMzero_op0->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); - isMzero_op1->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); - b_op0->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); - b_op1->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); + isMzero_op0->insertInto(nonan_bb, + BasicBlock::iterator(nonan_bb->getTerminator())); + isMzero_op1->insertInto(nonan_bb, + BasicBlock::iterator(nonan_bb->getTerminator())); + b_op0->insertInto(nonan_bb, + BasicBlock::iterator(nonan_bb->getTerminator())); + b_op1->insertInto(nonan_bb, + BasicBlock::iterator(nonan_bb->getTerminator())); #else nonan_bb->getInstList().insert( BasicBlock::iterator(nonan_bb->getTerminator()), isMzero_op0); @@ -1192,7 +1196,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { t_s0->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); s_s1->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); t_s1->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); - icmp_sign_bit->insertInto(nonan_bb, BasicBlock::iterator(nonan_bb->getTerminator())); + icmp_sign_bit->insertInto(nonan_bb, + BasicBlock::iterator(nonan_bb->getTerminator())); #else nonan_bb->getInstList().insert( BasicBlock::iterator(nonan_bb->getTerminator()), s_s0); @@ -1239,8 +1244,10 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction::LShr, b_op1, ConstantInt::get(b_op1->getType(), shiftR_exponent)); #if LLVM_MAJOR >= 16 - s_e0->insertInto(signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); - s_e1->insertInto(signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); + s_e0->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); + s_e1->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); #else signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), s_e0); @@ -1251,15 +1258,16 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { t_e0 = new TruncInst(s_e0, IntExponentTy); t_e1 = new TruncInst(s_e1, IntExponentTy); #if LLVM_MAJOR >= 16 - t_e0->insertInto(signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); - t_e1->insertInto(signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); + t_e0->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); + t_e1->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); #else signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), t_e0); signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), t_e1); #endif - if (sizeInBits - precision < exTySizeBytes * 8) { @@ -1270,8 +1278,10 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction::And, t_e1, ConstantInt::get(t_e1->getType(), mask_exponent)); #if LLVM_MAJOR >= 16 - m_e0->insertInto(signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); - m_e1->insertInto(signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); + m_e0->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); + m_e1->insertInto(signequal_bb, + BasicBlock::iterator(signequal_bb->getTerminator())); #else signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), m_e0); @@ -1312,7 +1322,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_exponents_equal = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1); #if LLVM_MAJOR >= 16 - icmp_exponents_equal->insertInto(signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); + icmp_exponents_equal->insertInto( + signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); #else signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), @@ -1332,7 +1343,9 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_exponent = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, m_e0, m_e1); #if LLVM_MAJOR >= 16 - icmp_exponent->insertInto(signequal2_bb, BasicBlock::iterator(signequal2_bb->getTerminator())); + icmp_exponent->insertInto( + signequal2_bb, + BasicBlock::iterator(signequal2_bb->getTerminator())); #else signequal2_bb->getInstList().insert( BasicBlock::iterator(signequal2_bb->getTerminator()), @@ -1346,7 +1359,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_exponents_equal = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, m_e0, m_e1); #if LLVM_MAJOR >= 16 - icmp_exponents_equal->insertInto(signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); + icmp_exponents_equal->insertInto( + signequal_bb, BasicBlock::iterator(signequal_bb->getTerminator())); #else signequal_bb->getInstList().insert( BasicBlock::iterator(signequal_bb->getTerminator()), @@ -1366,7 +1380,9 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_exponent = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, m_e0, m_e1); #if LLVM_MAJOR >= 16 - icmp_exponent->insertInto(signequal2_bb, BasicBlock::iterator(signequal2_bb->getTerminator())); + icmp_exponent->insertInto( + signequal2_bb, + BasicBlock::iterator(signequal2_bb->getTerminator())); #else signequal2_bb->getInstList().insert( BasicBlock::iterator(signequal2_bb->getTerminator()), @@ -1381,7 +1397,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { } #if LLVM_MAJOR >= 16 - icmp_exponent_result->insertInto(signequal2_bb, BasicBlock::iterator(signequal2_bb->getTerminator())); + icmp_exponent_result->insertInto( + signequal2_bb, BasicBlock::iterator(signequal2_bb->getTerminator())); #else signequal2_bb->getInstList().insert( BasicBlock::iterator(signequal2_bb->getTerminator()), @@ -1437,8 +1454,10 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction::And, b_op1, ConstantInt::get(b_op1->getType(), mask_fraction)); #if LLVM_MAJOR >= 16 - m_f0->insertInto(middle_bb, BasicBlock::iterator(middle_bb->getTerminator())); - m_f1->insertInto(middle_bb, BasicBlock::iterator(middle_bb->getTerminator())); + m_f0->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); + m_f1->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); #else middle_bb->getInstList().insert( BasicBlock::iterator(middle_bb->getTerminator()), m_f0); @@ -1451,8 +1470,10 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { t_f0 = new TruncInst(m_f0, IntFractionTy); t_f1 = new TruncInst(m_f1, IntFractionTy); #if LLVM_MAJOR >= 16 - t_f0->insertInto(middle_bb, BasicBlock::iterator(middle_bb->getTerminator())); - t_f1->insertInto(middle_bb, BasicBlock::iterator(middle_bb->getTerminator())); + t_f0->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); + t_f1->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); #else middle_bb->getInstList().insert( BasicBlock::iterator(middle_bb->getTerminator()), t_f0); @@ -1474,8 +1495,10 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { t_f0 = new TruncInst(b_op0, IntFractionTy); t_f1 = new TruncInst(b_op1, IntFractionTy); #if LLVM_MAJOR >= 16 - t_f0->insertInto(middle_bb, BasicBlock::iterator(middle_bb->getTerminator())); - t_f1->insertInto(middle_bb, BasicBlock::iterator(middle_bb->getTerminator())); + t_f0->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); + t_f1->insertInto(middle_bb, + BasicBlock::iterator(middle_bb->getTerminator())); #else middle_bb->getInstList().insert( BasicBlock::iterator(middle_bb->getTerminator()), t_f0); @@ -1503,7 +1526,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_fraction_result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, t_f0, t_f1); #if LLVM_MAJOR >= 16 - icmp_fraction_result->insertInto(middle2_bb, BasicBlock::iterator(middle2_bb->getTerminator())); + icmp_fraction_result->insertInto( + middle2_bb, BasicBlock::iterator(middle2_bb->getTerminator())); #else middle2_bb->getInstList().insert( BasicBlock::iterator(middle2_bb->getTerminator()), @@ -1516,7 +1540,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_fraction_result = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_NE, t_f0, t_f1); #if LLVM_MAJOR >= 16 - icmp_fraction_result->insertInto(middle2_bb, BasicBlock::iterator(middle2_bb->getTerminator())); + icmp_fraction_result->insertInto( + middle2_bb, BasicBlock::iterator(middle2_bb->getTerminator())); #else middle2_bb->getInstList().insert( BasicBlock::iterator(middle2_bb->getTerminator()), @@ -1542,13 +1567,13 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { if (FcmpInst->getPredicate() == CmpInst::FCMP_OGT || FcmpInst->getPredicate() == CmpInst::FCMP_UGT) { - icmp_fraction_result = CmpInst::Create( - Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1); - icmp_fraction_result2 = CmpInst::Create( - Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1); + icmp_fraction_result = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1); + icmp_fraction_result2 = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1); #if LLVM_MAJOR >= 16 - icmp_fraction_result->insertInto(negative_bb, negative_bb->end()); - icmp_fraction_result2->insertInto(positive_bb, negative_bb->end()); + icmp_fraction_result->insertInto(negative_bb, negative_bb->end()); + icmp_fraction_result2->insertInto(positive_bb, negative_bb->end()); #else negative_bb->getInstList().push_back(icmp_fraction_result); positive_bb->getInstList().push_back(icmp_fraction_result2); @@ -1556,13 +1581,13 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { } else { - icmp_fraction_result = CmpInst::Create( - Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1); - icmp_fraction_result2 = CmpInst::Create( - Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1); + icmp_fraction_result = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1); + icmp_fraction_result2 = + CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1); #if LLVM_MAJOR >= 16 - icmp_fraction_result->insertInto(negative_bb, negative_bb->end()); - icmp_fraction_result2->insertInto(positive_bb, negative_bb->end()); + icmp_fraction_result->insertInto(negative_bb, negative_bb->end()); + icmp_fraction_result2->insertInto(positive_bb, negative_bb->end()); #else negative_bb->getInstList().push_back(icmp_fraction_result); positive_bb->getInstList().push_back(icmp_fraction_result2); @@ -1581,7 +1606,8 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { PN2->addIncoming(icmp_fraction_result, negative_bb); PN2->addIncoming(icmp_fraction_result2, positive_bb); #if LLVM_MAJOR >= 16 - PN2->insertInto(middle2_bb, BasicBlock::iterator(middle2_bb->getTerminator())); + PN2->insertInto(middle2_bb, + BasicBlock::iterator(middle2_bb->getTerminator())); #else middle2_bb->getInstList().insert( BasicBlock::iterator(middle2_bb->getTerminator()), PN2); diff --git a/qemu_mode/README.deferred_initialization_example.md b/qemu_mode/README.deferred_initialization_example.md new file mode 100644 index 00000000..d940d6b5 --- /dev/null +++ b/qemu_mode/README.deferred_initialization_example.md @@ -0,0 +1,201 @@ +# Fuzz ARM32 Python Native Extensions in Binary-only Mode (LLVM fork-based) + +This is an example on how to fuzz Python native extensions in LLVM mode with deferred initialization on ARM32. + +We use Ubuntu x86_64 to run AFL++ and an Alpine ARMv7 Chroot to build the fuzzing target. + +Check [Resources](#resources) for the code used in this example. + +## Setup Alpine ARM Chroot on your x86_64 Linux Host + +### Use systemd-nspawn + +1. Install `qemu-user-binfmt`, `qemu-user-static` and `systemd-container` dependencies. +2. Restart the systemd-binfmt service: `systemctl restart systemd-binfmt.service` +3. Download an Alpine ARM RootFS from https://alpinelinux.org/downloads/ +4. Create a new `alpine_sysroot` folder and extract: `tar xfz alpine-minirootfs-3.17.1-armv7.tar.gz -C alpine_sysroot/` +5. Copy `qemu-arm-static` to Alpine's RootFS: `cp $(which qemu-arm-static) ./alpine/usr/bin/` +6. Chroot into the container: `sudo systemd-nspawn -D alpine/ --bind-ro=/etc/resolv.conf` +7. Install dependencies: `apk update && apk add build-base musl-dev clang15 python3 python3-dev py3-pip` +8. Exit the container with `exit` + +### Alternatively use Docker + +1. Install `qemu-user-binfmt` and `qemu-user-static` +2. Run Qemu container: ```$ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes``` +3. Run Alpine container: ```$ docker run -it --rm arm32v7/alpine sh``` + +## Build AFL++ Qemu Mode with ARM Support + +First, build AFL++ as described [here](https://github.com/AFLplusplus/AFLplusplus/blob/dev/docs/INSTALL.md). Then, run the Qemu build script: + +```bash +cd qemu_mode && CPU_TARGET=arm ./build_qemu_support.sh +``` + +## Compile and Build the Fuzzing Project +Build the native extension and the fuzzing harness for ARM using the Alpine container (check [Resources](#resources) for the code): +```bash +ALPINE_ROOT=<your-alpine-sysroot-directory> +FUZZ=<your-path-to-the-code> +sudo systemd-nspawn -D $ALPINE_ROOT --bind=$FUZZ:/fuzz +CC=$(which clang) CFLAGS="-g" LDSHARED="clang -shared" python3 -m pip install /fuzz +clang $(python3-config --embed --cflags) $(python3-config --embed --ldflags) -o /fuzz/fuzz_harness /fuzz/fuzz_harness.c +exit +``` + +Manually trigger bug: +```bash +echo -n "FUZZ" | qemu-arm-static -L $ALPINE_ROOT $FUZZ/fuzz_harness +``` + +## Run AFL++ +Make sure to start the forkserver *after* loading all the shared objects by setting the `AFL_ENTRYPOINT` environment variable (see [here](https://aflplus.plus/docs/env_variables/#5-settings-for-afl-qemu-trace) for details): + +Choose an address just before the `while()` loop, for example: +```bash +qemu-arm-static -L $ALPINE_ROOT $ALPINE_ROOT/usr/bin/objdump -d $FUZZ/fuzz_harness | grep -A 1 "PyObject_GetAttrString" + +00000584 <PyObject_GetAttrString@plt>: + 584: e28fc600 add ip, pc, #0, 12 +-- + 7c8: ebffff6d bl 584 <PyObject_GetAttrString@plt> + 7cc: e58d0008 str r0, [sp, #8] +... +``` + +Check Qemu memory maps using the instructions from [here](https://aflplus.plus/docs/tutorials/libxml2_tutorial/): +>The binary is position independent and QEMU persistent needs the real addresses, not the offsets. Fortunately, QEMU loads PIE executables at a fixed address, 0x4000000000 for x86_64. +> +> We can check it using `AFL_QEMU_DEBUG_MAPS`. You don’t need this step if your binary is not PIE. + +Setup Python environment variables and run `afl-qemu-trace`: +```bash +PYTHONPATH=$ALPINE_ROOT/usr/lib/python3.10/ PYTHONHOME=$ALPINE_ROOT/usr/bin/ QEMU_LD_PREFIX=$ALPINE_ROOT AFL_QEMU_DEBUG_MAPS=1 afl-qemu-trace $FUZZ/fuzz_harness + +... +40000000-40001000 r-xp 00000000 103:03 8002276 fuzz_harness +40001000-4001f000 ---p 00000000 00:00 0 +4001f000-40020000 r--p 0000f000 103:03 8002276 fuzz_harness +40020000-40021000 rw-p 00010000 103:03 8002276 fuzz_harness +40021000-40022000 ---p 00000000 00:00 0 +40022000-40023000 rw-p 00000000 00:00 0 +``` + +Finally, setup Qemu environment variables... +```bash +export QEMU_SET_ENV=PYTHONPATH=$ALPINE_ROOT/usr/lib/python310.zip:$ALPINE_ROOT/usr/lib/python3.10:$ALPINE_ROOT/usr/lib/python3.10/lib-dynload:$ALPINE_ROOT/usr/lib/python3.10/site-packages,PYTHONHOME=$ALPINE_ROOT/usr/bin/ +export QEMU_LD_PREFIX=$ALPINE_ROOT +``` + +... and run AFL++: +```bash +mkdir -p $FUZZ/in && echo -n "FU" > $FUZZ/in/seed +AFL_ENTRYPOINT=0x400007cc afl-fuzz -i $FUZZ/in -o $FUZZ/out -Q -- $FUZZ/fuzz_harness +``` + +## Resources + +### setup.py + +```python +from distutils.core import setup, Extension + +module = Extension("memory", sources=["fuzz_target.c"]) + +setup( + name="memory", + version="1.0", + description='A simple "BOOM!" extension', + ext_modules=[module], +) +``` + +### fuzz_target.c + +```c +#define PY_SSIZE_T_CLEAN +#include <Python.h> + +#pragma clang optimize off + +static PyObject *corruption(PyObject* self, PyObject* args) { + char arr[3]; + Py_buffer name; + + if (!PyArg_ParseTuple(args, "y*", &name)) + return NULL; + + if (name.buf != NULL) { + if (strcmp(name.buf, "FUZZ") == 0) { + arr[0] = 'B'; + arr[1] = 'O'; + arr[2] = 'O'; + arr[3] = 'M'; + } + } + + PyBuffer_Release(&name); + Py_RETURN_NONE; +} + +static PyMethodDef MemoryMethods[] = { + {"corruption", corruption, METH_VARARGS, "BOOM!"}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef memory_module = { + PyModuleDef_HEAD_INIT, + "memory", + "BOOM!", + -1, + MemoryMethods +}; + +PyMODINIT_FUNC PyInit_memory(void) { + return PyModule_Create(&memory_module); +} +``` + +### fuzz_harness.c + +```c +#include <Python.h> + +#pragma clang optimize off + +int main(int argc, char **argv) { + unsigned char buf[1024000]; + ssize_t size; + + Py_Initialize(); + PyObject* name = PyUnicode_DecodeFSDefault("memory"); + PyObject* module = PyImport_Import(name); + Py_DECREF(name); + + if (module != NULL) { + PyObject* corruption_func = PyObject_GetAttrString(module, "corruption"); + + while ((size = read(0, buf, sizeof(buf))) > 0 ? 1 : 0) { + PyObject* arg = PyBytes_FromStringAndSize((char *)buf, size); + + if (arg != NULL) { + PyObject* res = PyObject_CallFunctionObjArgs(corruption_func, arg, NULL); + + if (res != NULL) { + Py_XDECREF(res); + } + + Py_DECREF(arg); + } + } + + Py_DECREF(corruption_func); + Py_DECREF(module); + } + + // Py_Finalize() leaks memory on certain Python versions (see https://bugs.python.org/issue1635741) + // Py_Finalize(); + return 0; +} +``` diff --git a/qemu_mode/README.md b/qemu_mode/README.md index 4ed2f298..92038737 100644 --- a/qemu_mode/README.md +++ b/qemu_mode/README.md @@ -66,6 +66,8 @@ allows to move the forkserver to a different part, e.g., just before the file is opened (e.g., way after command line parsing and config file loading, etc.) which can be a huge speed improvement. +For an example, see [README.deferred_initialization_example.md](README.deferred_initialization_example.md). + ## 4) Persistent mode AFL++'s QEMU mode now supports also persistent mode for x86, x86_64, arm, and diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 97855607..6367f597 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -5798,7 +5798,7 @@ void pso_updating(afl_state_t *afl) { u8 fuzz_one(afl_state_t *afl) { - int key_val_lv_1 = 0, key_val_lv_2 = 0; + int key_val_lv_1 = -1, key_val_lv_2 = -1; #ifdef _AFL_DOCUMENT_MUTATIONS @@ -5840,7 +5840,7 @@ u8 fuzz_one(afl_state_t *afl) { } - return (key_val_lv_1 | key_val_lv_2); + return (key_val_lv_1 == 0 || key_val_lv_2 == 0 ? 0 : 1 ); } diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index b8114a7f..8c2eb5b7 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -2210,8 +2210,8 @@ int main(int argc, char **argv_orig, char **envp) { cull_queue(afl); // ensure we have at least one seed that is not disabled. - u32 entry, valid_seeds = 0; - for (entry = 0; entry < afl->queued_items; ++entry) + u32 valid_seeds = 0; + for (u32 entry = 0; entry < afl->queued_items; ++entry) if (!afl->queue_buf[entry]->disabled) { ++valid_seeds; } if (!afl->pending_not_fuzzed || !valid_seeds) { @@ -2241,7 +2241,7 @@ int main(int argc, char **argv_orig, char **envp) { u64 max_ms = 0; - for (entry = 0; entry < afl->queued_items; ++entry) + for (u32 entry = 0; entry < afl->queued_items; ++entry) if (!afl->queue_buf[entry]->disabled) if (afl->queue_buf[entry]->exec_us > max_ms) max_ms = afl->queue_buf[entry]->exec_us; @@ -2285,7 +2285,7 @@ int main(int argc, char **argv_orig, char **envp) { #ifdef INTROSPECTION u32 prev_saved_crashes = 0, prev_saved_tmouts = 0; #endif - u32 prev_queued_items = 0, runs_in_current_cycle = (u32)-1; + u32 skip_count = 0, prev_queued_items = 0, runs_in_current_cycle = (u32)-1; u8 skipped_fuzz; #ifdef INTROSPECTION @@ -2547,8 +2547,57 @@ int main(int argc, char **argv_orig, char **envp) { } skipped_fuzz = fuzz_one(afl); + + if (unlikely(skipped_fuzz)) { + + ++skip_count; + + if (unlikely(skip_count > afl->active_items)) { + + if (afl->active_items > 1 && !afl->old_seed_selection) { + + u32 found = 0; + for (u32 i = 0; i < afl->queued_items; ++i) { + + if (likely(!afl->queue_buf[i]->disabled && + afl->queue_buf[i]->perf_score == 0)) { + + ++found; + + } + + } + + if (found >= afl->active_items) { + + // all active items have a perf_score of 0 ... damn + for (u32 i = 0; i < afl->queued_items; ++i) { + + if (likely(!afl->queue_buf[i]->disabled)) { + + afl->queue_buf[i]->perf_score = afl->queue_buf[i]->weight; + + } + + } + + } + + } + + skip_count = 0; + + } + + } else { + + skip_count = 0; + + } + #ifdef INTROSPECTION ++afl->queue_cur->stats_selected; + if (unlikely(skipped_fuzz)) { ++afl->queue_cur->stats_skipped; diff --git a/src/afl-gotcpu.c b/src/afl-gotcpu.c index c5b8a27a..fd9e9f54 100644 --- a/src/afl-gotcpu.c +++ b/src/afl-gotcpu.c @@ -214,7 +214,13 @@ int main(int argc, char **argv) { #if defined(__linux__) if (sched_setaffinity(0, sizeof(c), &c)) { - PFATAL("sched_setaffinity failed for cpu %d", i); + const char *error_code = "Unkown error code"; + if (errno == EFAULT) error_code = "EFAULT"; + if (errno == EINVAL) error_code = "EINVAL"; + if (errno == EPERM) error_code = "EPERM"; + if (errno == ESRCH) error_code = "ESRCH"; + + PFATAL("sched_setaffinity failed for cpu %d, error: %s", i, error_code); } |