about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--instrumentation/afl-compiler-rt.o.c78
-rw-r--r--instrumentation/split-compares-pass.so.cc102
-rw-r--r--qemu_mode/README.deferred_initialization_example.md201
-rw-r--r--qemu_mode/README.md2
-rw-r--r--src/afl-fuzz-one.c4
-rw-r--r--src/afl-fuzz.c57
-rw-r--r--src/afl-gotcpu.c8
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);
 
       }