diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 45662ff5bf..d82e70694d 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -14,8 +14,7 @@ env: AFL_PIZZA_MODE: "-1" # this is sad, I know, but it breaks on a certain spring day otherwise :( CARGO_TERM_COLOR: always CARGO_NET_GIT_FETCH_WITH_CLI: true - # FIXME: please unpin macos rust stable toolchain once LLVM is bumped to version 22 - MAIN_LLVM_VERSION: 21 + MAIN_LLVM_VERSION: 22 RUST_BACKTRACE: full concurrency: @@ -994,7 +993,7 @@ jobs: macos: runs-on: macOS-latest steps: - - uses: dtolnay/rust-toolchain@1.94.1 + - uses: dtolnay/rust-toolchain@stable with: components: clippy - name: Fix PATH for Cargo diff --git a/crates/libafl_cc/src/autotokens-pass.cc b/crates/libafl_cc/src/autotokens-pass.cc index a343531a42..eb9cd47110 100644 --- a/crates/libafl_cc/src/autotokens-pass.cc +++ b/crates/libafl_cc/src/autotokens-pass.cc @@ -299,13 +299,11 @@ PreservedAnalyses AutoTokensPass::run(Module &M, ModuleAnalysisManager &MAM) { isStrcmp &= FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) && FT->getParamType(0) == FT->getParamType(1) && - FT->getParamType(0) == - IntegerType::getInt8Ty(M.getContext())->getPointerTo(0); + FT->getParamType(0) == PointerType::get(M.getContext(), 0); isStrcasecmp &= FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) && FT->getParamType(0) == FT->getParamType(1) && - FT->getParamType(0) == - IntegerType::getInt8Ty(M.getContext())->getPointerTo(0); + FT->getParamType(0) == PointerType::get(M.getContext(), 0); isMemcmp &= FT->getNumParams() == 3 && FT->getReturnType()->isIntegerTy(32) && FT->getParamType(0)->isPointerTy() && @@ -314,14 +312,12 @@ PreservedAnalyses AutoTokensPass::run(Module &M, ModuleAnalysisManager &MAM) { isStrncmp &= FT->getNumParams() == 3 && FT->getReturnType()->isIntegerTy(32) && FT->getParamType(0) == FT->getParamType(1) && - FT->getParamType(0) == - IntegerType::getInt8Ty(M.getContext())->getPointerTo(0) && + FT->getParamType(0) == PointerType::get(M.getContext(), 0) && FT->getParamType(2)->isIntegerTy(); isStrncasecmp &= FT->getNumParams() == 3 && FT->getReturnType()->isIntegerTy(32) && FT->getParamType(0) == FT->getParamType(1) && - FT->getParamType(0) == - IntegerType::getInt8Ty(M.getContext())->getPointerTo(0) && + FT->getParamType(0) == PointerType::get(M.getContext(), 0) && FT->getParamType(2)->isIntegerTy(); isStdString &= FT->getNumParams() >= 2 && FT->getParamType(0)->isPointerTy() && diff --git a/crates/libafl_cc/src/cmplog-instructions-pass.cc b/crates/libafl_cc/src/cmplog-instructions-pass.cc index a4a0fe42b9..d27d8570cc 100644 --- a/crates/libafl_cc/src/cmplog-instructions-pass.cc +++ b/crates/libafl_cc/src/cmplog-instructions-pass.cc @@ -158,7 +158,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) { } #endif - Constant *Null = Constant::getNullValue(PointerType::get(Int8Ty, 0)); + Constant *Null = Constant::getNullValue(PointerType::get(M.getContext(), 0)); /* iterate over all functions, bbs and instruction and add suitable calls */ for (auto &F : M) { diff --git a/crates/libafl_cc/src/cmplog-routines-pass.cc b/crates/libafl_cc/src/cmplog-routines-pass.cc index 52b67b932e..baf55c7d4b 100644 --- a/crates/libafl_cc/src/cmplog-routines-pass.cc +++ b/crates/libafl_cc/src/cmplog-routines-pass.cc @@ -75,7 +75,7 @@ bool CmpLogRoutines::hookRtns(Module &M) { IntegerType *Int8Ty = IntegerType::getInt8Ty(C); IntegerType *Int64Ty = IntegerType::getInt64Ty(C); IntegerType *Int32Ty = IntegerType::getInt32Ty(C); - PointerType *i8PtrTy = PointerType::get(Int8Ty, 0); + PointerType *i8PtrTy = PointerType::get(M.getContext(), 0); FunctionCallee cmplogHookFn; FunctionCallee cmplogLlvmStdStd; @@ -229,8 +229,7 @@ bool CmpLogRoutines::hookRtns(Module &M) { isStrcmp &= FT->getNumParams() == 2 && FT->getReturnType()->isIntegerTy(32) && FT->getParamType(0) == FT->getParamType(1) && - FT->getParamType(0) == - IntegerType::getInt8Ty(M.getContext())->getPointerTo(0); + FT->getParamType(0) == PointerType::get(M.getContext(), 0); bool isStrncmp = (!FuncName.compare("strncmp") || !FuncName.compare("xmlStrncmp") || @@ -246,8 +245,7 @@ bool CmpLogRoutines::hookRtns(Module &M) { isStrncmp &= FT->getNumParams() == 3 && FT->getReturnType()->isIntegerTy(32) && FT->getParamType(0) == FT->getParamType(1) && - FT->getParamType(0) == - IntegerType::getInt8Ty(M.getContext())->getPointerTo(0) && + FT->getParamType(0) == PointerType::get(M.getContext(), 0) && FT->getParamType(2)->isIntegerTy(); bool isGccStdStringStdString = diff --git a/crates/libafl_cc/src/common-llvm.h b/crates/libafl_cc/src/common-llvm.h index 97229d9df9..fc22ac1e6f 100644 --- a/crates/libafl_cc/src/common-llvm.h +++ b/crates/libafl_cc/src/common-llvm.h @@ -10,11 +10,6 @@ #define HAVE_VECTOR_INTRINSICS 1 #include -#if LLVM_VERSION_MAJOR >= 16 -// None constant being deprecated for LLVM-16, it is recommended -// to use the std::nullopt_t type instead. (#1010) -constexpr std::nullopt_t None = std::nullopt; -#endif // all llvm includes and friends #include "llvm/Support/CommandLine.h" @@ -25,10 +20,31 @@ constexpr std::nullopt_t None = std::nullopt; #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Verifier.h" #include "llvm/IR/CFG.h" -#include "llvm/Passes/PassPlugin.h" +#if LLVM_VERSION_MAJOR >= 22 + #include "llvm/Plugins/PassPlugin.h" +#else + #include "llvm/Passes/PassPlugin.h" +#endif #include "llvm/Passes/PassBuilder.h" #include "llvm/IR/PassManager.h" +#if LLVM_VERSION_MAJOR >= 21 + // None is only used in libafl_cc as the second parameter of MDNode::get() + // that param is an ArrayRef, which can no longer be constructed with a + // nullopt since LLVM 21+ + // + // Keep these around to keep IWYU quiet + #include "llvm/ADT/ArrayRef.h" +namespace llvm { +class Metadata; +} +inline constexpr llvm::ArrayRef None{}; +#elif LLVM_VERSION_MAJOR >= 16 +// None constant being deprecated for LLVM-16, it is recommended +// to use the std::nullopt_t type instead. (#1010) +constexpr std::nullopt_t None = std::nullopt; +#endif + #define FATAL(...) \ do { \ fprintf(stderr, "FATAL: " __VA_ARGS__); \ diff --git a/crates/libafl_cc/src/coverage-accounting-pass.cc b/crates/libafl_cc/src/coverage-accounting-pass.cc index 6dfa1b459d..f0786acbe6 100644 --- a/crates/libafl_cc/src/coverage-accounting-pass.cc +++ b/crates/libafl_cc/src/coverage-accounting-pass.cc @@ -232,8 +232,8 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) { __afl_acc_prev_loc is thread-local. */ GlobalVariable *AFLMemOpPtr = new GlobalVariable( - M, PointerType::get(Int32Ty, 0), false, GlobalValue::ExternalLinkage, 0, - "__afl_acc_memop_ptr"); + M, PointerType::get(M.getContext(), 0), false, + GlobalValue::ExternalLinkage, 0, "__afl_acc_memop_ptr"); GlobalVariable *AFLPrevLoc; @@ -301,7 +301,7 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) { /* Load SHM pointer */ LoadInst *MemReadPtr = - IRB.CreateLoad(PointerType::get(Int32Ty, 0), AFLMemOpPtr); + IRB.CreateLoad(PointerType::get(M.getContext(), 0), AFLMemOpPtr); MemReadPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); Value *MemReadPtrIdx = diff --git a/crates/libafl_cc/src/dump-cfg-pass.cc b/crates/libafl_cc/src/dump-cfg-pass.cc index 9903515ef5..815b166f59 100644 --- a/crates/libafl_cc/src/dump-cfg-pass.cc +++ b/crates/libafl_cc/src/dump-cfg-pass.cc @@ -38,13 +38,6 @@ #include -#define FATAL(x...) \ - do { \ - fprintf(stderr, "FATAL: " x); \ - exit(1); \ - \ - } while (0) - using namespace llvm; namespace { diff --git a/crates/libafl_cc/src/function-logging.cc b/crates/libafl_cc/src/function-logging.cc index 28da42cbe5..b51b30e83a 100644 --- a/crates/libafl_cc/src/function-logging.cc +++ b/crates/libafl_cc/src/function-logging.cc @@ -38,7 +38,11 @@ #include "llvm/ADT/Statistic.h" #include "llvm/IR/IRBuilder.h" -#include "llvm/Passes/PassPlugin.h" +#if LLVM_VERSION_MAJOR >= 22 + #include "llvm/Plugins/PassPlugin.h" +#else + #include "llvm/Passes/PassPlugin.h" +#endif #include "llvm/Passes/PassBuilder.h" #include "llvm/IR/PassManager.h" diff --git a/fuzzers/forkserver/forkserver_libafl_cc/Justfile b/fuzzers/forkserver/forkserver_libafl_cc/Justfile index 3567df1e64..cd577695e8 100644 --- a/fuzzers/forkserver/forkserver_libafl_cc/Justfile +++ b/fuzzers/forkserver/forkserver_libafl_cc/Justfile @@ -56,14 +56,25 @@ run: fuzzer [macos] test: fuzzer #!/bin/bash - timeout 30s {{ FORKSERVER }} ./{{ FUZZER_NAME }} ./corpus/ -t 1000 | tee fuzz_stdout.log || true - if grep -qa "objectives: 1" fuzz_stdout.log; then - echo "Fuzzer is working" + CRASH_DIR="crashes" + QUEUE_DIR="corpus_discovered" + timeout 30s {{ FORKSERVER }} -G 10 -t 5000 ./{{ FUZZER_NAME }} ./corpus/ || true + + # Print off the crashes/queue for testing before we delete, but don't fail the job + find "${CRASH_DIR}" "${QUEUE_DIR}" -type f -name '[0-9a-f]*' -print -exec od -A x -t x1 -c {} \; 2>/dev/null || true + + if find "${CRASH_DIR}" -type f -name '[0-9a-f]*' -printf '.' 2>/dev/null | grep -q .; then + echo "Good, Fuzzer found a crash" else - echo "Fuzzer does not generate any testcases or any crashes" + echo "Fuzzer did not find a crashing input, and should have" exit 1 fi + # Cleanup the crashes/queue dirs so that subsequent tests don't pick up + # previous crashes/findings. + # already exited if failed, keep around to debug + rm -r "${CRASH_DIR}" "${QUEUE_DIR}" + [windows] test: fuzzer echo "Unsupported on this platform" diff --git a/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs b/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs index 0df9721c2e..8a2c8b38eb 100644 --- a/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs +++ b/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs @@ -3,9 +3,12 @@ use std::path::PathBuf; use clap::Parser; use libafl::{ - corpus::{Corpus, InMemoryCorpus, OnDiskCorpus}, + corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus}, events::SimpleEventManager, - executors::{forkserver::ForkserverExecutor, HasObservers, StdChildArgs}, + executors::{ + forkserver::{ForkserverExecutor, MAX_INPUT_SIZE_DEFAULT}, + HasObservers, StdChildArgs, + }, feedback_and_fast, feedback_or, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, @@ -42,6 +45,14 @@ struct Opt { )] executable: String, + #[arg( + help = "set max length of generated fuzz input", + short = 'G', + long = "maxlen", + default_value_t = MAX_INPUT_SIZE_DEFAULT + )] + max_input_len: usize, + #[arg( help = "The directory to read initial inputs from ('seeds')", name = "INPUT_DIR", @@ -53,7 +64,7 @@ struct Opt { help = "Timeout for each individual execution, in milliseconds", short = 't', long = "timeout", - default_value = "1200" + default_value = "3000" )] timeout: u64, @@ -135,8 +146,8 @@ pub fn main() { let mut state = StdState::new( // RNG StdRand::new(), - // Corpus that will be evolved, we keep it in memory for performance - InMemoryCorpus::::new(), + // Corpus that will be evolved, keep on disk to ensure instrumentation is working + CachedOnDiskCorpus::::new(PathBuf::from("./corpus_discovered"), 64).unwrap(), // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), @@ -180,6 +191,7 @@ pub fn main() { .parse_afl_cmdline(args) .coverage_map_size(MAP_SIZE) .timeout(Duration::from_millis(opt.timeout)) + .max_input_size(opt.max_input_len) .kill_signal(opt.signal) .build(tuple_list!(time_observer, edges_observer)) .unwrap();