From f38244fda473aa37b79b46e0587698917904d32a Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Wed, 22 Jan 2025 20:33:27 -0500 Subject: [PATCH 01/23] integrate pathAFL fuzzer --- fuzzers/path_afl/builder.Dockerfile | 128 ++++++++ fuzzers/path_afl/convert.cpp | 325 +++++++++++++++++++ fuzzers/path_afl/filterCFG.py | 119 +++++++ fuzzers/path_afl/filterCFG_Callmap_script.sh | 11 + fuzzers/path_afl/filterCallmap.py | 40 +++ fuzzers/path_afl/fuzzer.py | 139 ++++++++ fuzzers/path_afl/runner.Dockerfile | 26 ++ 7 files changed, 788 insertions(+) create mode 100644 fuzzers/path_afl/builder.Dockerfile create mode 100644 fuzzers/path_afl/convert.cpp create mode 100755 fuzzers/path_afl/filterCFG.py create mode 100755 fuzzers/path_afl/filterCFG_Callmap_script.sh create mode 100755 fuzzers/path_afl/filterCallmap.py create mode 100644 fuzzers/path_afl/fuzzer.py create mode 100644 fuzzers/path_afl/runner.Dockerfile diff --git a/fuzzers/path_afl/builder.Dockerfile b/fuzzers/path_afl/builder.Dockerfile new file mode 100644 index 000000000..140d0da0e --- /dev/null +++ b/fuzzers/path_afl/builder.Dockerfile @@ -0,0 +1,128 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ARG parent_image +FROM $parent_image + +RUN apt-get update && apt-get install -y sudo make build-essential git wget tree vim gdb zstd libzstd-dev libjbig-dev libselinux-dev bash + +SHELL ["/bin/bash", "-c"] + +RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - + +RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main" >> /etc/apt/sources.list +RUN echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal main" >> /etc/apt/sources.list +RUN echo "# 17" >> /etc/apt/sources.list +RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main" >> /etc/apt/sources.list +RUN echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main" >> /etc/apt/sources.list + +RUN apt-get update && apt-get install -y clang-17 lld-17 llvm-17-dev \ + libc++-17-dev libc++abi-17-dev gcc-10 gcc-10-plugin-dev libstdc++-10-dev \ + libssl-dev cargo autopoint + +RUN update-alternatives \ + --install /usr/lib/llvm llvm /usr/lib/llvm-17 1000 \ + --slave /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-17 \ + --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-17 \ + --slave /usr/bin/llvm-as llvm-as /usr/bin/llvm-as-17 \ + --slave /usr/bin/llvm-bcanalyzer llvm-bcanalyzer /usr/bin/llvm-bcanalyzer-17 \ + --slave /usr/bin/llvm-c-test llvm-c-test /usr/bin/llvm-c-test-17 \ + --slave /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-17 \ + --slave /usr/bin/llvm-diff llvm-diff /usr/bin/llvm-diff-17 \ + --slave /usr/bin/llvm-dis llvm-dis /usr/bin/llvm-dis-17 \ + --slave /usr/bin/llvm-dwarfdump llvm-dwarfdump /usr/bin/llvm-dwarfdump-17 \ + --slave /usr/bin/llvm-extract llvm-extract /usr/bin/llvm-extract-17 \ + --slave /usr/bin/llvm-link llvm-link /usr/bin/llvm-link-17 \ + --slave /usr/bin/llvm-mc llvm-mc /usr/bin/llvm-mc-17 \ + --slave /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-17 \ + --slave /usr/bin/llvm-objdump llvm-objdump /usr/bin/llvm-objdump-17 \ + --slave /usr/bin/llvm-ranlib llvm-ranlib /usr/bin/llvm-ranlib-17 \ + --slave /usr/bin/llvm-readobj llvm-readobj /usr/bin/llvm-readobj-17 \ + --slave /usr/bin/llvm-rtdyld llvm-rtdyld /usr/bin/llvm-rtdyld-17 \ + --slave /usr/bin/llvm-size llvm-size /usr/bin/llvm-size-17 \ + --slave /usr/bin/llvm-stress llvm-stress /usr/bin/llvm-stress-17 \ + --slave /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-17 \ + --slave /usr/bin/llvm-tblgen llvm-tblgen /usr/bin/llvm-tblgen-17 + +RUN update-alternatives \ + --install /usr/bin/clang clang /usr/bin/clang-17 1000 \ + --slave /usr/bin/clang++ clang++ /usr/bin/clang++-17 \ + --slave /usr/bin/clang-cpp clang-cpp /usr/bin/clang-cpp-17 \ + --slave /usr/bin/ld.lld lld /usr/bin/ld.lld-17 + +# Uninstall old Rust +RUN if which rustup; then rustup self uninstall -y; fi + +# Install latest Rust +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /rustup.sh && \ + sh /rustup.sh -y + +ENV PATH="/root/.cargo/bin:${PATH}" + +RUN rm -rf /usr/local/bin/clang /usr/local/bin/clang++ /usr/local/bin/llvm* +RUN rm -rf /usr/local/lib/clang +RUN rm -rf /usr/local/include/clang +RUN rm -rf /usr/local/share/clang + +# RUN rm /usr/local/bin/clang /usr/local/bin/clang++ /usr/local/bin/clang-cpp +# ENV PATH="/usr/bin:/usr/local/bin:$PATH" + +# RUN ls /usr/lib/llvm-17/include/llvm && exit 1 + +# RUN clang --version | grep "clang version 17" || { echo "Clang version is not 17"; exit 1; } + +RUN git clone -b fx-no-tail-opt1 https://github.com/fEst1ck/path-cov.git /path-cov + +RUN cd /path-cov && \ + git checkout bb900e89e14766ebd9d4af27cae0862bdb37de9b && \ + cargo build --release + +RUN git clone -b fixversion https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl + +# RUN clang++-17 -v -E -x c++ - < /dev/null && eixt 1 + +RUN cd /path-afl && \ + which clang-17 && \ + which clang && \ + clang --version && \ + clang++ -stdlib=libstdc++ -c hashcompare.cpp && \ + ar rcs libhashcompare.a hashcompare.o && \ + cp /path-cov/target/release/libpath_reduction.so . + +# RUN which llvm-config-17 || { echo "llvm-config-17 not found"; exit 1; } + +RUN cd /path-afl && \ + export CC=clang && \ + export CXX=clang++ && \ + export AFL_NO_X86=1 && \ + unset CFLAGS CXXFLAGS && \ + PYTHON_INCLUDE=/ && \ + LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lstdc++ -lpath_reduction" make +# RUN export CC=clang && \ +# export CXX=clang++ && \ +# export AFL_NO_X86=1 && \ +# export PYTHON_INCLUDE=/ && \ +# LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lstdc++ -lpath_reduction" make -e -C utils/aflpp_driver || exit 1 + +RUN apt install g++ + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cd /path-afl && cp utils/aflpp_driver/libAFLDriver.a / + +RUN cp /usr/lib/x86_64-linux-gnu/libpython3.8.so.1.0 / + +RUN cp /usr/lib/llvm-17/lib/libc++.so.1 / +RUN cp /usr/lib/llvm-17/lib/libc++abi.so.1 / + diff --git a/fuzzers/path_afl/convert.cpp b/fuzzers/path_afl/convert.cpp new file mode 100644 index 000000000..434f4b1bb --- /dev/null +++ b/fuzzers/path_afl/convert.cpp @@ -0,0 +1,325 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// C++ 接口 ------------------------------------------------------------------- start +#define FUNC_ID_LEN 256 + +// CFG 结构体只需要在 cfg.txt 中解析获取 +// CYHNO_TE: 这里需要一个二进制文件 +typedef struct CFG { + // int funcID; funcID 就是 CFG 在 cfg_arr 中的下标索引 + char function_name[FUNC_ID_LEN]; // 函数的字符串形式,整数形式就是 cfg_arr 的下标 + int entry; // 整数,表示函数入点 block + int exit; // 整数,表示函数出点 block +} CFG; + +// calls 需要 processed_mapping_table.txt 中获取 +// successor_size 从 cfg.txt 中获取 +// successors_arr 从 cfg.txt 中获取 +// CYHNO_TE: 这里需要一个二进制文件 +typedef struct BlockEntry { + // int bbID; 基本块ID 就是在 block_arr 中的下标索引 + int calls; // -1 时,表示没有调用任何函数;非负数时,表示调用的函数的 funcID,也就是在 cfg_arr 中的下标索引 + int successor_size; // 表示这个基本块拥有的 successors 数量 + int *successors_arr; // 这个基本块的 successors_arr 数组 +} BlockEntry; + +// cfg_size 只需要过一遍 function_list.txt 即可,内存也那样分配就好 +// block_size 只需要过一遍 processed_mapping_table.txt 即可,内存也那样分配就好 +// CYHNO_TE: 这是顶层结构体 +// CYHNO_TE: 这里需要一个二进制文件 +typedef struct Top_Level { + int cfg_size; // cfg 的数量 + CFG *cfg_arr; // cfg 数组 + int block_size; // blocks 总数 + BlockEntry **block_arr; // block 数组 +} Top_Level; +// C++ 接口 ------------------------------------------------------------------- end + +void dump_block(BlockEntry *block) { + std::cout << "block->calls = " << block->calls << std::endl; + std::cout << "block->successor_size = " << block->successor_size << std::endl; + for (int i = 0; i < block->successor_size; i++) { + printf("block->successor_arr[%d] = %d\n", i, block->successors_arr[i]); + } +} + +void dump_cfg(CFG *cfg) { + std::string funcname(cfg->function_name); + std::cout << "cfg->function_name = " << funcname << std::endl; + std::cout << "cfg->entry = " << cfg->entry << std::endl; + std::cout << "cfg->exit = " << cfg->exit << std::endl; +} + +void dump_top(Top_Level *top) { + std::cout << "top->cfg_size = " << top->cfg_size << std::endl; + std::cout << "top->block_size = " << top->block_size << std::endl; + for(int i = 0; i < top->cfg_size; i++) { + dump_cfg(&(top->cfg_arr[i])); + } + for(int i = 0; i < top->block_size; i++) { + if(top->block_arr[i]) { + std::cout << "BB " << i << std::endl; + dump_block(top->block_arr[i]); + } + } +} + +void store_top(Top_Level *top); + +// 去除字符串首尾的空白字符 +std::string trim(const std::string& str) { + size_t first = str.find_first_not_of(" \t\n\r"); + size_t last = str.find_last_not_of(" \t\n\r"); + if (first == std::string::npos || last == std::string::npos) { + return ""; + } + return str.substr(first, last - first + 1); +} + +int main() { + + // 0. 一个顶层,收集完数据后要被 dump 出去 + Top_Level top; + + // 1. 读取 bbnum.txt 获知 PUT 的基本块总数,给 top.block_arr 分配空间,并初始化 top.block_arr + int numBB = -1; + FILE *file = fopen("bbnum.txt", "r"); + assert(file); + assert(fscanf(file, "%d", &numBB) == 1); + fclose(file); + top.block_size = numBB; + top.block_arr = (BlockEntry **) malloc(sizeof(BlockEntry *) * numBB); + memset(top.block_arr, 0, sizeof(BlockEntry *) * numBB); + + // 2. 构建一个 function_name -> integer 的映射 (需要读取 function_list.txt,原因后续填满 BasicBlock 需要使用) + // 同时给 cfg_arr 分配内存空间 + std::unordered_map funcname_int; + std::ifstream function_list_file("function_list.txt"); + assert(function_list_file.is_open()); // 检查文件是否成功打开h + std::string line; + std::string firstPart; + std::string secondPart; + + while (std::getline(function_list_file, line)) { // 逐行读取文件内容 + std::string input = line; + size_t pos = input.find(' '); // 查找第一个空格的位置 + if (pos != std::string::npos) { // 如果找到了空格 + firstPart = input.substr(0, pos); // 提取第一个空格之前的部分 + secondPart = input.substr(pos + 1); // 提取第一个空格之后的部分 + } else { + std::cout << "未找到空格" << std::endl; + } + + // 函数名 -> funcid 映射 + firstPart = trim(firstPart); + secondPart = trim(secondPart); + funcname_int[secondPart] = std::stoi(firstPart); + } + + // 获取函数的总数,然后给 cfg_arr 分配内存空间 + int numfunction = std::stoi(firstPart) + 1; + top.cfg_size = numfunction; + top.cfg_arr = (CFG *) malloc(sizeof(CFG) * numfunction); + + function_list_file.close(); // 关闭文件 + + // // 下面这段代码用来打印 funcname_int 里的数据 + // for (const auto& pair : funcname_int) { + // std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl; + // } + + // 3. 接下来的任务:填充 BlockEntry 数组 的calls属性 -------------------------------------------------------- start + std::ifstream callmap_file("callmap_filtered.txt"); + line = ""; + assert(callmap_file.is_open()); // 检查文件是否成功打开 + while (std::getline(callmap_file, line)) { // 逐行读取文件内容 + std::string input = trim(line); + size_t pos = input.find(' '); // 查找第一个空格的位置 + if (pos != std::string::npos) { // 如果找到了空格 + firstPart = input.substr(0, pos); // 提取第一个空格之前的部分 + secondPart = input.substr(pos + 1); // 提取第一个空格之后的部分 + } else { + // 未找到空格说明这个基本块号不是 call 基本块 + // 此时,input 本身就是 first part(BBID) + firstPart = input; + secondPart = ""; + } + + top.block_arr[std::stoi(firstPart)] = (BlockEntry *) malloc(sizeof(BlockEntry)); + + size_t found = secondPart.find("Calls"); + + if (found != std::string::npos) { + size_t pos = secondPart.find("Calls "); + assert(pos != std::string::npos); + std::string result = secondPart.substr(pos + std::strlen("Calls ")); + // std::cout << result << std::endl; + result = trim(result); + + if (funcname_int.count(result) > 0) { + top.block_arr[std::stoi(firstPart)]->calls = funcname_int[result]; + } else { + top.block_arr[std::stoi(firstPart)]->calls = -2; // -2 表示是 C 库函数 + } + // std::cout << "The string contains the word 'calls'." << std::endl; + } else { + top.block_arr[std::stoi(firstPart)]->calls = -1; + } + } + + callmap_file.close(); // 关闭文件 + // 3. 接下来的任务:填充 BlockEntry 数组 的calls属性 -------------------------------------------------------- end + + // 接下来的任务:填满 CFG 数组 -------------------------------------------------------------------- start + // 第二遍,这一次的目的是填满 cfg_arr (单独读取 cfg.txt 即可) --- doing + line = ""; // zekun_processed_mapping_table.txt 的每一行内容 + firstPart = ""; + secondPart = ""; + + std::ifstream cfg_file("cfg_filtered.txt"); + + int func_id = 0; + + assert(cfg_file.is_open()); + + bool justGetIn = false; // 一个 flag,表示是否刚刚进入一个函数,用来寻找 entryblock + bool waitForLast = false; // 一个 flag,标识是否在等待一个函数结束,用来寻找 exitblock + int exitblockStore = -1; // 用来储存可能是 exitblock 的整数 + int curBBID = -1; // 当前基本块的 BBID + + while (std::getline(cfg_file, line)) { // 逐行读取文件内容 + + size_t pos = line.find(' '); // 查找第一个空格的位置 + firstPart = line.substr(0, pos); + secondPart = line.substr(pos + 1); // 提取第一个空格之后的部分 + + size_t start = line.find_first_not_of(" \t\n\r"); + size_t end = line.find_last_not_of(" \t\n\r"); + + if (start != std::string::npos && end != std::string::npos) { + firstPart = firstPart.substr(start, end - start + 1); + secondPart = secondPart.substr(start, end - start + 1); + } + + if (firstPart == "Function:") { + + // printf("waitForLast = %d, exitblockStore = %d\n", waitForLast, exitblockStore); + + if (waitForLast) { + top.cfg_arr[func_id - 1].exit = exitblockStore; + // printf("exitBlock = %d\n", top.cfg_arr[func_id].exit); + waitForLast = false; + } + + strcpy(top.cfg_arr[func_id].function_name, secondPart.c_str()); + // printf("funcname = %s\n", top.cfg_arr[func_id].function_name); + justGetIn = true; + func_id++; + } + else if (firstPart == "BasicBlock:") { + + // std::cout << "secondPart = " << secondPart << std::endl; + curBBID = std::stoi(secondPart); + + // printf("func_id = %d, justGetIn = %d, std::stoi(secondPart) = %d\n", func_id, justGetIn, std::stoi(secondPart)); + + if(justGetIn) { + top.cfg_arr[func_id - 1].entry = std::stoi(secondPart); + // printf("entryBlock = %d\n", top.cfg_arr[func_id].entry); + justGetIn = false; + } + + waitForLast = true; + exitblockStore = std::stoi(secondPart); + + } + else if (firstPart == "Successors:") { + // 填满 BlockEntry 的 successor_size 和 successors_arr + + std::vector words; + std::vector integer_words; + + size_t start = 0, end = 0; + while ((end = secondPart.find(' ', start)) != std::string::npos) { + words.push_back(secondPart.substr(start, end - start)); + start = end + 1; + } + words.push_back(secondPart.substr(start)); // 添加最后一个单词 + // 把 vector 中的单词字符串转为整数 vector + for (const auto& w : words) { + if (!w.empty() && w != "Successors:") { + int num = std::stoi(w); + integer_words.push_back(num); + } + } + + assert(top.block_arr[curBBID]); + top.block_arr[curBBID]->successor_size = integer_words.size(); + top.block_arr[curBBID]->successors_arr = (int *) malloc(sizeof(int) * integer_words.size()); + + for(int i = 0; i < integer_words.size(); i++) { + top.block_arr[curBBID]->successors_arr[i] = integer_words[i]; + } + } + // 不需要 else,因为有可能是 "" 空字符串 + } + + top.cfg_arr[func_id - 1].exit = exitblockStore; + cfg_file.close(); + // top.cfg_arr[func_id].exit = exitblockStore; + // printf("exitBlock = %d\n", top.cfg_arr[func_id].exit); + // 接下来的任务:填满 CFG 数组 -------------------------------------------------------------------- end - checked + + + // 2. 读取 function_list.txt,构建整个映射表 --------------------------------------------------- end + + // 3. 这里可以尝试 dump top 的 Readable 形式 + dump_top(&top); + // 3. 这里可以尝试把 top 里的内容储存到二进制文件里 + store_top(&top); + + return 0; +} + +void store_top(Top_Level *top) { + FILE *file = fopen("top.bin", "wb"); + if (file != NULL) { + fwrite(top, sizeof(Top_Level), 1, file); + fwrite(top->cfg_arr, sizeof(CFG) * top->cfg_size, 1, file); + + int count = 0; + for(int i = 0; i < top->block_size; i++) { + if(top->block_arr[i]) { + count++; + } + } + fwrite(&count, sizeof(int), 1, file); + + for(int i = 0; i < top->block_size; i++) { + if(top->block_arr[i]) { + fwrite(&i, sizeof(int), 1, file); + fwrite(top->block_arr[i], sizeof(BlockEntry), 1, file); + } + } + + for(int i = 0; i < top->block_size; i++) { + if(top->block_arr[i]) { + fwrite(&i, sizeof(int), 1, file); + fwrite(top->block_arr[i]->successors_arr, sizeof(int) * top->block_arr[i]->successor_size, 1, file); + } + } + + fclose(file); + // printf("Data has been dumped into top.bin\n"); + } else { + perror("Failed to open file for writing"); + } +} diff --git a/fuzzers/path_afl/filterCFG.py b/fuzzers/path_afl/filterCFG.py new file mode 100755 index 000000000..184e5a582 --- /dev/null +++ b/fuzzers/path_afl/filterCFG.py @@ -0,0 +1,119 @@ +import sys +import re + +# 检查是否传入了足够的参数(至少需要三个参数加上脚本名称) +assert(len(sys.argv) == 4) +# 打印第一个、第二个和第三个参数 +# python3 filterCFG.py cfg.txt PUT_decomp.txt cfg_filtered.txt +print(f"参数1: {sys.argv[1]}") +print(f"参数2: {sys.argv[2]}") +print(f"参数3: {sys.argv[3]}") + +# 思考代码: +# 1.先把整个 cfg.txt 读入内存,按照 {key="第一个基本块的块号", value=[bool: false, "CFG字符串列表"]} 来储存 +# 2.扫描反汇编代码,扫描每个函数 +# 1.如果函数中没有对 path_inject_eachbb 的调用,那说明不是 PUT 源码,下一个函数 +# 2.如果有,那么看第一个 path_inject_eachbb 的参数,随后使用这个参数索引到之前的字典 +# 把字典 value 里对应的 false 设置为 true,随后继续下一个函数,直到扫描完整个反汇编文件 +# 3.扫描一遍之前的字典,把所有 bool = true 的 CFG字符串列表 dump 到 cfg_filtered.txt 里 + +# 1.先把整个 cfg.txt 读入内存,按照 {key="第一个基本块的块号", value=[bool: false, "CFG字符串列表"]} 来储存 +justEnterFunction = False # 这个flag用来识别每个函数的第一个基本块 entrypoing +with open(sys.argv[1], 'r', encoding='utf-8') as file: + wholeCFG = {} + singleCFG = [] + firstBBID = -1 + for line in file: + # 使用 strip() 去除每行末尾的换行符 + line = line.strip() + if "Function: " in line: + # 如果 singleCFG 不为空,那么把它放进 wholeCFG 字典里 + if singleCFG: + wholeCFG[firstBBID] = [False, singleCFG] + singleCFG = [] + justEnterFunction = True + else: + if justEnterFunction: + match = re.search(r'BasicBlock: (\d+)', line) + assert(match) + justEnterFunction = False + firstBBID = int(match.group(1)) + else: + pass + # do nothing + singleCFG.append(line) + file.close() + +# 循环结束后,还有最后一个函数的 CFG 没有加入 wholeCFG,现在加进去 +wholeCFG[firstBBID] = [False, singleCFG] + +# 2.扫描反汇编代码,扫描每个函数 +# 1.如果函数中没有对 path_inject_eachbb 的调用,那说明不是 PUT 源码,下一个函数 +# 2.如果有,那么看第一个 path_inject_eachbb 的参数,随后使用这个参数索引到之前的字典 +# 把字典 value 里对应的 false 设置为 true,随后继续下一个函数,直到扫描完整个反汇编文件 +justEnterFunction = False # 这个flag用来识别是否在一个函数内 +with open(sys.argv[2], 'r', encoding='utf-8') as file: + for line in file: + # 使用 strip() 去除每行末尾的换行符 + line = line.strip() + funcNameMatch = re.match(r'^[0-9a-fA-F]+ <[^>]+>:', line) + if funcNameMatch: + # if justEnterFunction: + # 若此时 justEnterFunction = True,说明上一个函数中不包含 callq path_inject_eachbb,不做处理直接skip + # 若此时 justEnterFunction = False,说明上一个函数中包含 callq path_inject_eachbb 已被找到,不做处理直接skip + justEnterFunction = True + elif justEnterFunction: + path_inject_match = re.search(r'call?\s+[0-9a-fA-F]+\s+', line) + if path_inject_match: + # 到这里已经找到这个函数的第一个 callq path_inject_eachbb 了,除了重置 justEnterFunction, + # 还要对 step1 里得到的字典做相应的处理 + # 此时,previousline 有两种可能: + # 1. xor %edi,%edi + # 2. mov $0x3208,%edi + print('matched!') + xor_match = re.search(r'xor\s+%edi,%edi', previousline) + mov_match = re.search(r'mov\s+\$(0x[0-9a-fA-F]+),%edi', previousline) + assert(xor_match or mov_match) + assert(not (xor_match and mov_match)) + if xor_match: + # 如果 previousline = xor 汇编指令,path_inject_eachbb 的参数是 0 + arg = 0 + else: + arg = int(mov_match.group(1), 16) + print(f"arg: {arg} {mov_match.group(1)}") + wholeCFG[arg][0] = True + justEnterFunction = False + else: + # 如果在函数里还有没有遇到 callq path_inject_eachbb,那么就继续读下一行 + pass + else: + # 如果既没有匹配到函数头,justEnterFunction = False + # 说明这个函数的 第一个callq path_inject_eachbb 已经被找到了 + # 继续下一行文字,直到进入到下一个函数为止 + pass + # 记录当前行,这一行的目的是在找到 callq path_inject_eachbb 后,寻找这个函数的参数 + previousline = line + file.close() + +# # 打印 wholeCFG +# print(wholeCFG) + +# 3.扫描一遍之前的字典,把所有 bool = true 的 CFG字符串列表 dump 到 cfg_filtered.txt 里 +# 打开文件以写入模式('w') +with open(sys.argv[3], "w") as file: + for key, value in wholeCFG.items(): + if value[0]: + for line in value[1]: + file.write(line + "\n") + file.close() + + +# xor %esi,%esi +# 2038f6: bf 08 32 00 00 mov $0x3208,%edi +# 2038fb: e8 a0 e4 e0 00 callq 1011da0 + + + + + + diff --git a/fuzzers/path_afl/filterCFG_Callmap_script.sh b/fuzzers/path_afl/filterCFG_Callmap_script.sh new file mode 100755 index 000000000..b6daf7b96 --- /dev/null +++ b/fuzzers/path_afl/filterCFG_Callmap_script.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# 获取 PUT 的反汇编结果 +objdump -d path_to_put > PUT_decomp.txt + +# 运行过滤CFG python 脚本 +python3 filterCFG.py cfg.txt PUT_decomp.txt cfg_filtered.txt + +# 运行过滤Callmap python 脚本 +python3 filterCallmap.py cfg_filtered.txt callmap.txt callmap_filtered.txt + diff --git a/fuzzers/path_afl/filterCallmap.py b/fuzzers/path_afl/filterCallmap.py new file mode 100755 index 000000000..780852849 --- /dev/null +++ b/fuzzers/path_afl/filterCallmap.py @@ -0,0 +1,40 @@ +import sys +import re + +# 检查是否传入了足够的参数(至少需要三个参数加上脚本名称) +assert(len(sys.argv) == 4) +# 打印第一个、第二个和第三个参数 +# python3 filterCallmap.py cfg_filtered.txt callmap.txt callmap_filtered.txt +# print(f"参数1: {sys.argv[1]}") +# print(f"参数2: {sys.argv[2]}") +# print(f"参数3: {sys.argv[3]}") + +# 思考代码: +# 1.读取 cfg_filtered.txt,扫描每个 BasicBlock,记录它们的编号,存到一个字典里 +# 2.读取 callmap.txt 的每一行,根据读到的 BBID 去比较字典里是否存在这个 BBID,来决定是否把这行输出到 callmap_filtered.txt 里 + +# 1.读取 cfg_filtered.txt,扫描每个 BasicBlock,记录它们的编号,存到一个字典里 +bbdict = {} +with open(sys.argv[1], 'r', encoding='utf-8') as file: + for line in file: + # 使用 strip() 去除每行末尾的换行符 + line = line.strip() + BasicBlock_match = re.search(r'BasicBlock: (\d+)', line) + if BasicBlock_match: + bbid = int(BasicBlock_match.group(1)) + bbdict[bbid] = 1 + else: + # 如果这行不包含 "BasicBlock",那么不做任何事情 + pass + +# 2.读取 callmap.txt 的每一行,根据读到的 BBID 去比较字典里是否存在这个 BBID,来决定是否把这行输出到 callmap_filtered.txt 里 +written_file = open(sys.argv[3], 'w') +with open(sys.argv[2], 'r', encoding='utf-8') as file: + for line in file: + # 使用 strip() 去除每行末尾的换行符 + line = line.strip() + bbid_match = re.search(r'(\d+).*', line) + bbid = int(bbid_match.group(1)) + if bbid in bbdict: + written_file.write(line + "\n") + diff --git a/fuzzers/path_afl/fuzzer.py b/fuzzers/path_afl/fuzzer.py new file mode 100644 index 000000000..81b7297d5 --- /dev/null +++ b/fuzzers/path_afl/fuzzer.py @@ -0,0 +1,139 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Integration code for pathAFL fuzzer.""" + +import os +import shutil +import subprocess +from fuzzers import utils + + +def prepare_build_environment(): + """Set environment variables used to build targets for pathAFL-based + fuzzers.""" + os.environ['LD_LIBRARY_PATH'] = '/path-afl' + os.environ['CC'] = '/path-afl/afl-clang-fast' + os.environ['CXX'] = '/path-afl/afl-clang-fast++' + current_directory = os.getcwd() + os.environ["BBIDFILE"] = os.path.join(current_directory, "bbid.txt") + os.environ["CALLMAPFILE"] = os.path.join(current_directory, "callmap.txt") + os.environ["CFGFILE"] = os.path.join(current_directory, "cfg.txt") + os.environ["FUZZER"] = '/path-afl' + os.environ["AFL_LLVM_CALLER"] = '1' + os.environ['FUZZER_LIB'] = '/libAFLDriver.a' + + +def build(): + """Build benchmark.""" + prepare_build_environment() + + utils.build_benchmark() + + subprocess.run('cat cfg.txt | grep "BasicBlock: " | wc -l > bbnum.txt', shell=True, check=True) + print(f"/out/{os.getenv('FUZZ_TARGET')}") + result = subprocess.run(["bash", '/path-afl/fuzzing_support/filterCFGandCallmap.sh', f"/out/{os.getenv('FUZZ_TARGET')}"], check=False, capture_output=True, text=True) + print(result.stdout) + print(result.stderr) + ... + subprocess.run('cat cfg_filtered.txt | grep \"Function: \" | nl -v 0 | awk \'{print $1, $3, $4, $5, $6, $7, $8, $9}\' > function_list.txt', shell=True, check=True) + subprocess.run('g++ -I/path-afl/fuzzing_support /path-afl/fuzzing_support/convert.cpp -o convert', shell=True, check=True) + subprocess.run('./convert', shell=True, check=True) + + print('[post_build] Copying afl-fuzz to $OUT directory') + + # Copy out the afl-fuzz binary as a build artifact. + shutil.copy('/path-afl/libpath_reduction.so', os.environ['OUT']) + shutil.copy('/path-afl/afl-fuzz', os.environ['OUT']) + shutil.copy('./top.bin', os.environ['OUT']) + shutil.copy('/libpython3.8.so.1.0', os.environ['OUT']) + try: + src = '/usr/lib/llvm-17/lib' + dst = os.environ['OUT'] + shutil.copytree(src, dst, dirs_exist_ok=True) + except KeyError: + print("Environment variable 'OUT' is not set.") + assert False + except FileNotFoundError as e: + print(f"Source directory not found: {e}") + assert False + except PermissionError as e: + print(f"Permission error: {e}") + assert False + except Exception as e: + print(f"An error occurred: {e}") + assert False + +def prepare_fuzz_environment(input_corpus): + """Prepare to fuzz with AFL or another AFL-based fuzzer.""" + # Tell AFL to not use its terminal UI so we get usable logs. + os.environ['AFL_NO_UI'] = '1' + # Skip AFL's CPU frequency check (fails on Docker). + os.environ['AFL_SKIP_CPUFREQ'] = '1' + # No need to bind affinity to one core, Docker enforces 1 core usage. + os.environ['AFL_NO_AFFINITY'] = '1' + # AFL will abort on startup if the core pattern sends notifications to + # external programs. We don't care about this. + os.environ['AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES'] = '1' + # Don't exit when crashes are found. This can happen when corpus from + # OSS-Fuzz is used. + os.environ['AFL_SKIP_CRASHES'] = '1' + # Shuffle the queue + os.environ['AFL_SHUFFLE_QUEUE'] = '1' + os.environ['CFG_BIN_FILE'] = './top.bin' + os.environ['LD_LIBRARY_PATH'] = f'./lib:{os.getcwd()}:{os.environ["LD_LIBRARY_PATH"]}' + + # AFL needs at least one non-empty seed to start. + utils.create_seed_file_for_empty_corpus(input_corpus) + +def run_afl_fuzz(input_corpus, + output_corpus, + target_binary, + additional_flags=None, + hide_output=False): + """Run afl-fuzz.""" + # Spawn the afl fuzzing process. + print('[run_afl_fuzz] Running target with afl-fuzz') + command = [ + './afl-fuzz', + '-i', + input_corpus, + '-o', + output_corpus, + # Use no memory limit as ASAN doesn't play nicely with one. + '-m', + 'none', + '-t', + '1000+', # Use same default 1 sec timeout, but add '+' to skip hangs. + ] + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + command.extend(['-x', dictionary_path]) + command += [ + '--', + target_binary, + # Pass INT_MAX to afl the maximize the number of persistent loops it + # performs. + '2147483647' + ] + print('[run_afl_fuzz] Running command: ' + ' '.join(command)) + output_stream = subprocess.DEVNULL if hide_output else None + subprocess.check_call(command, stdout=output_stream, stderr=output_stream) + +def fuzz(input_corpus, output_corpus, target_binary): + """Run afl-fuzz on target.""" + prepare_fuzz_environment(input_corpus) + + os.environ['K'] = '42' + + run_afl_fuzz(input_corpus, output_corpus, target_binary) \ No newline at end of file diff --git a/fuzzers/path_afl/runner.Dockerfile b/fuzzers/path_afl/runner.Dockerfile new file mode 100644 index 000000000..2b5dd351d --- /dev/null +++ b/fuzzers/path_afl/runner.Dockerfile @@ -0,0 +1,26 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM gcr.io/fuzzbench/base-image + +RUN apt-get update +RUN apt-get install -y python3.8 + +# This makes interactive docker runs painless: +ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/out" +#ENV AFL_MAP_SIZE=2621440 +ENV PATH="$PATH:/out" +ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +ENV AFL_TESTCACHE_SIZE=2 \ No newline at end of file From 6b0999dfab91a83d534f208c2e18e727e51ff856 Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Wed, 22 Jan 2025 20:49:47 -0500 Subject: [PATCH 02/23] format --- fuzzers/path_afl/filterCFG.py | 31 +++++++++++++------------------ fuzzers/path_afl/filterCallmap.py | 3 +-- fuzzers/path_afl/fuzzer.py | 30 ++++++++++++++++++++++++------ 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/fuzzers/path_afl/filterCFG.py b/fuzzers/path_afl/filterCFG.py index 184e5a582..7d9916a9b 100755 --- a/fuzzers/path_afl/filterCFG.py +++ b/fuzzers/path_afl/filterCFG.py @@ -2,7 +2,7 @@ import re # 检查是否传入了足够的参数(至少需要三个参数加上脚本名称) -assert(len(sys.argv) == 4) +assert (len(sys.argv) == 4) # 打印第一个、第二个和第三个参数 # python3 filterCFG.py cfg.txt PUT_decomp.txt cfg_filtered.txt print(f"参数1: {sys.argv[1]}") @@ -18,7 +18,7 @@ # 3.扫描一遍之前的字典,把所有 bool = true 的 CFG字符串列表 dump 到 cfg_filtered.txt 里 # 1.先把整个 cfg.txt 读入内存,按照 {key="第一个基本块的块号", value=[bool: false, "CFG字符串列表"]} 来储存 -justEnterFunction = False # 这个flag用来识别每个函数的第一个基本块 entrypoing +justEnterFunction = False # 这个flag用来识别每个函数的第一个基本块 entrypoing with open(sys.argv[1], 'r', encoding='utf-8') as file: wholeCFG = {} singleCFG = [] @@ -35,7 +35,7 @@ else: if justEnterFunction: match = re.search(r'BasicBlock: (\d+)', line) - assert(match) + assert (match) justEnterFunction = False firstBBID = int(match.group(1)) else: @@ -51,19 +51,20 @@ # 1.如果函数中没有对 path_inject_eachbb 的调用,那说明不是 PUT 源码,下一个函数 # 2.如果有,那么看第一个 path_inject_eachbb 的参数,随后使用这个参数索引到之前的字典 # 把字典 value 里对应的 false 设置为 true,随后继续下一个函数,直到扫描完整个反汇编文件 -justEnterFunction = False # 这个flag用来识别是否在一个函数内 +justEnterFunction = False # 这个flag用来识别是否在一个函数内 with open(sys.argv[2], 'r', encoding='utf-8') as file: for line in file: # 使用 strip() 去除每行末尾的换行符 line = line.strip() funcNameMatch = re.match(r'^[0-9a-fA-F]+ <[^>]+>:', line) if funcNameMatch: - # if justEnterFunction: - # 若此时 justEnterFunction = True,说明上一个函数中不包含 callq path_inject_eachbb,不做处理直接skip - # 若此时 justEnterFunction = False,说明上一个函数中包含 callq path_inject_eachbb 已被找到,不做处理直接skip + # if justEnterFunction: + # 若此时 justEnterFunction = True,说明上一个函数中不包含 callq path_inject_eachbb,不做处理直接skip + # 若此时 justEnterFunction = False,说明上一个函数中包含 callq path_inject_eachbb 已被找到,不做处理直接skip justEnterFunction = True elif justEnterFunction: - path_inject_match = re.search(r'call?\s+[0-9a-fA-F]+\s+', line) + path_inject_match = re.search( + r'call?\s+[0-9a-fA-F]+\s+', line) if path_inject_match: # 到这里已经找到这个函数的第一个 callq path_inject_eachbb 了,除了重置 justEnterFunction, # 还要对 step1 里得到的字典做相应的处理 @@ -72,9 +73,10 @@ # 2. mov $0x3208,%edi print('matched!') xor_match = re.search(r'xor\s+%edi,%edi', previousline) - mov_match = re.search(r'mov\s+\$(0x[0-9a-fA-F]+),%edi', previousline) - assert(xor_match or mov_match) - assert(not (xor_match and mov_match)) + mov_match = re.search(r'mov\s+\$(0x[0-9a-fA-F]+),%edi', + previousline) + assert (xor_match or mov_match) + assert (not (xor_match and mov_match)) if xor_match: # 如果 previousline = xor 汇编指令,path_inject_eachbb 的参数是 0 arg = 0 @@ -107,13 +109,6 @@ file.write(line + "\n") file.close() - # xor %esi,%esi # 2038f6: bf 08 32 00 00 mov $0x3208,%edi # 2038fb: e8 a0 e4 e0 00 callq 1011da0 - - - - - - diff --git a/fuzzers/path_afl/filterCallmap.py b/fuzzers/path_afl/filterCallmap.py index 780852849..ca41b4297 100755 --- a/fuzzers/path_afl/filterCallmap.py +++ b/fuzzers/path_afl/filterCallmap.py @@ -2,7 +2,7 @@ import re # 检查是否传入了足够的参数(至少需要三个参数加上脚本名称) -assert(len(sys.argv) == 4) +assert (len(sys.argv) == 4) # 打印第一个、第二个和第三个参数 # python3 filterCallmap.py cfg_filtered.txt callmap.txt callmap_filtered.txt # print(f"参数1: {sys.argv[1]}") @@ -37,4 +37,3 @@ bbid = int(bbid_match.group(1)) if bbid in bbdict: written_file.write(line + "\n") - diff --git a/fuzzers/path_afl/fuzzer.py b/fuzzers/path_afl/fuzzer.py index 81b7297d5..f5079f78a 100644 --- a/fuzzers/path_afl/fuzzer.py +++ b/fuzzers/path_afl/fuzzer.py @@ -40,14 +40,28 @@ def build(): utils.build_benchmark() - subprocess.run('cat cfg.txt | grep "BasicBlock: " | wc -l > bbnum.txt', shell=True, check=True) + subprocess.run('cat cfg.txt | grep "BasicBlock: " | wc -l > bbnum.txt', + shell=True, + check=True) print(f"/out/{os.getenv('FUZZ_TARGET')}") - result = subprocess.run(["bash", '/path-afl/fuzzing_support/filterCFGandCallmap.sh', f"/out/{os.getenv('FUZZ_TARGET')}"], check=False, capture_output=True, text=True) + result = subprocess.run([ + "bash", '/path-afl/fuzzing_support/filterCFGandCallmap.sh', + f"/out/{os.getenv('FUZZ_TARGET')}" + ], + check=False, + capture_output=True, + text=True) print(result.stdout) print(result.stderr) ... - subprocess.run('cat cfg_filtered.txt | grep \"Function: \" | nl -v 0 | awk \'{print $1, $3, $4, $5, $6, $7, $8, $9}\' > function_list.txt', shell=True, check=True) - subprocess.run('g++ -I/path-afl/fuzzing_support /path-afl/fuzzing_support/convert.cpp -o convert', shell=True, check=True) + subprocess.run( + 'cat cfg_filtered.txt | grep \"Function: \" | nl -v 0 | awk \'{print $1, $3, $4, $5, $6, $7, $8, $9}\' > function_list.txt', + shell=True, + check=True) + subprocess.run( + 'g++ -I/path-afl/fuzzing_support /path-afl/fuzzing_support/convert.cpp -o convert', + shell=True, + check=True) subprocess.run('./convert', shell=True, check=True) print('[post_build] Copying afl-fuzz to $OUT directory') @@ -74,6 +88,7 @@ def build(): print(f"An error occurred: {e}") assert False + def prepare_fuzz_environment(input_corpus): """Prepare to fuzz with AFL or another AFL-based fuzzer.""" # Tell AFL to not use its terminal UI so we get usable logs. @@ -91,11 +106,13 @@ def prepare_fuzz_environment(input_corpus): # Shuffle the queue os.environ['AFL_SHUFFLE_QUEUE'] = '1' os.environ['CFG_BIN_FILE'] = './top.bin' - os.environ['LD_LIBRARY_PATH'] = f'./lib:{os.getcwd()}:{os.environ["LD_LIBRARY_PATH"]}' + os.environ[ + 'LD_LIBRARY_PATH'] = f'./lib:{os.getcwd()}:{os.environ["LD_LIBRARY_PATH"]}' # AFL needs at least one non-empty seed to start. utils.create_seed_file_for_empty_corpus(input_corpus) + def run_afl_fuzz(input_corpus, output_corpus, target_binary, @@ -130,10 +147,11 @@ def run_afl_fuzz(input_corpus, output_stream = subprocess.DEVNULL if hide_output else None subprocess.check_call(command, stdout=output_stream, stderr=output_stream) + def fuzz(input_corpus, output_corpus, target_binary): """Run afl-fuzz on target.""" prepare_fuzz_environment(input_corpus) os.environ['K'] = '42' - run_afl_fuzz(input_corpus, output_corpus, target_binary) \ No newline at end of file + run_afl_fuzz(input_corpus, output_corpus, target_binary) From 0720fb3bcde590b8c4525a00805984704727e9ce Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Wed, 22 Jan 2025 21:06:05 -0500 Subject: [PATCH 03/23] format & add license header --- fuzzers/path_afl/convert.cpp | 12 ++++++++++++ fuzzers/path_afl/filterCFG.py | 12 ++++++++++++ fuzzers/path_afl/filterCFG_Callmap_script.sh | 12 ++++++++++++ fuzzers/path_afl/filterCallmap.py | 14 +++++++++++++- fuzzers/path_afl/fuzzer.py | 3 --- 5 files changed, 49 insertions(+), 4 deletions(-) diff --git a/fuzzers/path_afl/convert.cpp b/fuzzers/path_afl/convert.cpp index 434f4b1bb..93a0a7fe7 100644 --- a/fuzzers/path_afl/convert.cpp +++ b/fuzzers/path_afl/convert.cpp @@ -1,3 +1,15 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include #include #include diff --git a/fuzzers/path_afl/filterCFG.py b/fuzzers/path_afl/filterCFG.py index 7d9916a9b..281d97752 100755 --- a/fuzzers/path_afl/filterCFG.py +++ b/fuzzers/path_afl/filterCFG.py @@ -1,3 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import sys import re diff --git a/fuzzers/path_afl/filterCFG_Callmap_script.sh b/fuzzers/path_afl/filterCFG_Callmap_script.sh index b6daf7b96..d8e26dd8c 100755 --- a/fuzzers/path_afl/filterCFG_Callmap_script.sh +++ b/fuzzers/path_afl/filterCFG_Callmap_script.sh @@ -1,5 +1,17 @@ #!/bin/bash +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # 获取 PUT 的反汇编结果 objdump -d path_to_put > PUT_decomp.txt diff --git a/fuzzers/path_afl/filterCallmap.py b/fuzzers/path_afl/filterCallmap.py index ca41b4297..1827f9098 100755 --- a/fuzzers/path_afl/filterCallmap.py +++ b/fuzzers/path_afl/filterCallmap.py @@ -1,3 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import sys import re @@ -34,6 +46,6 @@ # 使用 strip() 去除每行末尾的换行符 line = line.strip() bbid_match = re.search(r'(\d+).*', line) - bbid = int(bbid_match.group(1)) + bbid = int(bbid_match.group(1) if bbid_match is not None else -1) if bbid in bbdict: written_file.write(line + "\n") diff --git a/fuzzers/path_afl/fuzzer.py b/fuzzers/path_afl/fuzzer.py index f5079f78a..f254fef4f 100644 --- a/fuzzers/path_afl/fuzzer.py +++ b/fuzzers/path_afl/fuzzer.py @@ -1,5 +1,3 @@ -# Copyright 2020 Google LLC -# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -53,7 +51,6 @@ def build(): text=True) print(result.stdout) print(result.stderr) - ... subprocess.run( 'cat cfg_filtered.txt | grep \"Function: \" | nl -v 0 | awk \'{print $1, $3, $4, $5, $6, $7, $8, $9}\' > function_list.txt', shell=True, From 3401afbc8eb8466321ba814fd4aaee18dca483eb Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Wed, 22 Jan 2025 21:25:42 -0500 Subject: [PATCH 04/23] delete unused files --- fuzzers/path_afl/convert.cpp | 337 ------------------- fuzzers/path_afl/filterCFG.py | 126 ------- fuzzers/path_afl/filterCFG_Callmap_script.sh | 23 -- fuzzers/path_afl/filterCallmap.py | 51 --- fuzzers/path_afl/fuzzer.py | 3 + 5 files changed, 3 insertions(+), 537 deletions(-) delete mode 100644 fuzzers/path_afl/convert.cpp delete mode 100755 fuzzers/path_afl/filterCFG.py delete mode 100755 fuzzers/path_afl/filterCFG_Callmap_script.sh delete mode 100755 fuzzers/path_afl/filterCallmap.py diff --git a/fuzzers/path_afl/convert.cpp b/fuzzers/path_afl/convert.cpp deleted file mode 100644 index 93a0a7fe7..000000000 --- a/fuzzers/path_afl/convert.cpp +++ /dev/null @@ -1,337 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// C++ 接口 ------------------------------------------------------------------- start -#define FUNC_ID_LEN 256 - -// CFG 结构体只需要在 cfg.txt 中解析获取 -// CYHNO_TE: 这里需要一个二进制文件 -typedef struct CFG { - // int funcID; funcID 就是 CFG 在 cfg_arr 中的下标索引 - char function_name[FUNC_ID_LEN]; // 函数的字符串形式,整数形式就是 cfg_arr 的下标 - int entry; // 整数,表示函数入点 block - int exit; // 整数,表示函数出点 block -} CFG; - -// calls 需要 processed_mapping_table.txt 中获取 -// successor_size 从 cfg.txt 中获取 -// successors_arr 从 cfg.txt 中获取 -// CYHNO_TE: 这里需要一个二进制文件 -typedef struct BlockEntry { - // int bbID; 基本块ID 就是在 block_arr 中的下标索引 - int calls; // -1 时,表示没有调用任何函数;非负数时,表示调用的函数的 funcID,也就是在 cfg_arr 中的下标索引 - int successor_size; // 表示这个基本块拥有的 successors 数量 - int *successors_arr; // 这个基本块的 successors_arr 数组 -} BlockEntry; - -// cfg_size 只需要过一遍 function_list.txt 即可,内存也那样分配就好 -// block_size 只需要过一遍 processed_mapping_table.txt 即可,内存也那样分配就好 -// CYHNO_TE: 这是顶层结构体 -// CYHNO_TE: 这里需要一个二进制文件 -typedef struct Top_Level { - int cfg_size; // cfg 的数量 - CFG *cfg_arr; // cfg 数组 - int block_size; // blocks 总数 - BlockEntry **block_arr; // block 数组 -} Top_Level; -// C++ 接口 ------------------------------------------------------------------- end - -void dump_block(BlockEntry *block) { - std::cout << "block->calls = " << block->calls << std::endl; - std::cout << "block->successor_size = " << block->successor_size << std::endl; - for (int i = 0; i < block->successor_size; i++) { - printf("block->successor_arr[%d] = %d\n", i, block->successors_arr[i]); - } -} - -void dump_cfg(CFG *cfg) { - std::string funcname(cfg->function_name); - std::cout << "cfg->function_name = " << funcname << std::endl; - std::cout << "cfg->entry = " << cfg->entry << std::endl; - std::cout << "cfg->exit = " << cfg->exit << std::endl; -} - -void dump_top(Top_Level *top) { - std::cout << "top->cfg_size = " << top->cfg_size << std::endl; - std::cout << "top->block_size = " << top->block_size << std::endl; - for(int i = 0; i < top->cfg_size; i++) { - dump_cfg(&(top->cfg_arr[i])); - } - for(int i = 0; i < top->block_size; i++) { - if(top->block_arr[i]) { - std::cout << "BB " << i << std::endl; - dump_block(top->block_arr[i]); - } - } -} - -void store_top(Top_Level *top); - -// 去除字符串首尾的空白字符 -std::string trim(const std::string& str) { - size_t first = str.find_first_not_of(" \t\n\r"); - size_t last = str.find_last_not_of(" \t\n\r"); - if (first == std::string::npos || last == std::string::npos) { - return ""; - } - return str.substr(first, last - first + 1); -} - -int main() { - - // 0. 一个顶层,收集完数据后要被 dump 出去 - Top_Level top; - - // 1. 读取 bbnum.txt 获知 PUT 的基本块总数,给 top.block_arr 分配空间,并初始化 top.block_arr - int numBB = -1; - FILE *file = fopen("bbnum.txt", "r"); - assert(file); - assert(fscanf(file, "%d", &numBB) == 1); - fclose(file); - top.block_size = numBB; - top.block_arr = (BlockEntry **) malloc(sizeof(BlockEntry *) * numBB); - memset(top.block_arr, 0, sizeof(BlockEntry *) * numBB); - - // 2. 构建一个 function_name -> integer 的映射 (需要读取 function_list.txt,原因后续填满 BasicBlock 需要使用) - // 同时给 cfg_arr 分配内存空间 - std::unordered_map funcname_int; - std::ifstream function_list_file("function_list.txt"); - assert(function_list_file.is_open()); // 检查文件是否成功打开h - std::string line; - std::string firstPart; - std::string secondPart; - - while (std::getline(function_list_file, line)) { // 逐行读取文件内容 - std::string input = line; - size_t pos = input.find(' '); // 查找第一个空格的位置 - if (pos != std::string::npos) { // 如果找到了空格 - firstPart = input.substr(0, pos); // 提取第一个空格之前的部分 - secondPart = input.substr(pos + 1); // 提取第一个空格之后的部分 - } else { - std::cout << "未找到空格" << std::endl; - } - - // 函数名 -> funcid 映射 - firstPart = trim(firstPart); - secondPart = trim(secondPart); - funcname_int[secondPart] = std::stoi(firstPart); - } - - // 获取函数的总数,然后给 cfg_arr 分配内存空间 - int numfunction = std::stoi(firstPart) + 1; - top.cfg_size = numfunction; - top.cfg_arr = (CFG *) malloc(sizeof(CFG) * numfunction); - - function_list_file.close(); // 关闭文件 - - // // 下面这段代码用来打印 funcname_int 里的数据 - // for (const auto& pair : funcname_int) { - // std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl; - // } - - // 3. 接下来的任务:填充 BlockEntry 数组 的calls属性 -------------------------------------------------------- start - std::ifstream callmap_file("callmap_filtered.txt"); - line = ""; - assert(callmap_file.is_open()); // 检查文件是否成功打开 - while (std::getline(callmap_file, line)) { // 逐行读取文件内容 - std::string input = trim(line); - size_t pos = input.find(' '); // 查找第一个空格的位置 - if (pos != std::string::npos) { // 如果找到了空格 - firstPart = input.substr(0, pos); // 提取第一个空格之前的部分 - secondPart = input.substr(pos + 1); // 提取第一个空格之后的部分 - } else { - // 未找到空格说明这个基本块号不是 call 基本块 - // 此时,input 本身就是 first part(BBID) - firstPart = input; - secondPart = ""; - } - - top.block_arr[std::stoi(firstPart)] = (BlockEntry *) malloc(sizeof(BlockEntry)); - - size_t found = secondPart.find("Calls"); - - if (found != std::string::npos) { - size_t pos = secondPart.find("Calls "); - assert(pos != std::string::npos); - std::string result = secondPart.substr(pos + std::strlen("Calls ")); - // std::cout << result << std::endl; - result = trim(result); - - if (funcname_int.count(result) > 0) { - top.block_arr[std::stoi(firstPart)]->calls = funcname_int[result]; - } else { - top.block_arr[std::stoi(firstPart)]->calls = -2; // -2 表示是 C 库函数 - } - // std::cout << "The string contains the word 'calls'." << std::endl; - } else { - top.block_arr[std::stoi(firstPart)]->calls = -1; - } - } - - callmap_file.close(); // 关闭文件 - // 3. 接下来的任务:填充 BlockEntry 数组 的calls属性 -------------------------------------------------------- end - - // 接下来的任务:填满 CFG 数组 -------------------------------------------------------------------- start - // 第二遍,这一次的目的是填满 cfg_arr (单独读取 cfg.txt 即可) --- doing - line = ""; // zekun_processed_mapping_table.txt 的每一行内容 - firstPart = ""; - secondPart = ""; - - std::ifstream cfg_file("cfg_filtered.txt"); - - int func_id = 0; - - assert(cfg_file.is_open()); - - bool justGetIn = false; // 一个 flag,表示是否刚刚进入一个函数,用来寻找 entryblock - bool waitForLast = false; // 一个 flag,标识是否在等待一个函数结束,用来寻找 exitblock - int exitblockStore = -1; // 用来储存可能是 exitblock 的整数 - int curBBID = -1; // 当前基本块的 BBID - - while (std::getline(cfg_file, line)) { // 逐行读取文件内容 - - size_t pos = line.find(' '); // 查找第一个空格的位置 - firstPart = line.substr(0, pos); - secondPart = line.substr(pos + 1); // 提取第一个空格之后的部分 - - size_t start = line.find_first_not_of(" \t\n\r"); - size_t end = line.find_last_not_of(" \t\n\r"); - - if (start != std::string::npos && end != std::string::npos) { - firstPart = firstPart.substr(start, end - start + 1); - secondPart = secondPart.substr(start, end - start + 1); - } - - if (firstPart == "Function:") { - - // printf("waitForLast = %d, exitblockStore = %d\n", waitForLast, exitblockStore); - - if (waitForLast) { - top.cfg_arr[func_id - 1].exit = exitblockStore; - // printf("exitBlock = %d\n", top.cfg_arr[func_id].exit); - waitForLast = false; - } - - strcpy(top.cfg_arr[func_id].function_name, secondPart.c_str()); - // printf("funcname = %s\n", top.cfg_arr[func_id].function_name); - justGetIn = true; - func_id++; - } - else if (firstPart == "BasicBlock:") { - - // std::cout << "secondPart = " << secondPart << std::endl; - curBBID = std::stoi(secondPart); - - // printf("func_id = %d, justGetIn = %d, std::stoi(secondPart) = %d\n", func_id, justGetIn, std::stoi(secondPart)); - - if(justGetIn) { - top.cfg_arr[func_id - 1].entry = std::stoi(secondPart); - // printf("entryBlock = %d\n", top.cfg_arr[func_id].entry); - justGetIn = false; - } - - waitForLast = true; - exitblockStore = std::stoi(secondPart); - - } - else if (firstPart == "Successors:") { - // 填满 BlockEntry 的 successor_size 和 successors_arr - - std::vector words; - std::vector integer_words; - - size_t start = 0, end = 0; - while ((end = secondPart.find(' ', start)) != std::string::npos) { - words.push_back(secondPart.substr(start, end - start)); - start = end + 1; - } - words.push_back(secondPart.substr(start)); // 添加最后一个单词 - // 把 vector 中的单词字符串转为整数 vector - for (const auto& w : words) { - if (!w.empty() && w != "Successors:") { - int num = std::stoi(w); - integer_words.push_back(num); - } - } - - assert(top.block_arr[curBBID]); - top.block_arr[curBBID]->successor_size = integer_words.size(); - top.block_arr[curBBID]->successors_arr = (int *) malloc(sizeof(int) * integer_words.size()); - - for(int i = 0; i < integer_words.size(); i++) { - top.block_arr[curBBID]->successors_arr[i] = integer_words[i]; - } - } - // 不需要 else,因为有可能是 "" 空字符串 - } - - top.cfg_arr[func_id - 1].exit = exitblockStore; - cfg_file.close(); - // top.cfg_arr[func_id].exit = exitblockStore; - // printf("exitBlock = %d\n", top.cfg_arr[func_id].exit); - // 接下来的任务:填满 CFG 数组 -------------------------------------------------------------------- end - checked - - - // 2. 读取 function_list.txt,构建整个映射表 --------------------------------------------------- end - - // 3. 这里可以尝试 dump top 的 Readable 形式 - dump_top(&top); - // 3. 这里可以尝试把 top 里的内容储存到二进制文件里 - store_top(&top); - - return 0; -} - -void store_top(Top_Level *top) { - FILE *file = fopen("top.bin", "wb"); - if (file != NULL) { - fwrite(top, sizeof(Top_Level), 1, file); - fwrite(top->cfg_arr, sizeof(CFG) * top->cfg_size, 1, file); - - int count = 0; - for(int i = 0; i < top->block_size; i++) { - if(top->block_arr[i]) { - count++; - } - } - fwrite(&count, sizeof(int), 1, file); - - for(int i = 0; i < top->block_size; i++) { - if(top->block_arr[i]) { - fwrite(&i, sizeof(int), 1, file); - fwrite(top->block_arr[i], sizeof(BlockEntry), 1, file); - } - } - - for(int i = 0; i < top->block_size; i++) { - if(top->block_arr[i]) { - fwrite(&i, sizeof(int), 1, file); - fwrite(top->block_arr[i]->successors_arr, sizeof(int) * top->block_arr[i]->successor_size, 1, file); - } - } - - fclose(file); - // printf("Data has been dumped into top.bin\n"); - } else { - perror("Failed to open file for writing"); - } -} diff --git a/fuzzers/path_afl/filterCFG.py b/fuzzers/path_afl/filterCFG.py deleted file mode 100755 index 281d97752..000000000 --- a/fuzzers/path_afl/filterCFG.py +++ /dev/null @@ -1,126 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import re - -# 检查是否传入了足够的参数(至少需要三个参数加上脚本名称) -assert (len(sys.argv) == 4) -# 打印第一个、第二个和第三个参数 -# python3 filterCFG.py cfg.txt PUT_decomp.txt cfg_filtered.txt -print(f"参数1: {sys.argv[1]}") -print(f"参数2: {sys.argv[2]}") -print(f"参数3: {sys.argv[3]}") - -# 思考代码: -# 1.先把整个 cfg.txt 读入内存,按照 {key="第一个基本块的块号", value=[bool: false, "CFG字符串列表"]} 来储存 -# 2.扫描反汇编代码,扫描每个函数 -# 1.如果函数中没有对 path_inject_eachbb 的调用,那说明不是 PUT 源码,下一个函数 -# 2.如果有,那么看第一个 path_inject_eachbb 的参数,随后使用这个参数索引到之前的字典 -# 把字典 value 里对应的 false 设置为 true,随后继续下一个函数,直到扫描完整个反汇编文件 -# 3.扫描一遍之前的字典,把所有 bool = true 的 CFG字符串列表 dump 到 cfg_filtered.txt 里 - -# 1.先把整个 cfg.txt 读入内存,按照 {key="第一个基本块的块号", value=[bool: false, "CFG字符串列表"]} 来储存 -justEnterFunction = False # 这个flag用来识别每个函数的第一个基本块 entrypoing -with open(sys.argv[1], 'r', encoding='utf-8') as file: - wholeCFG = {} - singleCFG = [] - firstBBID = -1 - for line in file: - # 使用 strip() 去除每行末尾的换行符 - line = line.strip() - if "Function: " in line: - # 如果 singleCFG 不为空,那么把它放进 wholeCFG 字典里 - if singleCFG: - wholeCFG[firstBBID] = [False, singleCFG] - singleCFG = [] - justEnterFunction = True - else: - if justEnterFunction: - match = re.search(r'BasicBlock: (\d+)', line) - assert (match) - justEnterFunction = False - firstBBID = int(match.group(1)) - else: - pass - # do nothing - singleCFG.append(line) - file.close() - -# 循环结束后,还有最后一个函数的 CFG 没有加入 wholeCFG,现在加进去 -wholeCFG[firstBBID] = [False, singleCFG] - -# 2.扫描反汇编代码,扫描每个函数 -# 1.如果函数中没有对 path_inject_eachbb 的调用,那说明不是 PUT 源码,下一个函数 -# 2.如果有,那么看第一个 path_inject_eachbb 的参数,随后使用这个参数索引到之前的字典 -# 把字典 value 里对应的 false 设置为 true,随后继续下一个函数,直到扫描完整个反汇编文件 -justEnterFunction = False # 这个flag用来识别是否在一个函数内 -with open(sys.argv[2], 'r', encoding='utf-8') as file: - for line in file: - # 使用 strip() 去除每行末尾的换行符 - line = line.strip() - funcNameMatch = re.match(r'^[0-9a-fA-F]+ <[^>]+>:', line) - if funcNameMatch: - # if justEnterFunction: - # 若此时 justEnterFunction = True,说明上一个函数中不包含 callq path_inject_eachbb,不做处理直接skip - # 若此时 justEnterFunction = False,说明上一个函数中包含 callq path_inject_eachbb 已被找到,不做处理直接skip - justEnterFunction = True - elif justEnterFunction: - path_inject_match = re.search( - r'call?\s+[0-9a-fA-F]+\s+', line) - if path_inject_match: - # 到这里已经找到这个函数的第一个 callq path_inject_eachbb 了,除了重置 justEnterFunction, - # 还要对 step1 里得到的字典做相应的处理 - # 此时,previousline 有两种可能: - # 1. xor %edi,%edi - # 2. mov $0x3208,%edi - print('matched!') - xor_match = re.search(r'xor\s+%edi,%edi', previousline) - mov_match = re.search(r'mov\s+\$(0x[0-9a-fA-F]+),%edi', - previousline) - assert (xor_match or mov_match) - assert (not (xor_match and mov_match)) - if xor_match: - # 如果 previousline = xor 汇编指令,path_inject_eachbb 的参数是 0 - arg = 0 - else: - arg = int(mov_match.group(1), 16) - print(f"arg: {arg} {mov_match.group(1)}") - wholeCFG[arg][0] = True - justEnterFunction = False - else: - # 如果在函数里还有没有遇到 callq path_inject_eachbb,那么就继续读下一行 - pass - else: - # 如果既没有匹配到函数头,justEnterFunction = False - # 说明这个函数的 第一个callq path_inject_eachbb 已经被找到了 - # 继续下一行文字,直到进入到下一个函数为止 - pass - # 记录当前行,这一行的目的是在找到 callq path_inject_eachbb 后,寻找这个函数的参数 - previousline = line - file.close() - -# # 打印 wholeCFG -# print(wholeCFG) - -# 3.扫描一遍之前的字典,把所有 bool = true 的 CFG字符串列表 dump 到 cfg_filtered.txt 里 -# 打开文件以写入模式('w') -with open(sys.argv[3], "w") as file: - for key, value in wholeCFG.items(): - if value[0]: - for line in value[1]: - file.write(line + "\n") - file.close() - -# xor %esi,%esi -# 2038f6: bf 08 32 00 00 mov $0x3208,%edi -# 2038fb: e8 a0 e4 e0 00 callq 1011da0 diff --git a/fuzzers/path_afl/filterCFG_Callmap_script.sh b/fuzzers/path_afl/filterCFG_Callmap_script.sh deleted file mode 100755 index d8e26dd8c..000000000 --- a/fuzzers/path_afl/filterCFG_Callmap_script.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# 获取 PUT 的反汇编结果 -objdump -d path_to_put > PUT_decomp.txt - -# 运行过滤CFG python 脚本 -python3 filterCFG.py cfg.txt PUT_decomp.txt cfg_filtered.txt - -# 运行过滤Callmap python 脚本 -python3 filterCallmap.py cfg_filtered.txt callmap.txt callmap_filtered.txt - diff --git a/fuzzers/path_afl/filterCallmap.py b/fuzzers/path_afl/filterCallmap.py deleted file mode 100755 index 1827f9098..000000000 --- a/fuzzers/path_afl/filterCallmap.py +++ /dev/null @@ -1,51 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import re - -# 检查是否传入了足够的参数(至少需要三个参数加上脚本名称) -assert (len(sys.argv) == 4) -# 打印第一个、第二个和第三个参数 -# python3 filterCallmap.py cfg_filtered.txt callmap.txt callmap_filtered.txt -# print(f"参数1: {sys.argv[1]}") -# print(f"参数2: {sys.argv[2]}") -# print(f"参数3: {sys.argv[3]}") - -# 思考代码: -# 1.读取 cfg_filtered.txt,扫描每个 BasicBlock,记录它们的编号,存到一个字典里 -# 2.读取 callmap.txt 的每一行,根据读到的 BBID 去比较字典里是否存在这个 BBID,来决定是否把这行输出到 callmap_filtered.txt 里 - -# 1.读取 cfg_filtered.txt,扫描每个 BasicBlock,记录它们的编号,存到一个字典里 -bbdict = {} -with open(sys.argv[1], 'r', encoding='utf-8') as file: - for line in file: - # 使用 strip() 去除每行末尾的换行符 - line = line.strip() - BasicBlock_match = re.search(r'BasicBlock: (\d+)', line) - if BasicBlock_match: - bbid = int(BasicBlock_match.group(1)) - bbdict[bbid] = 1 - else: - # 如果这行不包含 "BasicBlock",那么不做任何事情 - pass - -# 2.读取 callmap.txt 的每一行,根据读到的 BBID 去比较字典里是否存在这个 BBID,来决定是否把这行输出到 callmap_filtered.txt 里 -written_file = open(sys.argv[3], 'w') -with open(sys.argv[2], 'r', encoding='utf-8') as file: - for line in file: - # 使用 strip() 去除每行末尾的换行符 - line = line.strip() - bbid_match = re.search(r'(\d+).*', line) - bbid = int(bbid_match.group(1) if bbid_match is not None else -1) - if bbid in bbdict: - written_file.write(line + "\n") diff --git a/fuzzers/path_afl/fuzzer.py b/fuzzers/path_afl/fuzzer.py index f254fef4f..f5079f78a 100644 --- a/fuzzers/path_afl/fuzzer.py +++ b/fuzzers/path_afl/fuzzer.py @@ -1,3 +1,5 @@ +# Copyright 2020 Google LLC +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -51,6 +53,7 @@ def build(): text=True) print(result.stdout) print(result.stderr) + ... subprocess.run( 'cat cfg_filtered.txt | grep \"Function: \" | nl -v 0 | awk \'{print $1, $3, $4, $5, $6, $7, $8, $9}\' > function_list.txt', shell=True, From 8709300ed1ecc1f97a8bda73986464ac21482ddb Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Wed, 22 Jan 2025 21:34:03 -0500 Subject: [PATCH 05/23] add request --- service/experiment-requests.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/service/experiment-requests.yaml b/service/experiment-requests.yaml index fe0efe2a2..472cc47c9 100644 --- a/service/experiment-requests.yaml +++ b/service/experiment-requests.yaml @@ -20,6 +20,12 @@ # Please add new experiment requests towards the top of this file. # +- experiment: 2025-01-22-path-afl + description: "Evaluate path_afl" + fuzzers: + - aflplusplus + - path_afl + - experiment: 2023-06-12-aflpp description: "Benchmark afl++ releases and newmutation" fuzzers: From 76a0d0d31c207c719e3a443fee8fec2ae3a3d660 Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Wed, 22 Jan 2025 22:18:11 -0500 Subject: [PATCH 06/23] add dummy comment --- service/gcbrun_experiment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/service/gcbrun_experiment.py b/service/gcbrun_experiment.py index bbebcf1b9..ef28bc768 100644 --- a/service/gcbrun_experiment.py +++ b/service/gcbrun_experiment.py @@ -16,6 +16,7 @@ """Entrypoint for gcbrun into run_experiment. This script will get the command from the last PR comment containing "/gcbrun" and pass it to run_experiment.py which will run an experiment.""" +# a dummy comment! import logging import os From 0508c7f47fa331e0642b361430fed1f3060538ca Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Wed, 22 Jan 2025 22:21:22 -0500 Subject: [PATCH 07/23] revert experiment requests --- service/experiment-requests.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/service/experiment-requests.yaml b/service/experiment-requests.yaml index 472cc47c9..fe0efe2a2 100644 --- a/service/experiment-requests.yaml +++ b/service/experiment-requests.yaml @@ -20,12 +20,6 @@ # Please add new experiment requests towards the top of this file. # -- experiment: 2025-01-22-path-afl - description: "Evaluate path_afl" - fuzzers: - - aflplusplus - - path_afl - - experiment: 2023-06-12-aflpp description: "Benchmark afl++ releases and newmutation" fuzzers: From 114976463d8800f027749edbdf605c947b5cdc2d Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Wed, 22 Jan 2025 22:48:05 -0500 Subject: [PATCH 08/23] solve lint warnings --- fuzzers/path_afl/fuzzer.py | 137 ++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 70 deletions(-) diff --git a/fuzzers/path_afl/fuzzer.py b/fuzzers/path_afl/fuzzer.py index f5079f78a..49489f7e7 100644 --- a/fuzzers/path_afl/fuzzer.py +++ b/fuzzers/path_afl/fuzzer.py @@ -16,22 +16,23 @@ import os import shutil import subprocess + from fuzzers import utils def prepare_build_environment(): """Set environment variables used to build targets for pathAFL-based fuzzers.""" - os.environ['LD_LIBRARY_PATH'] = '/path-afl' - os.environ['CC'] = '/path-afl/afl-clang-fast' - os.environ['CXX'] = '/path-afl/afl-clang-fast++' + os.environ["LD_LIBRARY_PATH"] = "/path-afl" + os.environ["CC"] = "/path-afl/afl-clang-fast" + os.environ["CXX"] = "/path-afl/afl-clang-fast++" current_directory = os.getcwd() os.environ["BBIDFILE"] = os.path.join(current_directory, "bbid.txt") os.environ["CALLMAPFILE"] = os.path.join(current_directory, "callmap.txt") os.environ["CFGFILE"] = os.path.join(current_directory, "cfg.txt") - os.environ["FUZZER"] = '/path-afl' - os.environ["AFL_LLVM_CALLER"] = '1' - os.environ['FUZZER_LIB'] = '/libAFLDriver.a' + os.environ["FUZZER"] = "/path-afl" + os.environ["AFL_LLVM_CALLER"] = "1" + os.environ["FUZZER_LIB"] = "/libAFLDriver.a" def build(): @@ -40,110 +41,106 @@ def build(): utils.build_benchmark() - subprocess.run('cat cfg.txt | grep "BasicBlock: " | wc -l > bbnum.txt', - shell=True, - check=True) + subprocess.run( + 'cat cfg.txt | grep "BasicBlock: " | wc -l > bbnum.txt', + shell=True, + check=True, + ) print(f"/out/{os.getenv('FUZZ_TARGET')}") - result = subprocess.run([ - "bash", '/path-afl/fuzzing_support/filterCFGandCallmap.sh', - f"/out/{os.getenv('FUZZ_TARGET')}" - ], - check=False, - capture_output=True, - text=True) + result = subprocess.run( + [ + "bash", + "/path-afl/fuzzing_support/filterCFGandCallmap.sh", + f"/out/{os.getenv('FUZZ_TARGET')}", + ], + check=False, + capture_output=True, + text=True, + ) print(result.stdout) print(result.stderr) - ... subprocess.run( - 'cat cfg_filtered.txt | grep \"Function: \" | nl -v 0 | awk \'{print $1, $3, $4, $5, $6, $7, $8, $9}\' > function_list.txt', + "cat cfg_filtered.txt | grep \"Function: \" | nl -v 0 | " + "awk '{print $1, $3, $4, $5, $6, $7, $8, $9}' > function_list.txt", shell=True, - check=True) + check=True, + ) subprocess.run( - 'g++ -I/path-afl/fuzzing_support /path-afl/fuzzing_support/convert.cpp -o convert', + "g++ -I/path-afl/fuzzing_support " + "/path-afl/fuzzing_support/convert.cpp -o convert", shell=True, - check=True) - subprocess.run('./convert', shell=True, check=True) + check=True, + ) + subprocess.run("./convert", shell=True, check=True) - print('[post_build] Copying afl-fuzz to $OUT directory') + print("[post_build] Copying afl-fuzz to $OUT directory") # Copy out the afl-fuzz binary as a build artifact. - shutil.copy('/path-afl/libpath_reduction.so', os.environ['OUT']) - shutil.copy('/path-afl/afl-fuzz', os.environ['OUT']) - shutil.copy('./top.bin', os.environ['OUT']) - shutil.copy('/libpython3.8.so.1.0', os.environ['OUT']) - try: - src = '/usr/lib/llvm-17/lib' - dst = os.environ['OUT'] - shutil.copytree(src, dst, dirs_exist_ok=True) - except KeyError: - print("Environment variable 'OUT' is not set.") - assert False - except FileNotFoundError as e: - print(f"Source directory not found: {e}") - assert False - except PermissionError as e: - print(f"Permission error: {e}") - assert False - except Exception as e: - print(f"An error occurred: {e}") - assert False + shutil.copy("/path-afl/libpath_reduction.so", os.environ["OUT"]) + shutil.copy("/path-afl/afl-fuzz", os.environ["OUT"]) + shutil.copy("./top.bin", os.environ["OUT"]) + shutil.copy("/libpython3.8.so.1.0", os.environ["OUT"]) + src = "/usr/lib/llvm-17/lib" + dst = os.environ["OUT"] + shutil.copytree(src, dst, dirs_exist_ok=True) def prepare_fuzz_environment(input_corpus): """Prepare to fuzz with AFL or another AFL-based fuzzer.""" # Tell AFL to not use its terminal UI so we get usable logs. - os.environ['AFL_NO_UI'] = '1' + os.environ["AFL_NO_UI"] = "1" # Skip AFL's CPU frequency check (fails on Docker). - os.environ['AFL_SKIP_CPUFREQ'] = '1' + os.environ["AFL_SKIP_CPUFREQ"] = "1" # No need to bind affinity to one core, Docker enforces 1 core usage. - os.environ['AFL_NO_AFFINITY'] = '1' + os.environ["AFL_NO_AFFINITY"] = "1" # AFL will abort on startup if the core pattern sends notifications to # external programs. We don't care about this. - os.environ['AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES'] = '1' + os.environ["AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES"] = "1" # Don't exit when crashes are found. This can happen when corpus from # OSS-Fuzz is used. - os.environ['AFL_SKIP_CRASHES'] = '1' + os.environ["AFL_SKIP_CRASHES"] = "1" # Shuffle the queue - os.environ['AFL_SHUFFLE_QUEUE'] = '1' - os.environ['CFG_BIN_FILE'] = './top.bin' - os.environ[ - 'LD_LIBRARY_PATH'] = f'./lib:{os.getcwd()}:{os.environ["LD_LIBRARY_PATH"]}' + os.environ["AFL_SHUFFLE_QUEUE"] = "1" + os.environ["CFG_BIN_FILE"] = "./top.bin" + os.environ["LD_LIBRARY_PATH"] = ( + f'./lib:{os.getcwd()}:{os.environ["LD_LIBRARY_PATH"]}') # AFL needs at least one non-empty seed to start. utils.create_seed_file_for_empty_corpus(input_corpus) -def run_afl_fuzz(input_corpus, - output_corpus, - target_binary, - additional_flags=None, - hide_output=False): +def run_afl_fuzz( + input_corpus, + output_corpus, + target_binary, + hide_output=False, +): """Run afl-fuzz.""" # Spawn the afl fuzzing process. - print('[run_afl_fuzz] Running target with afl-fuzz') + print("[run_afl_fuzz] Running target with afl-fuzz") command = [ - './afl-fuzz', - '-i', + "./afl-fuzz", + "-i", input_corpus, - '-o', + "-o", output_corpus, # Use no memory limit as ASAN doesn't play nicely with one. - '-m', - 'none', - '-t', - '1000+', # Use same default 1 sec timeout, but add '+' to skip hangs. + "-m", + "none", + "-t", + "1000+", # Use same default 1 sec timeout, but add '+' to skip hangs. ] dictionary_path = utils.get_dictionary_path(target_binary) if dictionary_path: - command.extend(['-x', dictionary_path]) + command.extend(["-x", dictionary_path]) command += [ - '--', + "--", target_binary, # Pass INT_MAX to afl the maximize the number of persistent loops it # performs. - '2147483647' + "2147483647", ] - print('[run_afl_fuzz] Running command: ' + ' '.join(command)) + print("[run_afl_fuzz] Running command: " + " ".join(command)) output_stream = subprocess.DEVNULL if hide_output else None subprocess.check_call(command, stdout=output_stream, stderr=output_stream) @@ -152,6 +149,6 @@ def fuzz(input_corpus, output_corpus, target_binary): """Run afl-fuzz on target.""" prepare_fuzz_environment(input_corpus) - os.environ['K'] = '42' + os.environ["K"] = "42" run_afl_fuzz(input_corpus, output_corpus, target_binary) From b4ffbbe6ff90db9ca86df2a538992731aadc2d6d Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Wed, 22 Jan 2025 22:49:37 -0500 Subject: [PATCH 09/23] add another dummy comment --- service/gcbrun_experiment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/service/gcbrun_experiment.py b/service/gcbrun_experiment.py index ef28bc768..5958aa60e 100644 --- a/service/gcbrun_experiment.py +++ b/service/gcbrun_experiment.py @@ -17,6 +17,7 @@ from the last PR comment containing "/gcbrun" and pass it to run_experiment.py which will run an experiment.""" # a dummy comment! +# another dummy comment! import logging import os From 65446e79a95cc5b7ebd070c71b2c1cbb2ca807d3 Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Wed, 29 Jan 2025 23:54:13 -0500 Subject: [PATCH 10/23] change path reduction version --- fuzzers/path_afl/builder.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzers/path_afl/builder.Dockerfile b/fuzzers/path_afl/builder.Dockerfile index 140d0da0e..ad2072a7e 100644 --- a/fuzzers/path_afl/builder.Dockerfile +++ b/fuzzers/path_afl/builder.Dockerfile @@ -85,7 +85,7 @@ RUN rm -rf /usr/local/share/clang RUN git clone -b fx-no-tail-opt1 https://github.com/fEst1ck/path-cov.git /path-cov RUN cd /path-cov && \ - git checkout bb900e89e14766ebd9d4af27cae0862bdb37de9b && \ + git checkout ae6df67fee70abcada256f9519932237143ff8b6 && \ cargo build --release RUN git clone -b fixversion https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl From b4334a6a5fb3a903a48b0c211eca5d97db7079a3 Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Fri, 31 Jan 2025 01:37:37 -0500 Subject: [PATCH 11/23] disable cmplog in aflpp --- fuzzers/aflplusplus/fuzzer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzers/aflplusplus/fuzzer.py b/fuzzers/aflplusplus/fuzzer.py index 7016da75e..cb2ddbdcd 100755 --- a/fuzzers/aflplusplus/fuzzer.py +++ b/fuzzers/aflplusplus/fuzzer.py @@ -241,7 +241,7 @@ def fuzz(input_corpus, target_binary, flags=tuple(), skip=False, - no_cmplog=False): # pylint: disable=too-many-arguments + no_cmplog=True): # pylint: disable=too-many-arguments """Run fuzzer.""" # Calculate CmpLog binary path from the instrumented target binary. target_binary_directory = os.path.dirname(target_binary) From 155608738af11eb42b0ff64ab4d694a100eae9d5 Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Mon, 3 Feb 2025 20:09:49 -0500 Subject: [PATCH 12/23] disable afl++ cmplog --- fuzzers/aflplusplus/fuzzer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzzers/aflplusplus/fuzzer.py b/fuzzers/aflplusplus/fuzzer.py index cb2ddbdcd..8fe240500 100755 --- a/fuzzers/aflplusplus/fuzzer.py +++ b/fuzzers/aflplusplus/fuzzer.py @@ -262,8 +262,8 @@ def fuzz(input_corpus, flags += ['-x', './afl++.dict'] # Move the following to skip for upcoming _double tests: - if os.path.exists(cmplog_target_binary) and no_cmplog is False: - flags += ['-c', cmplog_target_binary] + # if os.path.exists(cmplog_target_binary) and no_cmplog is False: + # flags += ['-c', cmplog_target_binary] #os.environ['AFL_IGNORE_TIMEOUTS'] = '1' os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' From 2edd3f013e25271ab0a7f95af8ebc0487ec85615 Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Sat, 8 Feb 2025 17:53:04 -0500 Subject: [PATCH 13/23] update driver to clear hash pool --- fuzzers/path_afl/builder.Dockerfile | 6 ++++-- fuzzers/path_afl/fuzzer.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fuzzers/path_afl/builder.Dockerfile b/fuzzers/path_afl/builder.Dockerfile index ad2072a7e..5c35aaecf 100644 --- a/fuzzers/path_afl/builder.Dockerfile +++ b/fuzzers/path_afl/builder.Dockerfile @@ -96,7 +96,7 @@ RUN cd /path-afl && \ which clang-17 && \ which clang && \ clang --version && \ - clang++ -stdlib=libstdc++ -c hashcompare.cpp && \ + clang++ -stdlib=libc++ -c hashcompare.cpp && \ ar rcs libhashcompare.a hashcompare.o && \ cp /path-cov/target/release/libpath_reduction.so . @@ -108,7 +108,7 @@ RUN cd /path-afl && \ export AFL_NO_X86=1 && \ unset CFLAGS CXXFLAGS && \ PYTHON_INCLUDE=/ && \ - LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lstdc++ -lpath_reduction" make + LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lc++ -lpath_reduction" make # RUN export CC=clang && \ # export CXX=clang++ && \ # export AFL_NO_X86=1 && \ @@ -121,6 +121,8 @@ RUN apt install g++ # Set AFL_NO_X86 to skip flaky tests. RUN cd /path-afl && cp utils/aflpp_driver/libAFLDriver.a / +RUN cp /path-afl/hashcompare.o / + RUN cp /usr/lib/x86_64-linux-gnu/libpython3.8.so.1.0 / RUN cp /usr/lib/llvm-17/lib/libc++.so.1 / diff --git a/fuzzers/path_afl/fuzzer.py b/fuzzers/path_afl/fuzzer.py index 49489f7e7..0db1eb7e9 100644 --- a/fuzzers/path_afl/fuzzer.py +++ b/fuzzers/path_afl/fuzzer.py @@ -32,7 +32,7 @@ def prepare_build_environment(): os.environ["CFGFILE"] = os.path.join(current_directory, "cfg.txt") os.environ["FUZZER"] = "/path-afl" os.environ["AFL_LLVM_CALLER"] = "1" - os.environ["FUZZER_LIB"] = "/libAFLDriver.a" + os.environ["FUZZER_LIB"] = "/libAFLDriver.a /hashcompare.o" def build(): From aab6c70a72f9026ea031d8c7bcb4bad402ef268d Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Sat, 8 Feb 2025 18:12:35 -0500 Subject: [PATCH 14/23] add debug line --- fuzzers/path_afl/builder.Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fuzzers/path_afl/builder.Dockerfile b/fuzzers/path_afl/builder.Dockerfile index 5c35aaecf..4ccca13ad 100644 --- a/fuzzers/path_afl/builder.Dockerfile +++ b/fuzzers/path_afl/builder.Dockerfile @@ -88,7 +88,9 @@ RUN cd /path-cov && \ git checkout ae6df67fee70abcada256f9519932237143ff8b6 && \ cargo build --release -RUN git clone -b fixversion https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl +RUN echo 42 + +RUN git clone -b driver-clear-pool https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl # RUN clang++-17 -v -E -x c++ - < /dev/null && eixt 1 From ba0b5c25b7e51ebf7a839a325f8f2d10b31b5d5c Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Sun, 9 Feb 2025 02:53:36 -0500 Subject: [PATCH 15/23] change to k=1, use edge-priority --- fuzzers/path_afl/builder.Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzzers/path_afl/builder.Dockerfile b/fuzzers/path_afl/builder.Dockerfile index 4ccca13ad..93da27bb4 100644 --- a/fuzzers/path_afl/builder.Dockerfile +++ b/fuzzers/path_afl/builder.Dockerfile @@ -85,12 +85,12 @@ RUN rm -rf /usr/local/share/clang RUN git clone -b fx-no-tail-opt1 https://github.com/fEst1ck/path-cov.git /path-cov RUN cd /path-cov && \ - git checkout ae6df67fee70abcada256f9519932237143ff8b6 && \ + git checkout bb900e89e14766ebd9d4af27cae0862bdb37de9b && \ cargo build --release RUN echo 42 -RUN git clone -b driver-clear-pool https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl +RUN git clone -b edge-priority https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl # RUN clang++-17 -v -E -x c++ - < /dev/null && eixt 1 From 97b9228f1930f206889c7b4933b59567bf5538ac Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Sun, 9 Feb 2025 02:55:51 -0500 Subject: [PATCH 16/23] add -Z flag --- fuzzers/aflplusplus/fuzzer.py | 2 ++ fuzzers/path_afl/fuzzer.py | 1 + 2 files changed, 3 insertions(+) diff --git a/fuzzers/aflplusplus/fuzzer.py b/fuzzers/aflplusplus/fuzzer.py index 8fe240500..a4886d5ce 100755 --- a/fuzzers/aflplusplus/fuzzer.py +++ b/fuzzers/aflplusplus/fuzzer.py @@ -258,6 +258,8 @@ def fuzz(input_corpus, flags = list(flags) + flags += '-Z' + if os.path.exists('./afl++.dict'): flags += ['-x', './afl++.dict'] diff --git a/fuzzers/path_afl/fuzzer.py b/fuzzers/path_afl/fuzzer.py index 0db1eb7e9..61f0a691a 100644 --- a/fuzzers/path_afl/fuzzer.py +++ b/fuzzers/path_afl/fuzzer.py @@ -120,6 +120,7 @@ def run_afl_fuzz( print("[run_afl_fuzz] Running target with afl-fuzz") command = [ "./afl-fuzz", + "-Z", "-i", input_corpus, "-o", From 6cf0d54c5f026f35fbfe5c0a40d4e8eb380f7720 Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Sun, 9 Feb 2025 03:42:27 -0500 Subject: [PATCH 17/23] fix driver issue --- fuzzers/path_afl/builder.Dockerfile | 4 ---- fuzzers/path_afl/fuzzer.py | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/fuzzers/path_afl/builder.Dockerfile b/fuzzers/path_afl/builder.Dockerfile index 93da27bb4..a339c199b 100644 --- a/fuzzers/path_afl/builder.Dockerfile +++ b/fuzzers/path_afl/builder.Dockerfile @@ -88,8 +88,6 @@ RUN cd /path-cov && \ git checkout bb900e89e14766ebd9d4af27cae0862bdb37de9b && \ cargo build --release -RUN echo 42 - RUN git clone -b edge-priority https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl # RUN clang++-17 -v -E -x c++ - < /dev/null && eixt 1 @@ -123,8 +121,6 @@ RUN apt install g++ # Set AFL_NO_X86 to skip flaky tests. RUN cd /path-afl && cp utils/aflpp_driver/libAFLDriver.a / -RUN cp /path-afl/hashcompare.o / - RUN cp /usr/lib/x86_64-linux-gnu/libpython3.8.so.1.0 / RUN cp /usr/lib/llvm-17/lib/libc++.so.1 / diff --git a/fuzzers/path_afl/fuzzer.py b/fuzzers/path_afl/fuzzer.py index 61f0a691a..06d25c0d1 100644 --- a/fuzzers/path_afl/fuzzer.py +++ b/fuzzers/path_afl/fuzzer.py @@ -32,7 +32,7 @@ def prepare_build_environment(): os.environ["CFGFILE"] = os.path.join(current_directory, "cfg.txt") os.environ["FUZZER"] = "/path-afl" os.environ["AFL_LLVM_CALLER"] = "1" - os.environ["FUZZER_LIB"] = "/libAFLDriver.a /hashcompare.o" + os.environ["FUZZER_LIB"] = "/libAFLDriver.a" def build(): From 3373c9bd651754dc29c6b8fa15fe76d3b716dbd4 Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Sun, 9 Feb 2025 04:48:51 -0500 Subject: [PATCH 18/23] remove -Z for afl++ --- fuzzers/aflplusplus/fuzzer.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/fuzzers/aflplusplus/fuzzer.py b/fuzzers/aflplusplus/fuzzer.py index a4886d5ce..8fe240500 100755 --- a/fuzzers/aflplusplus/fuzzer.py +++ b/fuzzers/aflplusplus/fuzzer.py @@ -258,8 +258,6 @@ def fuzz(input_corpus, flags = list(flags) - flags += '-Z' - if os.path.exists('./afl++.dict'): flags += ['-x', './afl++.dict'] From 72df900a7a6b9543c9f8fff00f879c6d20600692 Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Sun, 9 Feb 2025 05:04:16 -0500 Subject: [PATCH 19/23] use libstdc++ --- fuzzers/path_afl/builder.Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzzers/path_afl/builder.Dockerfile b/fuzzers/path_afl/builder.Dockerfile index a339c199b..49d8b4eeb 100644 --- a/fuzzers/path_afl/builder.Dockerfile +++ b/fuzzers/path_afl/builder.Dockerfile @@ -96,7 +96,7 @@ RUN cd /path-afl && \ which clang-17 && \ which clang && \ clang --version && \ - clang++ -stdlib=libc++ -c hashcompare.cpp && \ + clang++ -stdlib=libstdc++ -c hashcompare.cpp && \ ar rcs libhashcompare.a hashcompare.o && \ cp /path-cov/target/release/libpath_reduction.so . @@ -108,7 +108,7 @@ RUN cd /path-afl && \ export AFL_NO_X86=1 && \ unset CFLAGS CXXFLAGS && \ PYTHON_INCLUDE=/ && \ - LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lc++ -lpath_reduction" make + LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lstdc++ -lpath_reduction" make # RUN export CC=clang && \ # export CXX=clang++ && \ # export AFL_NO_X86=1 && \ From d0cdeb034e0b85e69db693ef5e8e713cb23d032d Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Sun, 9 Feb 2025 16:10:46 -0500 Subject: [PATCH 20/23] -Z for afl++ --- fuzzers/aflplusplus/fuzzer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fuzzers/aflplusplus/fuzzer.py b/fuzzers/aflplusplus/fuzzer.py index 8fe240500..a4886d5ce 100755 --- a/fuzzers/aflplusplus/fuzzer.py +++ b/fuzzers/aflplusplus/fuzzer.py @@ -258,6 +258,8 @@ def fuzz(input_corpus, flags = list(flags) + flags += '-Z' + if os.path.exists('./afl++.dict'): flags += ['-x', './afl++.dict'] From d37599a4187b1bc162c3ce63204a666cac0ad066 Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Sun, 9 Feb 2025 17:31:23 -0500 Subject: [PATCH 21/23] recover cmplog for afl++ --- fuzzers/aflplusplus/fuzzer.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fuzzers/aflplusplus/fuzzer.py b/fuzzers/aflplusplus/fuzzer.py index a4886d5ce..7016da75e 100755 --- a/fuzzers/aflplusplus/fuzzer.py +++ b/fuzzers/aflplusplus/fuzzer.py @@ -241,7 +241,7 @@ def fuzz(input_corpus, target_binary, flags=tuple(), skip=False, - no_cmplog=True): # pylint: disable=too-many-arguments + no_cmplog=False): # pylint: disable=too-many-arguments """Run fuzzer.""" # Calculate CmpLog binary path from the instrumented target binary. target_binary_directory = os.path.dirname(target_binary) @@ -258,14 +258,12 @@ def fuzz(input_corpus, flags = list(flags) - flags += '-Z' - if os.path.exists('./afl++.dict'): flags += ['-x', './afl++.dict'] # Move the following to skip for upcoming _double tests: - # if os.path.exists(cmplog_target_binary) and no_cmplog is False: - # flags += ['-c', cmplog_target_binary] + if os.path.exists(cmplog_target_binary) and no_cmplog is False: + flags += ['-c', cmplog_target_binary] #os.environ['AFL_IGNORE_TIMEOUTS'] = '1' os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' From c8b1b31419c676dc8b8c1d10b1542251ddab8526 Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Sun, 9 Feb 2025 17:50:14 -0500 Subject: [PATCH 22/23] add fuzzers --- .../aflplusplus_z_no_cmp/builder.Dockerfile | 49 +++ fuzzers/aflplusplus_z_no_cmp/description.md | 14 + fuzzers/aflplusplus_z_no_cmp/fuzzer.py | 284 ++++++++++++++++++ .../aflplusplus_z_no_cmp/runner.Dockerfile | 24 ++ fuzzers/path_afl_k2/builder.Dockerfile | 128 ++++++++ fuzzers/path_afl_k2/fuzzer.py | 155 ++++++++++ fuzzers/path_afl_k2/runner.Dockerfile | 26 ++ .../path_afl_k2_old_driver/builder.Dockerfile | 128 ++++++++ fuzzers/path_afl_k2_old_driver/fuzzer.py | 155 ++++++++++ .../path_afl_k2_old_driver/runner.Dockerfile | 26 ++ .../path_afl_old_driver/builder.Dockerfile | 128 ++++++++ fuzzers/path_afl_old_driver/fuzzer.py | 155 ++++++++++ fuzzers/path_afl_old_driver/runner.Dockerfile | 26 ++ 13 files changed, 1298 insertions(+) create mode 100644 fuzzers/aflplusplus_z_no_cmp/builder.Dockerfile create mode 100644 fuzzers/aflplusplus_z_no_cmp/description.md create mode 100755 fuzzers/aflplusplus_z_no_cmp/fuzzer.py create mode 100644 fuzzers/aflplusplus_z_no_cmp/runner.Dockerfile create mode 100644 fuzzers/path_afl_k2/builder.Dockerfile create mode 100644 fuzzers/path_afl_k2/fuzzer.py create mode 100644 fuzzers/path_afl_k2/runner.Dockerfile create mode 100644 fuzzers/path_afl_k2_old_driver/builder.Dockerfile create mode 100644 fuzzers/path_afl_k2_old_driver/fuzzer.py create mode 100644 fuzzers/path_afl_k2_old_driver/runner.Dockerfile create mode 100644 fuzzers/path_afl_old_driver/builder.Dockerfile create mode 100644 fuzzers/path_afl_old_driver/fuzzer.py create mode 100644 fuzzers/path_afl_old_driver/runner.Dockerfile diff --git a/fuzzers/aflplusplus_z_no_cmp/builder.Dockerfile b/fuzzers/aflplusplus_z_no_cmp/builder.Dockerfile new file mode 100644 index 000000000..fc0561c41 --- /dev/null +++ b/fuzzers/aflplusplus_z_no_cmp/builder.Dockerfile @@ -0,0 +1,49 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ARG parent_image +FROM $parent_image + +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + python3-dev \ + python3-setuptools \ + automake \ + cmake \ + git \ + flex \ + bison \ + libglib2.0-dev \ + libpixman-1-dev \ + cargo \ + libgtk-3-dev \ + # for QEMU mode + ninja-build \ + gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev \ + libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev + +# Download afl++. +RUN git clone -b dev https://github.com/AFLplusplus/AFLplusplus /afl && \ + cd /afl && \ + git checkout 56d5aa3101945e81519a3fac8783d0d8fad82779 || \ + true + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cd /afl && \ + unset CFLAGS CXXFLAGS && \ + export CC=clang AFL_NO_X86=1 && \ + PYTHON_INCLUDE=/ make && \ + cp utils/aflpp_driver/libAFLDriver.a / diff --git a/fuzzers/aflplusplus_z_no_cmp/description.md b/fuzzers/aflplusplus_z_no_cmp/description.md new file mode 100644 index 000000000..f7eb407ad --- /dev/null +++ b/fuzzers/aflplusplus_z_no_cmp/description.md @@ -0,0 +1,14 @@ +# aflplusplus + +AFL++ fuzzer instance that has the following config active for all benchmarks: + - PCGUARD instrumentation + - cmplog feature + - dict2file feature + - "fast" power schedule + - persistent mode + shared memory test cases + +Repository: [https://github.com/AFLplusplus/AFLplusplus/](https://github.com/AFLplusplus/AFLplusplus/) + +[builder.Dockerfile](builder.Dockerfile) +[fuzzer.py](fuzzer.py) +[runner.Dockerfile](runner.Dockerfile) diff --git a/fuzzers/aflplusplus_z_no_cmp/fuzzer.py b/fuzzers/aflplusplus_z_no_cmp/fuzzer.py new file mode 100755 index 000000000..a4886d5ce --- /dev/null +++ b/fuzzers/aflplusplus_z_no_cmp/fuzzer.py @@ -0,0 +1,284 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +"""Integration code for AFLplusplus fuzzer.""" + +import os +import shutil + +from fuzzers.afl import fuzzer as afl_fuzzer +from fuzzers import utils + + +def get_cmplog_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'cmplog') + + +def get_uninstrumented_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'uninstrumented') + + +def build(*args): # pylint: disable=too-many-branches,too-many-statements + """Build benchmark.""" + # BUILD_MODES is not already supported by fuzzbench, meanwhile we provide + # a default configuration. + + build_modes = list(args) + if 'BUILD_MODES' in os.environ: + build_modes = os.environ['BUILD_MODES'].split(',') + + # Placeholder comment. + build_directory = os.environ['OUT'] + + # If nothing was set this is the default: + if not build_modes: + build_modes = ['tracepc', 'cmplog', 'dict2file'] + + # For bug type benchmarks we have to instrument via native clang pcguard :( + build_flags = os.environ['CFLAGS'] + + if build_flags.find( + 'array-bounds' + ) != -1 and 'qemu' not in build_modes and 'classic' not in build_modes: + if 'gcc' not in build_modes: + build_modes[0] = 'native' + + # Instrumentation coverage modes: + if 'lto' in build_modes: + os.environ['CC'] = '/afl/afl-clang-lto' + os.environ['CXX'] = '/afl/afl-clang-lto++' + edge_file = build_directory + '/aflpp_edges.txt' + os.environ['AFL_LLVM_DOCUMENT_IDS'] = edge_file + if os.path.isfile('/usr/local/bin/llvm-ranlib-13'): + os.environ['RANLIB'] = 'llvm-ranlib-13' + os.environ['AR'] = 'llvm-ar-13' + os.environ['AS'] = 'llvm-as-13' + elif os.path.isfile('/usr/local/bin/llvm-ranlib-12'): + os.environ['RANLIB'] = 'llvm-ranlib-12' + os.environ['AR'] = 'llvm-ar-12' + os.environ['AS'] = 'llvm-as-12' + else: + os.environ['RANLIB'] = 'llvm-ranlib' + os.environ['AR'] = 'llvm-ar' + os.environ['AS'] = 'llvm-as' + elif 'qemu' in build_modes: + os.environ['CC'] = 'clang' + os.environ['CXX'] = 'clang++' + elif 'gcc' in build_modes: + os.environ['CC'] = 'afl-gcc-fast' + os.environ['CXX'] = 'afl-g++-fast' + if build_flags.find('array-bounds') != -1: + os.environ['CFLAGS'] = '-fsanitize=address -O1' + os.environ['CXXFLAGS'] = '-fsanitize=address -O1' + else: + os.environ['CFLAGS'] = '' + os.environ['CXXFLAGS'] = '' + os.environ['CPPFLAGS'] = '' + else: + os.environ['CC'] = '/afl/afl-clang-fast' + os.environ['CXX'] = '/afl/afl-clang-fast++' + + print('AFL++ build: ') + print(build_modes) + + if 'qemu' in build_modes or 'symcc' in build_modes: + os.environ['CFLAGS'] = ' '.join(utils.NO_SANITIZER_COMPAT_CFLAGS) + cxxflags = [utils.LIBCPLUSPLUS_FLAG] + utils.NO_SANITIZER_COMPAT_CFLAGS + os.environ['CXXFLAGS'] = ' '.join(cxxflags) + + if 'tracepc' in build_modes or 'pcguard' in build_modes: + os.environ['AFL_LLVM_USE_TRACE_PC'] = '1' + elif 'classic' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'CLASSIC' + elif 'native' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'LLVMNATIVE' + + # Instrumentation coverage options: + # Do not use a fixed map location (LTO only) + if 'dynamic' in build_modes: + os.environ['AFL_LLVM_MAP_DYNAMIC'] = '1' + # Use a fixed map location (LTO only) + if 'fixed' in build_modes: + os.environ['AFL_LLVM_MAP_ADDR'] = '0x10000' + # Generate an extra dictionary. + if 'dict2file' in build_modes or 'native' in build_modes: + os.environ['AFL_LLVM_DICT2FILE'] = build_directory + '/afl++.dict' + os.environ['AFL_LLVM_DICT2FILE_NO_MAIN'] = '1' + # Enable context sentitivity for LLVM mode (non LTO only) + if 'ctx' in build_modes: + os.environ['AFL_LLVM_CTX'] = '1' + # Enable N-gram coverage for LLVM mode (non LTO only) + if 'ngram2' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '2' + elif 'ngram3' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '3' + elif 'ngram4' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '4' + elif 'ngram5' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '5' + elif 'ngram6' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '6' + elif 'ngram7' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '7' + elif 'ngram8' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '8' + elif 'ngram16' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '16' + if 'ctx1' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '1' + elif 'ctx2' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '2' + elif 'ctx3' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '3' + elif 'ctx4' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '4' + + # Only one of the following OR cmplog + # enable laf-intel compare splitting + if 'laf' in build_modes: + os.environ['AFL_LLVM_LAF_SPLIT_SWITCHES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_COMPARES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_FLOATS'] = '1' + if 'autodict' not in build_modes: + os.environ['AFL_LLVM_LAF_TRANSFORM_COMPARES'] = '1' + + if 'eclipser' in build_modes: + os.environ['FUZZER_LIB'] = '/libStandaloneFuzzTarget.a' + else: + os.environ['FUZZER_LIB'] = '/libAFLDriver.a' + + # Some benchmarks like lcms. (see: + # https://github.com/mm2/Little-CMS/commit/ab1093539b4287c233aca6a3cf53b234faceb792#diff-f0e6d05e72548974e852e8e55dffc4ccR212) + # fail to compile if the compiler outputs things to stderr in unexpected + # cases. Prevent these failures by using AFL_QUIET to stop afl-clang-fast + # from writing AFL specific messages to stderr. + os.environ['AFL_QUIET'] = '1' + os.environ['AFL_MAP_SIZE'] = '2621440' + + src = os.getenv('SRC') + work = os.getenv('WORK') + + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + utils.build_benchmark() + + if 'cmplog' in build_modes and 'qemu' not in build_modes: + + # CmpLog requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['AFL_LLVM_CMPLOG'] = '1' + + # For CmpLog build, set the OUT and FUZZ_TARGET environment + # variable to point to the new CmpLog build directory. + cmplog_build_directory = get_cmplog_build_directory(build_directory) + os.mkdir(cmplog_build_directory) + new_env['OUT'] = cmplog_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(cmplog_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for CmpLog fuzzing target') + utils.build_benchmark(env=new_env) + + if 'symcc' in build_modes: + + symcc_build_directory = get_uninstrumented_build_directory( + build_directory) + os.mkdir(symcc_build_directory) + + # symcc requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['CC'] = '/symcc/build/symcc' + new_env['CXX'] = '/symcc/build/sym++' + new_env['SYMCC_OUTPUT_DIR'] = '/tmp' + new_env['CXXFLAGS'] = new_env['CXXFLAGS'].replace('-stlib=libc++', '') + new_env['FUZZER_LIB'] = '/libfuzzer-harness.o' + new_env['OUT'] = symcc_build_directory + new_env['SYMCC_LIBCXX_PATH'] = '/libcxx_native_build' + new_env['SYMCC_NO_SYMBOLIC_INPUT'] = '1' + new_env['SYMCC_SILENT'] = '1' + + # For symcc build, set the OUT and FUZZ_TARGET environment + # variable to point to the new symcc build directory. + new_env['OUT'] = symcc_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(symcc_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for symcc fuzzing target') + utils.build_benchmark(env=new_env) + + shutil.copy('/afl/afl-fuzz', build_directory) + if os.path.exists('/afl/afl-qemu-trace'): + shutil.copy('/afl/afl-qemu-trace', build_directory) + if os.path.exists('/aflpp_qemu_driver_hook.so'): + shutil.copy('/aflpp_qemu_driver_hook.so', build_directory) + if os.path.exists('/get_frida_entry.sh'): + shutil.copy('/afl/afl-frida-trace.so', build_directory) + shutil.copy('/get_frida_entry.sh', build_directory) + + +# pylint: disable=too-many-arguments +def fuzz(input_corpus, + output_corpus, + target_binary, + flags=tuple(), + skip=False, + no_cmplog=True): # pylint: disable=too-many-arguments + """Run fuzzer.""" + # Calculate CmpLog binary path from the instrumented target binary. + target_binary_directory = os.path.dirname(target_binary) + cmplog_target_binary_directory = ( + get_cmplog_build_directory(target_binary_directory)) + target_binary_name = os.path.basename(target_binary) + cmplog_target_binary = os.path.join(cmplog_target_binary_directory, + target_binary_name) + + afl_fuzzer.prepare_fuzz_environment(input_corpus) + # decomment this to enable libdislocator. + # os.environ['AFL_ALIGNED_ALLOC'] = '1' # align malloc to max_align_t + # os.environ['AFL_PRELOAD'] = '/afl/libdislocator.so' + + flags = list(flags) + + flags += '-Z' + + if os.path.exists('./afl++.dict'): + flags += ['-x', './afl++.dict'] + + # Move the following to skip for upcoming _double tests: + # if os.path.exists(cmplog_target_binary) and no_cmplog is False: + # flags += ['-c', cmplog_target_binary] + + #os.environ['AFL_IGNORE_TIMEOUTS'] = '1' + os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' + os.environ['AFL_FAST_CAL'] = '1' + os.environ['AFL_NO_WARN_INSTABILITY'] = '1' + + if not skip: + os.environ['AFL_DISABLE_TRIM'] = '1' + os.environ['AFL_CMPLOG_ONLY_NEW'] = '1' + if 'ADDITIONAL_ARGS' in os.environ: + flags += os.environ['ADDITIONAL_ARGS'].split(' ') + + afl_fuzzer.run_afl_fuzz(input_corpus, + output_corpus, + target_binary, + additional_flags=flags) diff --git a/fuzzers/aflplusplus_z_no_cmp/runner.Dockerfile b/fuzzers/aflplusplus_z_no_cmp/runner.Dockerfile new file mode 100644 index 000000000..5640d5b24 --- /dev/null +++ b/fuzzers/aflplusplus_z_no_cmp/runner.Dockerfile @@ -0,0 +1,24 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM gcr.io/fuzzbench/base-image + +# This makes interactive docker runs painless: +ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/out" +#ENV AFL_MAP_SIZE=2621440 +ENV PATH="$PATH:/out" +ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +ENV AFL_TESTCACHE_SIZE=2 +# RUN apt-get update && apt-get upgrade && apt install -y unzip git gdb joe diff --git a/fuzzers/path_afl_k2/builder.Dockerfile b/fuzzers/path_afl_k2/builder.Dockerfile new file mode 100644 index 000000000..33608f5d6 --- /dev/null +++ b/fuzzers/path_afl_k2/builder.Dockerfile @@ -0,0 +1,128 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ARG parent_image +FROM $parent_image + +RUN apt-get update && apt-get install -y sudo make build-essential git wget tree vim gdb zstd libzstd-dev libjbig-dev libselinux-dev bash + +SHELL ["/bin/bash", "-c"] + +RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - + +RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main" >> /etc/apt/sources.list +RUN echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal main" >> /etc/apt/sources.list +RUN echo "# 17" >> /etc/apt/sources.list +RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main" >> /etc/apt/sources.list +RUN echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main" >> /etc/apt/sources.list + +RUN apt-get update && apt-get install -y clang-17 lld-17 llvm-17-dev \ + libc++-17-dev libc++abi-17-dev gcc-10 gcc-10-plugin-dev libstdc++-10-dev \ + libssl-dev cargo autopoint + +RUN update-alternatives \ + --install /usr/lib/llvm llvm /usr/lib/llvm-17 1000 \ + --slave /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-17 \ + --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-17 \ + --slave /usr/bin/llvm-as llvm-as /usr/bin/llvm-as-17 \ + --slave /usr/bin/llvm-bcanalyzer llvm-bcanalyzer /usr/bin/llvm-bcanalyzer-17 \ + --slave /usr/bin/llvm-c-test llvm-c-test /usr/bin/llvm-c-test-17 \ + --slave /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-17 \ + --slave /usr/bin/llvm-diff llvm-diff /usr/bin/llvm-diff-17 \ + --slave /usr/bin/llvm-dis llvm-dis /usr/bin/llvm-dis-17 \ + --slave /usr/bin/llvm-dwarfdump llvm-dwarfdump /usr/bin/llvm-dwarfdump-17 \ + --slave /usr/bin/llvm-extract llvm-extract /usr/bin/llvm-extract-17 \ + --slave /usr/bin/llvm-link llvm-link /usr/bin/llvm-link-17 \ + --slave /usr/bin/llvm-mc llvm-mc /usr/bin/llvm-mc-17 \ + --slave /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-17 \ + --slave /usr/bin/llvm-objdump llvm-objdump /usr/bin/llvm-objdump-17 \ + --slave /usr/bin/llvm-ranlib llvm-ranlib /usr/bin/llvm-ranlib-17 \ + --slave /usr/bin/llvm-readobj llvm-readobj /usr/bin/llvm-readobj-17 \ + --slave /usr/bin/llvm-rtdyld llvm-rtdyld /usr/bin/llvm-rtdyld-17 \ + --slave /usr/bin/llvm-size llvm-size /usr/bin/llvm-size-17 \ + --slave /usr/bin/llvm-stress llvm-stress /usr/bin/llvm-stress-17 \ + --slave /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-17 \ + --slave /usr/bin/llvm-tblgen llvm-tblgen /usr/bin/llvm-tblgen-17 + +RUN update-alternatives \ + --install /usr/bin/clang clang /usr/bin/clang-17 1000 \ + --slave /usr/bin/clang++ clang++ /usr/bin/clang++-17 \ + --slave /usr/bin/clang-cpp clang-cpp /usr/bin/clang-cpp-17 \ + --slave /usr/bin/ld.lld lld /usr/bin/ld.lld-17 + +# Uninstall old Rust +RUN if which rustup; then rustup self uninstall -y; fi + +# Install latest Rust +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /rustup.sh && \ + sh /rustup.sh -y + +ENV PATH="/root/.cargo/bin:${PATH}" + +RUN rm -rf /usr/local/bin/clang /usr/local/bin/clang++ /usr/local/bin/llvm* +RUN rm -rf /usr/local/lib/clang +RUN rm -rf /usr/local/include/clang +RUN rm -rf /usr/local/share/clang + +# RUN rm /usr/local/bin/clang /usr/local/bin/clang++ /usr/local/bin/clang-cpp +# ENV PATH="/usr/bin:/usr/local/bin:$PATH" + +# RUN ls /usr/lib/llvm-17/include/llvm && exit 1 + +# RUN clang --version | grep "clang version 17" || { echo "Clang version is not 17"; exit 1; } + +RUN git clone -b fx-no-tail-opt1 https://github.com/fEst1ck/path-cov.git /path-cov + +RUN cd /path-cov && \ + git checkout ae6df67fee70abcada256f9519932237143ff8b6 && \ + cargo build --release + +RUN git clone -b edge-priority https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl + +# RUN clang++-17 -v -E -x c++ - < /dev/null && eixt 1 + +RUN cd /path-afl && \ + which clang-17 && \ + which clang && \ + clang --version && \ + clang++ -stdlib=libstdc++ -c hashcompare.cpp && \ + ar rcs libhashcompare.a hashcompare.o && \ + cp /path-cov/target/release/libpath_reduction.so . + +# RUN which llvm-config-17 || { echo "llvm-config-17 not found"; exit 1; } + +RUN cd /path-afl && \ + export CC=clang && \ + export CXX=clang++ && \ + export AFL_NO_X86=1 && \ + unset CFLAGS CXXFLAGS && \ + PYTHON_INCLUDE=/ && \ + LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lstdc++ -lpath_reduction" make +# RUN export CC=clang && \ +# export CXX=clang++ && \ +# export AFL_NO_X86=1 && \ +# export PYTHON_INCLUDE=/ && \ +# LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lstdc++ -lpath_reduction" make -e -C utils/aflpp_driver || exit 1 + +RUN apt install g++ + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cd /path-afl && cp utils/aflpp_driver/libAFLDriver.a / + +RUN cp /usr/lib/x86_64-linux-gnu/libpython3.8.so.1.0 / + +RUN cp /usr/lib/llvm-17/lib/libc++.so.1 / +RUN cp /usr/lib/llvm-17/lib/libc++abi.so.1 / + diff --git a/fuzzers/path_afl_k2/fuzzer.py b/fuzzers/path_afl_k2/fuzzer.py new file mode 100644 index 000000000..06d25c0d1 --- /dev/null +++ b/fuzzers/path_afl_k2/fuzzer.py @@ -0,0 +1,155 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Integration code for pathAFL fuzzer.""" + +import os +import shutil +import subprocess + +from fuzzers import utils + + +def prepare_build_environment(): + """Set environment variables used to build targets for pathAFL-based + fuzzers.""" + os.environ["LD_LIBRARY_PATH"] = "/path-afl" + os.environ["CC"] = "/path-afl/afl-clang-fast" + os.environ["CXX"] = "/path-afl/afl-clang-fast++" + current_directory = os.getcwd() + os.environ["BBIDFILE"] = os.path.join(current_directory, "bbid.txt") + os.environ["CALLMAPFILE"] = os.path.join(current_directory, "callmap.txt") + os.environ["CFGFILE"] = os.path.join(current_directory, "cfg.txt") + os.environ["FUZZER"] = "/path-afl" + os.environ["AFL_LLVM_CALLER"] = "1" + os.environ["FUZZER_LIB"] = "/libAFLDriver.a" + + +def build(): + """Build benchmark.""" + prepare_build_environment() + + utils.build_benchmark() + + subprocess.run( + 'cat cfg.txt | grep "BasicBlock: " | wc -l > bbnum.txt', + shell=True, + check=True, + ) + print(f"/out/{os.getenv('FUZZ_TARGET')}") + result = subprocess.run( + [ + "bash", + "/path-afl/fuzzing_support/filterCFGandCallmap.sh", + f"/out/{os.getenv('FUZZ_TARGET')}", + ], + check=False, + capture_output=True, + text=True, + ) + print(result.stdout) + print(result.stderr) + subprocess.run( + "cat cfg_filtered.txt | grep \"Function: \" | nl -v 0 | " + "awk '{print $1, $3, $4, $5, $6, $7, $8, $9}' > function_list.txt", + shell=True, + check=True, + ) + subprocess.run( + "g++ -I/path-afl/fuzzing_support " + "/path-afl/fuzzing_support/convert.cpp -o convert", + shell=True, + check=True, + ) + subprocess.run("./convert", shell=True, check=True) + + print("[post_build] Copying afl-fuzz to $OUT directory") + + # Copy out the afl-fuzz binary as a build artifact. + shutil.copy("/path-afl/libpath_reduction.so", os.environ["OUT"]) + shutil.copy("/path-afl/afl-fuzz", os.environ["OUT"]) + shutil.copy("./top.bin", os.environ["OUT"]) + shutil.copy("/libpython3.8.so.1.0", os.environ["OUT"]) + src = "/usr/lib/llvm-17/lib" + dst = os.environ["OUT"] + shutil.copytree(src, dst, dirs_exist_ok=True) + + +def prepare_fuzz_environment(input_corpus): + """Prepare to fuzz with AFL or another AFL-based fuzzer.""" + # Tell AFL to not use its terminal UI so we get usable logs. + os.environ["AFL_NO_UI"] = "1" + # Skip AFL's CPU frequency check (fails on Docker). + os.environ["AFL_SKIP_CPUFREQ"] = "1" + # No need to bind affinity to one core, Docker enforces 1 core usage. + os.environ["AFL_NO_AFFINITY"] = "1" + # AFL will abort on startup if the core pattern sends notifications to + # external programs. We don't care about this. + os.environ["AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES"] = "1" + # Don't exit when crashes are found. This can happen when corpus from + # OSS-Fuzz is used. + os.environ["AFL_SKIP_CRASHES"] = "1" + # Shuffle the queue + os.environ["AFL_SHUFFLE_QUEUE"] = "1" + os.environ["CFG_BIN_FILE"] = "./top.bin" + os.environ["LD_LIBRARY_PATH"] = ( + f'./lib:{os.getcwd()}:{os.environ["LD_LIBRARY_PATH"]}') + + # AFL needs at least one non-empty seed to start. + utils.create_seed_file_for_empty_corpus(input_corpus) + + +def run_afl_fuzz( + input_corpus, + output_corpus, + target_binary, + hide_output=False, +): + """Run afl-fuzz.""" + # Spawn the afl fuzzing process. + print("[run_afl_fuzz] Running target with afl-fuzz") + command = [ + "./afl-fuzz", + "-Z", + "-i", + input_corpus, + "-o", + output_corpus, + # Use no memory limit as ASAN doesn't play nicely with one. + "-m", + "none", + "-t", + "1000+", # Use same default 1 sec timeout, but add '+' to skip hangs. + ] + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + command.extend(["-x", dictionary_path]) + command += [ + "--", + target_binary, + # Pass INT_MAX to afl the maximize the number of persistent loops it + # performs. + "2147483647", + ] + print("[run_afl_fuzz] Running command: " + " ".join(command)) + output_stream = subprocess.DEVNULL if hide_output else None + subprocess.check_call(command, stdout=output_stream, stderr=output_stream) + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run afl-fuzz on target.""" + prepare_fuzz_environment(input_corpus) + + os.environ["K"] = "42" + + run_afl_fuzz(input_corpus, output_corpus, target_binary) diff --git a/fuzzers/path_afl_k2/runner.Dockerfile b/fuzzers/path_afl_k2/runner.Dockerfile new file mode 100644 index 000000000..2b5dd351d --- /dev/null +++ b/fuzzers/path_afl_k2/runner.Dockerfile @@ -0,0 +1,26 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM gcr.io/fuzzbench/base-image + +RUN apt-get update +RUN apt-get install -y python3.8 + +# This makes interactive docker runs painless: +ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/out" +#ENV AFL_MAP_SIZE=2621440 +ENV PATH="$PATH:/out" +ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +ENV AFL_TESTCACHE_SIZE=2 \ No newline at end of file diff --git a/fuzzers/path_afl_k2_old_driver/builder.Dockerfile b/fuzzers/path_afl_k2_old_driver/builder.Dockerfile new file mode 100644 index 000000000..93756faf7 --- /dev/null +++ b/fuzzers/path_afl_k2_old_driver/builder.Dockerfile @@ -0,0 +1,128 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ARG parent_image +FROM $parent_image + +RUN apt-get update && apt-get install -y sudo make build-essential git wget tree vim gdb zstd libzstd-dev libjbig-dev libselinux-dev bash + +SHELL ["/bin/bash", "-c"] + +RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - + +RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main" >> /etc/apt/sources.list +RUN echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal main" >> /etc/apt/sources.list +RUN echo "# 17" >> /etc/apt/sources.list +RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main" >> /etc/apt/sources.list +RUN echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main" >> /etc/apt/sources.list + +RUN apt-get update && apt-get install -y clang-17 lld-17 llvm-17-dev \ + libc++-17-dev libc++abi-17-dev gcc-10 gcc-10-plugin-dev libstdc++-10-dev \ + libssl-dev cargo autopoint + +RUN update-alternatives \ + --install /usr/lib/llvm llvm /usr/lib/llvm-17 1000 \ + --slave /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-17 \ + --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-17 \ + --slave /usr/bin/llvm-as llvm-as /usr/bin/llvm-as-17 \ + --slave /usr/bin/llvm-bcanalyzer llvm-bcanalyzer /usr/bin/llvm-bcanalyzer-17 \ + --slave /usr/bin/llvm-c-test llvm-c-test /usr/bin/llvm-c-test-17 \ + --slave /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-17 \ + --slave /usr/bin/llvm-diff llvm-diff /usr/bin/llvm-diff-17 \ + --slave /usr/bin/llvm-dis llvm-dis /usr/bin/llvm-dis-17 \ + --slave /usr/bin/llvm-dwarfdump llvm-dwarfdump /usr/bin/llvm-dwarfdump-17 \ + --slave /usr/bin/llvm-extract llvm-extract /usr/bin/llvm-extract-17 \ + --slave /usr/bin/llvm-link llvm-link /usr/bin/llvm-link-17 \ + --slave /usr/bin/llvm-mc llvm-mc /usr/bin/llvm-mc-17 \ + --slave /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-17 \ + --slave /usr/bin/llvm-objdump llvm-objdump /usr/bin/llvm-objdump-17 \ + --slave /usr/bin/llvm-ranlib llvm-ranlib /usr/bin/llvm-ranlib-17 \ + --slave /usr/bin/llvm-readobj llvm-readobj /usr/bin/llvm-readobj-17 \ + --slave /usr/bin/llvm-rtdyld llvm-rtdyld /usr/bin/llvm-rtdyld-17 \ + --slave /usr/bin/llvm-size llvm-size /usr/bin/llvm-size-17 \ + --slave /usr/bin/llvm-stress llvm-stress /usr/bin/llvm-stress-17 \ + --slave /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-17 \ + --slave /usr/bin/llvm-tblgen llvm-tblgen /usr/bin/llvm-tblgen-17 + +RUN update-alternatives \ + --install /usr/bin/clang clang /usr/bin/clang-17 1000 \ + --slave /usr/bin/clang++ clang++ /usr/bin/clang++-17 \ + --slave /usr/bin/clang-cpp clang-cpp /usr/bin/clang-cpp-17 \ + --slave /usr/bin/ld.lld lld /usr/bin/ld.lld-17 + +# Uninstall old Rust +RUN if which rustup; then rustup self uninstall -y; fi + +# Install latest Rust +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /rustup.sh && \ + sh /rustup.sh -y + +ENV PATH="/root/.cargo/bin:${PATH}" + +RUN rm -rf /usr/local/bin/clang /usr/local/bin/clang++ /usr/local/bin/llvm* +RUN rm -rf /usr/local/lib/clang +RUN rm -rf /usr/local/include/clang +RUN rm -rf /usr/local/share/clang + +# RUN rm /usr/local/bin/clang /usr/local/bin/clang++ /usr/local/bin/clang-cpp +# ENV PATH="/usr/bin:/usr/local/bin:$PATH" + +# RUN ls /usr/lib/llvm-17/include/llvm && exit 1 + +# RUN clang --version | grep "clang version 17" || { echo "Clang version is not 17"; exit 1; } + +RUN git clone -b fx-no-tail-opt1 https://github.com/fEst1ck/path-cov.git /path-cov + +RUN cd /path-cov && \ + git checkout ae6df67fee70abcada256f9519932237143ff8b6 && \ + cargo build --release + +RUN git clone -b edge-priority-old-driver https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl + +# RUN clang++-17 -v -E -x c++ - < /dev/null && eixt 1 + +RUN cd /path-afl && \ + which clang-17 && \ + which clang && \ + clang --version && \ + clang++ -stdlib=libstdc++ -c hashcompare.cpp && \ + ar rcs libhashcompare.a hashcompare.o && \ + cp /path-cov/target/release/libpath_reduction.so . + +# RUN which llvm-config-17 || { echo "llvm-config-17 not found"; exit 1; } + +RUN cd /path-afl && \ + export CC=clang && \ + export CXX=clang++ && \ + export AFL_NO_X86=1 && \ + unset CFLAGS CXXFLAGS && \ + PYTHON_INCLUDE=/ && \ + LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lstdc++ -lpath_reduction" make +# RUN export CC=clang && \ +# export CXX=clang++ && \ +# export AFL_NO_X86=1 && \ +# export PYTHON_INCLUDE=/ && \ +# LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lstdc++ -lpath_reduction" make -e -C utils/aflpp_driver || exit 1 + +RUN apt install g++ + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cd /path-afl && cp utils/aflpp_driver/libAFLDriver.a / + +RUN cp /usr/lib/x86_64-linux-gnu/libpython3.8.so.1.0 / + +RUN cp /usr/lib/llvm-17/lib/libc++.so.1 / +RUN cp /usr/lib/llvm-17/lib/libc++abi.so.1 / + diff --git a/fuzzers/path_afl_k2_old_driver/fuzzer.py b/fuzzers/path_afl_k2_old_driver/fuzzer.py new file mode 100644 index 000000000..06d25c0d1 --- /dev/null +++ b/fuzzers/path_afl_k2_old_driver/fuzzer.py @@ -0,0 +1,155 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Integration code for pathAFL fuzzer.""" + +import os +import shutil +import subprocess + +from fuzzers import utils + + +def prepare_build_environment(): + """Set environment variables used to build targets for pathAFL-based + fuzzers.""" + os.environ["LD_LIBRARY_PATH"] = "/path-afl" + os.environ["CC"] = "/path-afl/afl-clang-fast" + os.environ["CXX"] = "/path-afl/afl-clang-fast++" + current_directory = os.getcwd() + os.environ["BBIDFILE"] = os.path.join(current_directory, "bbid.txt") + os.environ["CALLMAPFILE"] = os.path.join(current_directory, "callmap.txt") + os.environ["CFGFILE"] = os.path.join(current_directory, "cfg.txt") + os.environ["FUZZER"] = "/path-afl" + os.environ["AFL_LLVM_CALLER"] = "1" + os.environ["FUZZER_LIB"] = "/libAFLDriver.a" + + +def build(): + """Build benchmark.""" + prepare_build_environment() + + utils.build_benchmark() + + subprocess.run( + 'cat cfg.txt | grep "BasicBlock: " | wc -l > bbnum.txt', + shell=True, + check=True, + ) + print(f"/out/{os.getenv('FUZZ_TARGET')}") + result = subprocess.run( + [ + "bash", + "/path-afl/fuzzing_support/filterCFGandCallmap.sh", + f"/out/{os.getenv('FUZZ_TARGET')}", + ], + check=False, + capture_output=True, + text=True, + ) + print(result.stdout) + print(result.stderr) + subprocess.run( + "cat cfg_filtered.txt | grep \"Function: \" | nl -v 0 | " + "awk '{print $1, $3, $4, $5, $6, $7, $8, $9}' > function_list.txt", + shell=True, + check=True, + ) + subprocess.run( + "g++ -I/path-afl/fuzzing_support " + "/path-afl/fuzzing_support/convert.cpp -o convert", + shell=True, + check=True, + ) + subprocess.run("./convert", shell=True, check=True) + + print("[post_build] Copying afl-fuzz to $OUT directory") + + # Copy out the afl-fuzz binary as a build artifact. + shutil.copy("/path-afl/libpath_reduction.so", os.environ["OUT"]) + shutil.copy("/path-afl/afl-fuzz", os.environ["OUT"]) + shutil.copy("./top.bin", os.environ["OUT"]) + shutil.copy("/libpython3.8.so.1.0", os.environ["OUT"]) + src = "/usr/lib/llvm-17/lib" + dst = os.environ["OUT"] + shutil.copytree(src, dst, dirs_exist_ok=True) + + +def prepare_fuzz_environment(input_corpus): + """Prepare to fuzz with AFL or another AFL-based fuzzer.""" + # Tell AFL to not use its terminal UI so we get usable logs. + os.environ["AFL_NO_UI"] = "1" + # Skip AFL's CPU frequency check (fails on Docker). + os.environ["AFL_SKIP_CPUFREQ"] = "1" + # No need to bind affinity to one core, Docker enforces 1 core usage. + os.environ["AFL_NO_AFFINITY"] = "1" + # AFL will abort on startup if the core pattern sends notifications to + # external programs. We don't care about this. + os.environ["AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES"] = "1" + # Don't exit when crashes are found. This can happen when corpus from + # OSS-Fuzz is used. + os.environ["AFL_SKIP_CRASHES"] = "1" + # Shuffle the queue + os.environ["AFL_SHUFFLE_QUEUE"] = "1" + os.environ["CFG_BIN_FILE"] = "./top.bin" + os.environ["LD_LIBRARY_PATH"] = ( + f'./lib:{os.getcwd()}:{os.environ["LD_LIBRARY_PATH"]}') + + # AFL needs at least one non-empty seed to start. + utils.create_seed_file_for_empty_corpus(input_corpus) + + +def run_afl_fuzz( + input_corpus, + output_corpus, + target_binary, + hide_output=False, +): + """Run afl-fuzz.""" + # Spawn the afl fuzzing process. + print("[run_afl_fuzz] Running target with afl-fuzz") + command = [ + "./afl-fuzz", + "-Z", + "-i", + input_corpus, + "-o", + output_corpus, + # Use no memory limit as ASAN doesn't play nicely with one. + "-m", + "none", + "-t", + "1000+", # Use same default 1 sec timeout, but add '+' to skip hangs. + ] + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + command.extend(["-x", dictionary_path]) + command += [ + "--", + target_binary, + # Pass INT_MAX to afl the maximize the number of persistent loops it + # performs. + "2147483647", + ] + print("[run_afl_fuzz] Running command: " + " ".join(command)) + output_stream = subprocess.DEVNULL if hide_output else None + subprocess.check_call(command, stdout=output_stream, stderr=output_stream) + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run afl-fuzz on target.""" + prepare_fuzz_environment(input_corpus) + + os.environ["K"] = "42" + + run_afl_fuzz(input_corpus, output_corpus, target_binary) diff --git a/fuzzers/path_afl_k2_old_driver/runner.Dockerfile b/fuzzers/path_afl_k2_old_driver/runner.Dockerfile new file mode 100644 index 000000000..2b5dd351d --- /dev/null +++ b/fuzzers/path_afl_k2_old_driver/runner.Dockerfile @@ -0,0 +1,26 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM gcr.io/fuzzbench/base-image + +RUN apt-get update +RUN apt-get install -y python3.8 + +# This makes interactive docker runs painless: +ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/out" +#ENV AFL_MAP_SIZE=2621440 +ENV PATH="$PATH:/out" +ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +ENV AFL_TESTCACHE_SIZE=2 \ No newline at end of file diff --git a/fuzzers/path_afl_old_driver/builder.Dockerfile b/fuzzers/path_afl_old_driver/builder.Dockerfile new file mode 100644 index 000000000..e750806ed --- /dev/null +++ b/fuzzers/path_afl_old_driver/builder.Dockerfile @@ -0,0 +1,128 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ARG parent_image +FROM $parent_image + +RUN apt-get update && apt-get install -y sudo make build-essential git wget tree vim gdb zstd libzstd-dev libjbig-dev libselinux-dev bash + +SHELL ["/bin/bash", "-c"] + +RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - + +RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main" >> /etc/apt/sources.list +RUN echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal main" >> /etc/apt/sources.list +RUN echo "# 17" >> /etc/apt/sources.list +RUN echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main" >> /etc/apt/sources.list +RUN echo "deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main" >> /etc/apt/sources.list + +RUN apt-get update && apt-get install -y clang-17 lld-17 llvm-17-dev \ + libc++-17-dev libc++abi-17-dev gcc-10 gcc-10-plugin-dev libstdc++-10-dev \ + libssl-dev cargo autopoint + +RUN update-alternatives \ + --install /usr/lib/llvm llvm /usr/lib/llvm-17 1000 \ + --slave /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-17 \ + --slave /usr/bin/llvm-ar llvm-ar /usr/bin/llvm-ar-17 \ + --slave /usr/bin/llvm-as llvm-as /usr/bin/llvm-as-17 \ + --slave /usr/bin/llvm-bcanalyzer llvm-bcanalyzer /usr/bin/llvm-bcanalyzer-17 \ + --slave /usr/bin/llvm-c-test llvm-c-test /usr/bin/llvm-c-test-17 \ + --slave /usr/bin/llvm-cov llvm-cov /usr/bin/llvm-cov-17 \ + --slave /usr/bin/llvm-diff llvm-diff /usr/bin/llvm-diff-17 \ + --slave /usr/bin/llvm-dis llvm-dis /usr/bin/llvm-dis-17 \ + --slave /usr/bin/llvm-dwarfdump llvm-dwarfdump /usr/bin/llvm-dwarfdump-17 \ + --slave /usr/bin/llvm-extract llvm-extract /usr/bin/llvm-extract-17 \ + --slave /usr/bin/llvm-link llvm-link /usr/bin/llvm-link-17 \ + --slave /usr/bin/llvm-mc llvm-mc /usr/bin/llvm-mc-17 \ + --slave /usr/bin/llvm-nm llvm-nm /usr/bin/llvm-nm-17 \ + --slave /usr/bin/llvm-objdump llvm-objdump /usr/bin/llvm-objdump-17 \ + --slave /usr/bin/llvm-ranlib llvm-ranlib /usr/bin/llvm-ranlib-17 \ + --slave /usr/bin/llvm-readobj llvm-readobj /usr/bin/llvm-readobj-17 \ + --slave /usr/bin/llvm-rtdyld llvm-rtdyld /usr/bin/llvm-rtdyld-17 \ + --slave /usr/bin/llvm-size llvm-size /usr/bin/llvm-size-17 \ + --slave /usr/bin/llvm-stress llvm-stress /usr/bin/llvm-stress-17 \ + --slave /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-17 \ + --slave /usr/bin/llvm-tblgen llvm-tblgen /usr/bin/llvm-tblgen-17 + +RUN update-alternatives \ + --install /usr/bin/clang clang /usr/bin/clang-17 1000 \ + --slave /usr/bin/clang++ clang++ /usr/bin/clang++-17 \ + --slave /usr/bin/clang-cpp clang-cpp /usr/bin/clang-cpp-17 \ + --slave /usr/bin/ld.lld lld /usr/bin/ld.lld-17 + +# Uninstall old Rust +RUN if which rustup; then rustup self uninstall -y; fi + +# Install latest Rust +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /rustup.sh && \ + sh /rustup.sh -y + +ENV PATH="/root/.cargo/bin:${PATH}" + +RUN rm -rf /usr/local/bin/clang /usr/local/bin/clang++ /usr/local/bin/llvm* +RUN rm -rf /usr/local/lib/clang +RUN rm -rf /usr/local/include/clang +RUN rm -rf /usr/local/share/clang + +# RUN rm /usr/local/bin/clang /usr/local/bin/clang++ /usr/local/bin/clang-cpp +# ENV PATH="/usr/bin:/usr/local/bin:$PATH" + +# RUN ls /usr/lib/llvm-17/include/llvm && exit 1 + +# RUN clang --version | grep "clang version 17" || { echo "Clang version is not 17"; exit 1; } + +RUN git clone -b fx-no-tail-opt1 https://github.com/fEst1ck/path-cov.git /path-cov + +RUN cd /path-cov && \ + git checkout bb900e89e14766ebd9d4af27cae0862bdb37de9b && \ + cargo build --release + +RUN git clone -b edge-priority-old-driver https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl + +# RUN clang++-17 -v -E -x c++ - < /dev/null && eixt 1 + +RUN cd /path-afl && \ + which clang-17 && \ + which clang && \ + clang --version && \ + clang++ -stdlib=libstdc++ -c hashcompare.cpp && \ + ar rcs libhashcompare.a hashcompare.o && \ + cp /path-cov/target/release/libpath_reduction.so . + +# RUN which llvm-config-17 || { echo "llvm-config-17 not found"; exit 1; } + +RUN cd /path-afl && \ + export CC=clang && \ + export CXX=clang++ && \ + export AFL_NO_X86=1 && \ + unset CFLAGS CXXFLAGS && \ + PYTHON_INCLUDE=/ && \ + LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lstdc++ -lpath_reduction" make +# RUN export CC=clang && \ +# export CXX=clang++ && \ +# export AFL_NO_X86=1 && \ +# export PYTHON_INCLUDE=/ && \ +# LLVM_CONFIG=llvm-config-17 LD_LIBRARY_PATH="/path-afl" CFLAGS="-I/path-afl/fuzzing_support" LDFLAGS="-L/path-afl -lcrypto -lhashcompare -lstdc++ -lpath_reduction" make -e -C utils/aflpp_driver || exit 1 + +RUN apt install g++ + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cd /path-afl && cp utils/aflpp_driver/libAFLDriver.a / + +RUN cp /usr/lib/x86_64-linux-gnu/libpython3.8.so.1.0 / + +RUN cp /usr/lib/llvm-17/lib/libc++.so.1 / +RUN cp /usr/lib/llvm-17/lib/libc++abi.so.1 / + diff --git a/fuzzers/path_afl_old_driver/fuzzer.py b/fuzzers/path_afl_old_driver/fuzzer.py new file mode 100644 index 000000000..06d25c0d1 --- /dev/null +++ b/fuzzers/path_afl_old_driver/fuzzer.py @@ -0,0 +1,155 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Integration code for pathAFL fuzzer.""" + +import os +import shutil +import subprocess + +from fuzzers import utils + + +def prepare_build_environment(): + """Set environment variables used to build targets for pathAFL-based + fuzzers.""" + os.environ["LD_LIBRARY_PATH"] = "/path-afl" + os.environ["CC"] = "/path-afl/afl-clang-fast" + os.environ["CXX"] = "/path-afl/afl-clang-fast++" + current_directory = os.getcwd() + os.environ["BBIDFILE"] = os.path.join(current_directory, "bbid.txt") + os.environ["CALLMAPFILE"] = os.path.join(current_directory, "callmap.txt") + os.environ["CFGFILE"] = os.path.join(current_directory, "cfg.txt") + os.environ["FUZZER"] = "/path-afl" + os.environ["AFL_LLVM_CALLER"] = "1" + os.environ["FUZZER_LIB"] = "/libAFLDriver.a" + + +def build(): + """Build benchmark.""" + prepare_build_environment() + + utils.build_benchmark() + + subprocess.run( + 'cat cfg.txt | grep "BasicBlock: " | wc -l > bbnum.txt', + shell=True, + check=True, + ) + print(f"/out/{os.getenv('FUZZ_TARGET')}") + result = subprocess.run( + [ + "bash", + "/path-afl/fuzzing_support/filterCFGandCallmap.sh", + f"/out/{os.getenv('FUZZ_TARGET')}", + ], + check=False, + capture_output=True, + text=True, + ) + print(result.stdout) + print(result.stderr) + subprocess.run( + "cat cfg_filtered.txt | grep \"Function: \" | nl -v 0 | " + "awk '{print $1, $3, $4, $5, $6, $7, $8, $9}' > function_list.txt", + shell=True, + check=True, + ) + subprocess.run( + "g++ -I/path-afl/fuzzing_support " + "/path-afl/fuzzing_support/convert.cpp -o convert", + shell=True, + check=True, + ) + subprocess.run("./convert", shell=True, check=True) + + print("[post_build] Copying afl-fuzz to $OUT directory") + + # Copy out the afl-fuzz binary as a build artifact. + shutil.copy("/path-afl/libpath_reduction.so", os.environ["OUT"]) + shutil.copy("/path-afl/afl-fuzz", os.environ["OUT"]) + shutil.copy("./top.bin", os.environ["OUT"]) + shutil.copy("/libpython3.8.so.1.0", os.environ["OUT"]) + src = "/usr/lib/llvm-17/lib" + dst = os.environ["OUT"] + shutil.copytree(src, dst, dirs_exist_ok=True) + + +def prepare_fuzz_environment(input_corpus): + """Prepare to fuzz with AFL or another AFL-based fuzzer.""" + # Tell AFL to not use its terminal UI so we get usable logs. + os.environ["AFL_NO_UI"] = "1" + # Skip AFL's CPU frequency check (fails on Docker). + os.environ["AFL_SKIP_CPUFREQ"] = "1" + # No need to bind affinity to one core, Docker enforces 1 core usage. + os.environ["AFL_NO_AFFINITY"] = "1" + # AFL will abort on startup if the core pattern sends notifications to + # external programs. We don't care about this. + os.environ["AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES"] = "1" + # Don't exit when crashes are found. This can happen when corpus from + # OSS-Fuzz is used. + os.environ["AFL_SKIP_CRASHES"] = "1" + # Shuffle the queue + os.environ["AFL_SHUFFLE_QUEUE"] = "1" + os.environ["CFG_BIN_FILE"] = "./top.bin" + os.environ["LD_LIBRARY_PATH"] = ( + f'./lib:{os.getcwd()}:{os.environ["LD_LIBRARY_PATH"]}') + + # AFL needs at least one non-empty seed to start. + utils.create_seed_file_for_empty_corpus(input_corpus) + + +def run_afl_fuzz( + input_corpus, + output_corpus, + target_binary, + hide_output=False, +): + """Run afl-fuzz.""" + # Spawn the afl fuzzing process. + print("[run_afl_fuzz] Running target with afl-fuzz") + command = [ + "./afl-fuzz", + "-Z", + "-i", + input_corpus, + "-o", + output_corpus, + # Use no memory limit as ASAN doesn't play nicely with one. + "-m", + "none", + "-t", + "1000+", # Use same default 1 sec timeout, but add '+' to skip hangs. + ] + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + command.extend(["-x", dictionary_path]) + command += [ + "--", + target_binary, + # Pass INT_MAX to afl the maximize the number of persistent loops it + # performs. + "2147483647", + ] + print("[run_afl_fuzz] Running command: " + " ".join(command)) + output_stream = subprocess.DEVNULL if hide_output else None + subprocess.check_call(command, stdout=output_stream, stderr=output_stream) + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run afl-fuzz on target.""" + prepare_fuzz_environment(input_corpus) + + os.environ["K"] = "42" + + run_afl_fuzz(input_corpus, output_corpus, target_binary) diff --git a/fuzzers/path_afl_old_driver/runner.Dockerfile b/fuzzers/path_afl_old_driver/runner.Dockerfile new file mode 100644 index 000000000..2b5dd351d --- /dev/null +++ b/fuzzers/path_afl_old_driver/runner.Dockerfile @@ -0,0 +1,26 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM gcr.io/fuzzbench/base-image + +RUN apt-get update +RUN apt-get install -y python3.8 + +# This makes interactive docker runs painless: +ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/out" +#ENV AFL_MAP_SIZE=2621440 +ENV PATH="$PATH:/out" +ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +ENV AFL_TESTCACHE_SIZE=2 \ No newline at end of file From 0c95e2d73c979221e13e4b07ab0f1ebdac7c24cf Mon Sep 17 00:00:00 2001 From: Zekun Wang Date: Sat, 22 Feb 2025 00:56:15 -0500 Subject: [PATCH 23/23] use commit --- fuzzers/path_afl/builder.Dockerfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fuzzers/path_afl/builder.Dockerfile b/fuzzers/path_afl/builder.Dockerfile index 49d8b4eeb..cc05697f5 100644 --- a/fuzzers/path_afl/builder.Dockerfile +++ b/fuzzers/path_afl/builder.Dockerfile @@ -88,7 +88,10 @@ RUN cd /path-cov && \ git checkout bb900e89e14766ebd9d4af27cae0862bdb37de9b && \ cargo build --release -RUN git clone -b edge-priority https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl +RUN git clone https://github.com/path-cov-fuzzer/newpathAFLplusplus.git /path-afl + +RUN cd /path-afl && \ + git checkout 8634aeacb16de6cbab20f4b6f4ef23368fc1ae25 # RUN clang++-17 -v -E -x c++ - < /dev/null && eixt 1