diff --git a/compiler-rt/lib/fuzzer/FuzzerMutate.cpp b/compiler-rt/lib/fuzzer/FuzzerMutate.cpp --- a/compiler-rt/lib/fuzzer/FuzzerMutate.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerMutate.cpp @@ -379,6 +379,76 @@ return Size; } +// The following magic constants were borrowed from AFL. + +#define INTERESTING_8 \ + -128, /* Overflow signed 8-bit when decremented */ \ + -1, /* */ \ + 0, /* */ \ + 1, /* */ \ + 16, /* One-off with common buffer size */ \ + 32, /* One-off with common buffer size */ \ + 64, /* One-off with common buffer size */ \ + 100, /* One-off with common buffer size */ \ + 127 /* Overflow signed 8-bit when incremented */ + +#define INTERESTING_16 \ + -32768, /* Overflow signed 16-bit when decremented */ \ + -129, /* Overflow signed 8-bit */ \ + 128, /* Overflow signed 8-bit */ \ + 255, /* Overflow unsig 8-bit when incremented */ \ + 256, /* Overflow unsig 8-bit */ \ + 512, /* One-off with common buffer size */ \ + 1000, /* One-off with common buffer size */ \ + 1024, /* One-off with common buffer size */ \ + 4096, /* One-off with common buffer size */ \ + 32767 /* Overflow signed 16-bit when incremented */ + +#define INTERESTING_32 \ + -2147483648LL, /* Overflow signed 32-bit when decremented */ \ + -100663046, /* Large negative number (endian-agnostic) */ \ + -32769, /* Overflow signed 16-bit */ \ + 32768, /* Overflow signed 16-bit */ \ + 65535, /* Overflow unsig 16-bit when incremented */ \ + 65536, /* Overflow unsig 16 bit */ \ + 100663045, /* Large positive number (endian-agnostic) */ \ + 2147483647 /* Overflow signed 32-bit when incremented */ + +template static T GetRandomMagic(Random &Rand) { + static_assert(std::is_integral::value, "Invalid type for magic values"); + + T Val = 0; + switch (sizeof(T)) { + case 1: { + constexpr int8_t Magics[] = {INTERESTING_8}; + int8_t SignedVal = Magics[Rand(sizeof(Magics) / sizeof(int8_t))]; + Val = static_cast(SignedVal); + break; + } + case 2: { + constexpr int16_t Magics[] = {INTERESTING_8, INTERESTING_16}; + int16_t SignedVal = Magics[Rand(sizeof(Magics) / sizeof(int16_t))]; + Val = static_cast(SignedVal); + break; + } + case 4: { + constexpr int32_t Magics[] = {INTERESTING_8, INTERESTING_16, + INTERESTING_32}; + int32_t SignedVal = Magics[Rand(sizeof(Magics) / sizeof(int32_t))]; + Val = static_cast(SignedVal); + break; + } + case 8: { + constexpr int64_t Magics[] = {INTERESTING_8, INTERESTING_16, + INTERESTING_32}; + int64_t SignedVal = Magics[Rand(sizeof(Magics) / sizeof(int64_t))]; + Val = static_cast(SignedVal); + break; + } + } + return Val; +} + template size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) { if (Size < sizeof(T)) return 0; @@ -389,6 +459,11 @@ Val = Size; if (Rand.RandBool()) Val = Bswap(Val); + } else if (Rand.RandBool()) { + Val = GetRandomMagic(Rand); + if (Rand.RandBool()) { + Val = Bswap(Val); + } } else { memcpy(&Val, Data + Off, sizeof(Val)); T Add = Rand(21); diff --git a/compiler-rt/test/fuzzer/OverwriteBytesTest.cpp b/compiler-rt/test/fuzzer/OverwriteBytesTest.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/fuzzer/OverwriteBytesTest.cpp @@ -0,0 +1,81 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include +#include + +uint8_t SeedInput[] = { + 0xba, + 0xe3, + 0x92, + 0x7c, + 0x80, + 0x86, + 0x73, + 0x0f, + 0xf2, + 0x83, + 0x23, + 0x0f, + 0xf5, + 0x17, + 0x4c, + 0x08, + 0xf2, + 0x83, + 0x23, + 0x0f, + 0xd8, + 0x71, + 0x58, + 0x1c, + 0xb9, + 0x8d, + 0xf1, + 0x0e, + 0x80, + 0x86, + 0x73, + 0x0f, + 0xf0, + 0x83, + 0x23, + 0x0f, +}; + +#define MAGIC_BYTE_VALUE 0x1 +#define MAGIC_BYTE_OFFSET 0xf + +static volatile int *Nil = nullptr; + +#ifdef PRINT_SEED_INPUT + +int main(int argc, char **argv) { + fwrite(SeedInput, sizeof(SeedInput[0]), sizeof(SeedInput), stdout); + return 0; +} + +#else + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size != sizeof(SeedInput)) { + return 0; + } + + *(uint64_t *)(SeedInput + MAGIC_BYTE_OFFSET) = MAGIC_BYTE_VALUE; + + if (memmem(Data, Size, SeedInput, Size) == Data) { + *Nil = 42; // crash. + } + + return 0; +} + +#endif diff --git a/compiler-rt/test/fuzzer/overwrite-bytes.test b/compiler-rt/test/fuzzer/overwrite-bytes.test new file mode 100644 --- /dev/null +++ b/compiler-rt/test/fuzzer/overwrite-bytes.test @@ -0,0 +1,9 @@ +REQUIRES: linux, x86_64 +RUN: %cpp_compiler %S/OverwriteBytesTest.cpp -o %t-OverwriteBytesTest +RUN: %cpp_compiler -fno-sanitize=fuzzer -DPRINT_SEED_INPUT=1 %S/OverwriteBytesTest.cpp -o %t-OverwriteBytesTestPrintSeed +RUN: %t-OverwriteBytesTestPrintSeed > %t-OverwriteBytesTest.seed + +RUN: not %run %t-OverwriteBytesTest -seed=1 -use_memmem=0 -mutate_depth=1 -reduce_inputs=0 -runs=10000000 -seed_inputs=%t-OverwriteBytesTest.seed 2>&1 | FileCheck %s + +CHECK: ABORTING +CHECK-NEXT: MS: 1 ChangeBinInt-;