├── example ├── input.txt ├── usesec20 │ ├── jsmn │ │ ├── perf_function_list.txt │ │ ├── Makefile │ │ ├── experiment.md │ │ ├── bench.c │ │ └── fuzz.c │ ├── http │ │ ├── Makefile │ │ ├── perf_function_list.txt │ │ ├── experiment.md │ │ └── fuzz.c │ ├── brotli │ │ ├── Makefile │ │ ├── experiment.md │ │ └── perf_function_list.txt │ ├── libyaml │ │ ├── experiment.md │ │ ├── fuzzer.c │ │ ├── Makefile │ │ └── perf_function_list.txt │ ├── libhtp │ │ ├── experiment.md │ │ ├── Makefile │ │ └── perf_function_list.txt │ ├── openssl │ │ ├── experiment.md │ │ ├── Makefile │ │ └── fuzz │ │ │ └── driver.c │ ├── README.md │ ├── common.mk │ └── slh-wrapper.sh ├── sizes.c ├── demo.c ├── Makefile └── fuzz.c ├── postprocessing ├── __init__.py ├── aggregate_rlbk_stats.awk └── build_report.awk ├── install ├── patches │ ├── README.md │ ├── llvm │ │ ├── CMakeLists.txt │ │ ├── X86.h │ │ ├── sanitizer_coverage_libcdep_new.cc │ │ ├── asan_poisoning.cc │ │ └── X86TargetMachine.cpp │ └── honggfuzz │ │ ├── instrument.c │ │ ├── honggfuzz.h │ │ └── fuzz.c ├── honggfuzz.sh ├── llvm.sh ├── common.sh └── wrapper.sh ├── tests ├── dummy.c ├── Makefile ├── acceptance-switch.c ├── acceptance-basic.c ├── raw-sample.json ├── rtl_rlbk.S ├── rtl_chkp.S ├── acceptance-mmul.c ├── common │ ├── header.S │ └── process_state.S ├── rtl_report.S ├── rtl_chkp_rlbk.S ├── analyzer_unit.py ├── run.bats └── aggregated-sample.json ├── LICENSE ├── src ├── specfuzz_cov.c ├── specfuzz_rtl.h └── specfuzz_init.c ├── Makefile └── README.md /example/input.txt: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /postprocessing/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /install/patches/README.md: -------------------------------------------------------------------------------- 1 | This directory contains patches for tools that require tweaking to be used with SpecFuzz. -------------------------------------------------------------------------------- /tests/dummy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, const char *argv[]) { 5 | printf("Hello World!\n"); 6 | return 0; 7 | } -------------------------------------------------------------------------------- /example/usesec20/jsmn/perf_function_list.txt: -------------------------------------------------------------------------------- 1 | dump 2 | jsmn_parse 3 | jsmn_alloc_token 4 | jsmn_parse_string 5 | jsmn_parse_primitive 6 | jsmn_init 7 | jsmn_fill_token -------------------------------------------------------------------------------- /example/sizes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | size_t array1_size = 10; 5 | size_t array2_size = 10; 6 | 7 | uint8_t array1[10] = {0}; 8 | uint8_t array2[10] = {0}; 9 | uint8_t temp = 0; -------------------------------------------------------------------------------- /example/usesec20/jsmn/Makefile: -------------------------------------------------------------------------------- 1 | SRC := fuzz jsmn 2 | ifdef PERF 3 | SRC := bench jsmn 4 | endif 5 | 6 | VPATH := . 7 | 8 | CFLAGS := -I. 9 | 10 | include ../common.mk 11 | 12 | clean: 13 | rm -f *.o $(ALL_TYPES) -------------------------------------------------------------------------------- /example/usesec20/http/Makefile: -------------------------------------------------------------------------------- 1 | SRC := fuzz http_parser 2 | 3 | ifdef PERF 4 | SRC := bench http_parser 5 | endif 6 | 7 | VPATH := . 8 | 9 | CFLAGS := -I. -DHTTP_PARSER_STRICT=1 10 | 11 | include ../common.mk 12 | 13 | clean: 14 | rm -f *.o $(ALL_TYPES) -------------------------------------------------------------------------------- /example/usesec20/http/perf_function_list.txt: -------------------------------------------------------------------------------- 1 | http_parser_execute 2 | parse_url_char 3 | http_message_needs_eof 4 | http_should_keep_alive 5 | http_method_str 6 | http_status_str 7 | http_parser_init 8 | http_parser_settings_init 9 | http_errno_name 10 | http_errno_description 11 | http_parser_url_init 12 | http_parser_parse_url 13 | http_parse_host 14 | http_parser_pause 15 | http_body_is_final 16 | http_parser_version 17 | http_parser_set_max_header_size 18 | http_parse_host_char -------------------------------------------------------------------------------- /example/usesec20/brotli/Makefile: -------------------------------------------------------------------------------- 1 | SRC := $(patsubst %.c,%,$(wildcard c/dec/*.c)) $(patsubst %.c,%,$(wildcard c/common/*.c)) c/fuzz/decode_fuzzer c/fuzz/run_decode_fuzzer 2 | ifdef PERF 3 | SRC := $(patsubst %.c,%,$(wildcard c/dec/*.c)) $(patsubst %.c,%,$(wildcard c/enc/*.c)) $(patsubst %.c,%,$(wildcard c/common/*.c)) c/tools/brotli 4 | endif 5 | 6 | VPATH := c 7 | 8 | include ../common.mk 9 | CFLAGS += -Ic/include -Wno-pointer-sign 10 | LDFLAGS += -lm 11 | 12 | clean: 13 | rm -f c/common/*.o c/dec/*.o c/fuzz/*.o $(ALL_TYPES) -------------------------------------------------------------------------------- /example/demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | extern size_t array1_size, array2_size; 6 | extern uint8_t temp, array2[], array1[]; 7 | 8 | void victim_function(size_t x) { 9 | if (x < array1_size) { 10 | temp &= array2[array1[x] * 512]; 11 | } 12 | } 13 | 14 | int main(int argc, char **argv) { 15 | if (argc != 2) { 16 | printf("USAGE: %s \n", argv[0]); 17 | exit(1); 18 | } 19 | 20 | int index = atoi(argv[1]); 21 | victim_function(index); 22 | printf("r = %d\n", temp); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | CC ?= clang 2 | CFLAGS ?= -O3 -ggdb 3 | RTLIB ?= -lspecfuzz 4 | 5 | .SUFFIXES: # disable built-in rules 6 | .PHONY: all 7 | 8 | TESTS := dummy rtl_chkp rtl_chkp_rlbk acceptance-basic acceptance-mmul 9 | 10 | 11 | all: 12 | echo "no default" 13 | 14 | %: %.S libtest.a 15 | $(CC) $(CFLAGS) $< -o $@ $(RTLIB) -ltest -L. -fsanitize=address 16 | 17 | %: %.c libtest.a 18 | $(CC) $(CFLAGS) $< -o $@ $(RTLIB) 19 | 20 | libtest.a: common/process_state.S 21 | # here, we must use a normal, non-SpecFuzz compiler to avoid the instrumentation 22 | gcc $(CFLAGS) common/process_state.S -c -o process_state.o 23 | ar rc $@ process_state.o 24 | rm process_state.o 25 | 26 | clean: 27 | rm -f *.o $(TESTS) 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | SpecFuzz: A tool to enable fuzzing for Spectre vulnerabilities 2 | Copyright (C) 2020 Oleksii Oleksenko 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . -------------------------------------------------------------------------------- /install/honggfuzz.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "Installing HonggFuzz..." 4 | if [ -z ${INSTALL_DIR} ] ; then echo "Env. variable INSTALL_DIR must be set!" ; exit 1; fi 5 | # shellcheck source=common.sh 6 | source "$(dirname "$0")"/common.sh 7 | 8 | NAME="honggfuzz" 9 | VERSION="589a9fb92" 10 | 11 | WORK_DIR="${INSTALL_DIR}/${NAME}-${VERSION}" # the directory where we link the sources and build them 12 | SRC_DIR="${WORK_DIR}/src" 13 | BUILD_DIR="${WORK_DIR}/build" 14 | 15 | mkdir -p ${WORK_DIR} 16 | 17 | # download 18 | clone_git_repo https://github.com/google/honggfuzz.git ${SRC_DIR} ${VERSION} "" 19 | 20 | # configure 21 | mkdir -p ${BUILD_DIR} 22 | cd ${SRC_DIR} || exit 23 | 24 | # install 25 | make -j8 26 | make -j8 install 27 | 28 | echo "HonggFuzz is installed" 29 | -------------------------------------------------------------------------------- /tests/acceptance-switch.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int my_switch(int a) { 4 | switch (a) { 5 | case 0: 6 | a = 0; 7 | break; 8 | case 1: 9 | a = 3; 10 | break; 11 | case 2: 12 | a = 5; 13 | break; 14 | case 3: 15 | a = 7; 16 | break; 17 | case 4: 18 | a = 11; 19 | break; 20 | case 5: 21 | a = 13; 22 | break; 23 | case 6: 24 | a = 17; 25 | break; 26 | default: 27 | a = 19; 28 | break; 29 | } 30 | return a; 31 | } 32 | 33 | int main(int argc, char **argv) { 34 | int a = atoi(argv[1]); 35 | return my_switch(a); 36 | } -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | NAME := demo 2 | SRC := demo sizes 3 | 4 | CC = clang 5 | CXX = clang++ 6 | CFLAGS := -fsanitize=address -O3 -ggdb 7 | 8 | CCSF = clang-sf 9 | CXXSF = clang-sf++ 10 | SF_CFLAGS := -fsanitize=address -O3 -ggdb --enable-coverage 11 | HONGGFUZZ_LDFLAGS := -L${HONGG_SRC}/libhfuzz/ -L${HONGG_SRC}/libhfcommon -lhfuzz -lhfcommon 12 | 13 | all: sf 14 | 15 | native: $(addsuffix .o, $(SRC)) 16 | $(CC) $(CFLAGS) $? -o $(NAME)-native 17 | 18 | %.o: %.c 19 | $(CC) $(CFLAGS) $< -c -o $@ 20 | 21 | sf: $(addsuffix .sf.o, $(SRC)) 22 | $(CCSF) $(SF_CFLAGS) $? -o $(NAME)-sf 23 | 24 | %.sf.o: %.c 25 | $(CCSF) $(SF_CFLAGS) $< -c -o $@ 26 | 27 | fuzz: fuzz.sf.o sizes.sf.o 28 | $(CCSF) $(HONGGFUZZ_LDFLAGS) $(SF_CFLAGS) $? -o fuzz 29 | 30 | clean: 31 | rm -f *.o $(NAME)-native $(NAME)-sf fuzz -------------------------------------------------------------------------------- /tests/acceptance-basic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int array_before[] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; 6 | int array[] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; 7 | int array_next[] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; 8 | int temp; 9 | char two_pages[2 * 4096] __attribute__((aligned (4096))); 10 | 11 | int main(int argc, char **argv) { 12 | int index = atoi(argv[1]); 13 | void *invalid_page = &two_pages[4096]; 14 | munmap(invalid_page, 4096); 15 | //printf("invalid range: %p - %p ; pointer %p\n", 16 | // invalid_page, 17 | // invalid_page + 4096, 18 | // &two_pages[index]); 19 | 20 | if (index < 10) { 21 | temp &= array[index]; 22 | temp += two_pages[index]; 23 | } else { 24 | temp = 0; 25 | } 26 | printf("r = %d\n", temp); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /src/specfuzz_cov.c: -------------------------------------------------------------------------------- 1 | //===-------- specfuzz_cov.c ------------------------------------------------===// 2 | // 3 | // Copyright: This file is distributed under the GPL version 3 License. 4 | // See LICENSE for details. 5 | // 6 | //===------------------------------------------------------------------------===// 7 | /// \file 8 | /// 9 | /// Dummy default implementations of SpecFuzz coverage functions. 10 | /// Used mainly for testing 11 | /// 12 | /// The corresponding strong symbols must be defined by the fuzzer 13 | //===------------------------------------------------------------------------===// 14 | #include "specfuzz_rtl.h" 15 | 16 | void specfuzz_cov_init() {} 17 | 18 | __attribute__((weak)) __attribute__((preserve_most)) 19 | void specfuzz_cov_trace_pc(uintptr_t pc) { 20 | branch_execution_count = 1; 21 | } 22 | 23 | __attribute__((weak)) 24 | void specfuzz_cov_vuln(uintptr_t pc) {} -------------------------------------------------------------------------------- /tests/raw-sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [], 3 | "statistics": { 4 | "coverage": [ 5 | 12.34, 6 | 2345 7 | ], 8 | "branches": 1, 9 | "faults": 1 10 | }, 11 | "branches": { 12 | "10": { 13 | "address": "0xa", 14 | "faults": [], 15 | "fault_count": 1, 16 | "nonspeculative_execution_count": 2 17 | } 18 | }, 19 | "faults": { 20 | "17": { 21 | "address": "0x11", 22 | "accessed_addresses": [ 23 | 42 24 | ], 25 | "offsets": [], 26 | "branch_sequences": [ 27 | [ 28 | "0xa", 29 | "0xb" 30 | ], 31 | [ 32 | "0xc" 33 | ] 34 | ], 35 | "order": 1, 36 | "fault_count": 3, 37 | "controlled": false, 38 | "controlled_offset": false, 39 | "types": [ 40 | 2, 41 | 11 42 | ] 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/rtl_rlbk.S: -------------------------------------------------------------------------------- 1 | .include "common/header.S" 2 | 3 | .macro TEST id fn_name 4 | PREPARE_CORRUPTION_TEST \id 42 5 | CALL_RTL_FUNCTION \fn_name 6 | EXECUTE_CORRUPTION_TEST 42 1 7 | .endm 8 | 9 | .text 10 | .globl main 11 | .p2align 4, 0x90 12 | .type main, @function 13 | main: 14 | RESET_META 15 | movq $0, nesting_level 16 | TEST 1 specfuzz_rlbk_if_done 17 | 18 | movq $1, nesting_level 19 | movq $10, instruction_counter 20 | TEST 2 specfuzz_rlbk_if_done 21 | 22 | movq $0, nesting_level 23 | TEST 3 specfuzz_rlbk_forced 24 | 25 | movq $0, nesting_level 26 | TEST 4 specfuzz_rlbk_external_call 27 | 28 | movq $0, nesting_level 29 | TEST 5 specfuzz_rlbk_indirect_call 30 | 31 | movq $0, nesting_level 32 | TEST 6 specfuzz_rlbk_serializing 33 | 34 | movq $0, nesting_level 35 | TEST 7 specfuzz_rlbk_patched 36 | 37 | movq $0, %rax 38 | ret 39 | -------------------------------------------------------------------------------- /example/usesec20/http/experiment.md: -------------------------------------------------------------------------------- 1 | When building for the first time, collect a function list: 2 | 3 | ```shell script 4 | make sf SF_COLLECT=1 5 | make clean 6 | ``` 7 | 8 | Build fuzzer: 9 | 10 | ```shell script 11 | make sf 12 | ``` 13 | 14 | Fuzzing: 15 | 16 | ```shell script 17 | honggfuzz --run_time 3600 --exit_upon_crash -Q --no_fb_timeout 1 --timeout 120 -n 1 -f http-corpus/ -l hongg.log -- ./sf ___FILE___ 2>&1 | analyzer collect -r hongg.log -o analyzer.json -b sf >errors.log 2>&1 18 | ``` 19 | 20 | Build a whitelist: 21 | 22 | ```shell script 23 | analyzer minimize analyzer.json -o minimal.json 24 | analyzer aggregate minimal.json -s $(llvm-7.0.1-config --sfdir)/llvm-symbolizer -b ./sf -o aggregated.json 25 | analyzer query aggregated.json -o whitelist.txt 26 | ``` 27 | 28 | Build a patched binary: 29 | 30 | ```shell script 31 | make patched PERF=1 32 | ``` 33 | 34 | Performance: 35 | 36 | ```shell script 37 | ./patched large.txt 38 | ``` -------------------------------------------------------------------------------- /example/usesec20/jsmn/experiment.md: -------------------------------------------------------------------------------- 1 | When building for the first time, collect a function list: 2 | 3 | ```shell script 4 | make sf SF_COLLECT=1 5 | make clean 6 | ``` 7 | 8 | Build fuzzer: 9 | 10 | ```shell script 11 | make sf 12 | ``` 13 | 14 | Fuzzing: 15 | 16 | ```shell script 17 | honggfuzz --run_time 3600 --exit_upon_crash -Q --no_fb_timeout 1 --timeout 120 -n 1 -f jsmn-corpus/ -l hongg.log -- ./sf ___FILE___ 2>&1 | analyzer collect -r hongg.log -o analyzer.json -b sf >errors.log 2>&1 18 | ``` 19 | 20 | Build a whitelist: 21 | 22 | ```shell script 23 | analyzer minimize analyzer.json -o minimal.json 24 | analyzer aggregate minimal.json -s $(llvm-7.0.1-config --sfdir)/llvm-symbolizer -b ./sf -o aggregated.json 25 | analyzer query aggregated.json -o whitelist.txt 26 | ``` 27 | 28 | Build a patched binary: 29 | 30 | ```shell script 31 | make patched PERF=1 32 | ``` 33 | 34 | Performance: 35 | 36 | ```shell script 37 | ./patched perf.json 38 | ``` -------------------------------------------------------------------------------- /example/fuzz.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | extern size_t array1_size, array2_size; 6 | extern uint8_t temp, array2[], array1[]; 7 | 8 | void victim_function(size_t x) { 9 | if (x < array1_size) { 10 | temp &= array2[array1[x] * 512]; 11 | } 12 | } 13 | 14 | int main(int argc, char **argv) { 15 | if (argc != 2) { 16 | printf("USAGE: %s \n", argv[0]); 17 | exit(1); 18 | } 19 | 20 | FILE *f = fopen(argv[1], "r"); 21 | if (!f) { 22 | fprintf(stderr, "Failed to open input file."); 23 | exit(1); 24 | } 25 | 26 | char value[1024]; 27 | fscanf(f, " %1023s", value); 28 | if (ferror(f)) { 29 | fclose(f); 30 | fprintf(stderr, "Failed read input file."); 31 | exit(1); 32 | } 33 | 34 | int index = atoi(value); 35 | victim_function(index); 36 | printf("r = %d\n", temp); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /example/usesec20/libyaml/experiment.md: -------------------------------------------------------------------------------- 1 | When building for the first time, collect a function list: 2 | 3 | ```shell script 4 | make sf SF_COLLECT=1 5 | make clean 6 | ``` 7 | 8 | Build fuzzer: 9 | 10 | ```shell script 11 | make sf 12 | ``` 13 | 14 | Fuzzing: 15 | 16 | ```shell script 17 | honggfuzz --run_time 3600 --exit_upon_crash -Q --no_fb_timeout 1 --timeout 120 -n 1 -f libyaml-corpus/ -l hongg.log -- ./sf ___FILE___ 2>&1 | analyzer collect -r hongg.log -o analyzer.json -b sf >errors.log 2>&1 18 | ``` 19 | 20 | Build a whitelist: 21 | 22 | ```shell script 23 | analyzer minimize analyzer.json -o minimal.json 24 | analyzer aggregate minimal.json -s $(llvm-7.0.1-config --sfdir)/llvm-symbolizer -b ./sf -o aggregated.json 25 | analyzer query aggregated.json -o whitelist.txt 26 | ``` 27 | 28 | Build a patched binary: 29 | 30 | ```shell script 31 | make patched PERF=1 32 | ``` 33 | 34 | Performance: 35 | 36 | ```shell script 37 | ./patched large.yaml 38 | ``` -------------------------------------------------------------------------------- /example/usesec20/libhtp/experiment.md: -------------------------------------------------------------------------------- 1 | When building for the first time, collect a function list: 2 | 3 | ```shell script 4 | make sf SF_COLLECT=1 5 | make clean 6 | ``` 7 | 8 | Build fuzzer: 9 | 10 | ```shell script 11 | make sf 12 | ``` 13 | 14 | Fuzzing: 15 | 16 | ```shell script 17 | honggfuzz --run_time 3600 --exit_upon_crash -Q --no_fb_timeout 1 --timeout 120 -n 1 -f libhtp-corpus/ -l hongg.log -- ./sf ___FILE___ 2>&1 | analyzer collect -r hongg.log -o analyzer.json -b sf >errors.log 2>&1 18 | ``` 19 | 20 | Build a whitelist: 21 | 22 | ```shell script 23 | analyzer minimize analyzer.json -o minimal.json 24 | analyzer aggregate minimal.json -s $(llvm-7.0.1-config --sfdir)/llvm-symbolizer -b ./sf -o aggregated.json 25 | analyzer query aggregated.json -o whitelist.txt 26 | ``` 27 | 28 | Build a patched binary: 29 | 30 | ```shell script 31 | make patched PERF=1 32 | ``` 33 | 34 | Performance: 35 | 36 | ```shell script 37 | srcdir=test/files ./patched --gtest_filter=Benchmark.ConnectionWithManyTransactions 38 | ``` -------------------------------------------------------------------------------- /example/usesec20/brotli/experiment.md: -------------------------------------------------------------------------------- 1 | When building for the first time, collect a function list: 2 | 3 | ```shell script 4 | make sf SF_COLLECT=1 5 | make clean 6 | ``` 7 | 8 | Build fuzzer: 9 | 10 | ```shell script 11 | make sf 12 | ``` 13 | 14 | Fuzz: 15 | 16 | ```shell script 17 | honggfuzz --run_time 3600 --exit_upon_crash -Q --no_fb_timeout 1 --timeout 120 -n 1 -f brotli-corpus/ -l hongg.log -- ./sf ___FILE___ 2>&1 | analyzer collect -r hongg.log -o analyzer.json -b sf >errors.log 2>&1 18 | ``` 19 | 20 | Build a whitelist: 21 | 22 | ```shell script 23 | analyzer minimize analyzer.json -o minimal.json 24 | analyzer aggregate minimal.json -s $(llvm-7.0.1-config --sfdir)/llvm-symbolizer -b ./sf -o aggregated.json 25 | analyzer query aggregated.json -o whitelist.txt 26 | ``` 27 | 28 | Build a patched binary: 29 | 30 | ```shell script 31 | make patched PERF=1 32 | ``` 33 | 34 | Performance: 35 | 36 | ```shell script 37 | ./patched --decompress enwik9.br -f 38 | ``` 39 | 40 | Input file: http://www.mattmahoney.net/dc/textdata.html -------------------------------------------------------------------------------- /tests/rtl_chkp.S: -------------------------------------------------------------------------------- 1 | .include "common/header.S" 2 | 3 | .macro TEST id 4 | PREPARE_CORRUPTION_TEST \id 42 5 | CALL_RTL_FUNCTION specfuzz_chkp 6 | jmp 1f // imitate instrumentation 7 | 1: 8 | EXECUTE_CORRUPTION_TEST 42 0 9 | .endm 10 | 11 | .macro TEST_WITH_META id 12 | PREPARE_CORRUPTION_TEST \id 42 13 | CALL_RTL_FUNCTION specfuzz_chkp 14 | jmp 1f // imitate instrumentation 15 | 1: 16 | EXECUTE_CORRUPTION_TEST 42 1 17 | .endm 18 | 19 | .text 20 | .globl main 21 | .p2align 4, 0x90 22 | .type main, @function 23 | main: 24 | RESET_META 25 | 26 | # default behavior 27 | TEST 1 28 | 29 | # configuration variants 30 | movq $1, disable_speculation 31 | TEST_WITH_META 2 32 | 33 | movq $1, nesting_level 34 | movq $10, instruction_counter # needs to be set. Otherwise, RTL will execute a rollback 35 | TEST 3 36 | 37 | movq $2, nesting_level # larger than max_nesting_level 38 | movq $10, instruction_counter 39 | TEST 4 40 | 41 | movq $0, %rax 42 | ret 43 | -------------------------------------------------------------------------------- /tests/acceptance-mmul.c: -------------------------------------------------------------------------------- 1 | //===------------------------------------------------------------------------===// 2 | /// \file 3 | /// A tiny acceptance test to ensure that instrumentation does not do 4 | /// major state corruptions 5 | /// 6 | /// Based on simple matrix multiplication 7 | //===------------------------------------------------------------------------===// 8 | 9 | #include 10 | 11 | int matA[2][2] = {0, 1, 2, 3}; 12 | int matB[2][2] = {4, 5, 6, 7}; 13 | int matC[2][2]; // 6 7 26 31 14 | 15 | __attribute__((noinline)) 16 | void multiply(int i, int j, int N) { 17 | int k; 18 | for (k = 0; k < N; k++) { 19 | matC[i][j] += matA[i][k] * matB[k][j]; 20 | } 21 | } 22 | 23 | __attribute__((noinline)) 24 | int sum() { 25 | int total = 0; 26 | for (int i = 0; i < 2; i++) { 27 | for (int j = 0; j < 2; j++) { 28 | total += matC[i][j]; 29 | } 30 | } 31 | return total; 32 | } 33 | 34 | int main() { 35 | int i, j; 36 | 37 | for (i = 0; i < 2; i++) { 38 | for (j = 0; j < 2; j++) { 39 | matC[i][j] = 0; 40 | multiply(i, j, 2); 41 | } 42 | } 43 | printf("%d\n", sum()); 44 | return 0; 45 | } -------------------------------------------------------------------------------- /example/usesec20/openssl/experiment.md: -------------------------------------------------------------------------------- 1 | For this benchmark, it's better to put the Makefile somewhere outside the OpenSSL source code directory. You would need to change the `LIB_DIR` variable to point to this source code directory. 2 | 3 | Also, don't forget to replace the original OpenSSL fuzzing driver (`fuzz/driver.c`) with our version. 4 | 5 | All the next steps are the same as for the other benchmarks. 6 | 7 | --- 8 | 9 | When building for the first time, collect a function list: 10 | 11 | ```shell script 12 | make sf SF_COLLECT=1 13 | make clean 14 | ``` 15 | 16 | Build fuzzer: 17 | 18 | ```shell script 19 | make sf 20 | ``` 21 | 22 | Fuzzing: 23 | 24 | ```shell script 25 | honggfuzz --run_time 3600 --exit_upon_crash -Q --no_fb_timeout 1 --timeout 120 -n 1 -f openssl-corpus/ -l hongg.log -- ./sf ___FILE___ 2>&1 | analyzer collect -r hongg.log -o analyzer.json -b sf >errors.log 2>&1 26 | ``` 27 | 28 | Build a whitelist: 29 | 30 | ```shell script 31 | analyzer minimize analyzer.json -o minimal.json 32 | analyzer aggregate minimal.json -s $(llvm-7.0.1-config --sfdir)/llvm-symbolizer -b ./sf -o aggregated.json 33 | analyzer query aggregated.json -o whitelist.txt 34 | ``` 35 | 36 | Build a patched binary: 37 | 38 | ```shell script 39 | make patched PERF=1 40 | ``` 41 | 42 | Performance: 43 | 44 | ```shell script 45 | ./patched speed -multi 4 rsa dsa ecdsa 46 | ``` 47 | -------------------------------------------------------------------------------- /tests/common/header.S: -------------------------------------------------------------------------------- 1 | .extern set_state 2 | .extern store_stack_state 3 | .extern store_metadata 4 | .extern check_state 5 | .extern specfuzz_chkp 6 | .extern current_rsp 7 | .extern log_test_start 8 | .extern log_test_end 9 | 10 | .macro LOG msg 11 | movl $\msg, %edi 12 | xorl %eax, %eax 13 | callq printf 14 | .endm 15 | 16 | .macro RESET_META 17 | movq $0, disable_speculation 18 | movq $0, nesting_level 19 | movq $specfuzz_call_type_stack, specfuzz_call_type_stack_sp 20 | movq $0, instruction_counter 21 | .endm 22 | 23 | .macro PREPARE_CORRUPTION_TEST id value 24 | movq $\id, %rsi 25 | LOG log_test_start 26 | movq $\value, %rdi 27 | callq set_state 28 | callq store_stack_state 29 | callq store_metadata 30 | .endm 31 | 32 | .macro EXECUTE_CORRUPTION_TEST value include_meta 33 | movq $\value, %rdi 34 | callq check_state 35 | cmp $0, %rax 36 | je 1f 37 | ret 38 | 1: 39 | 40 | .if \include_meta 41 | callq check_metadata 42 | .endif 43 | RESET_META 44 | LOG log_test_end 45 | .endm 46 | 47 | .macro CALL_RTL_FUNCTION fn_name 48 | movq %rsp, current_rsp 49 | leaq specfuzz_rtl_frame, %rsp 50 | callq \fn_name 51 | movq current_rsp, %rsp 52 | .endm 53 | 54 | .data 55 | log_test_start: .asciz "Running test No. %d: " 56 | log_test_end: .asciz "ok\n" 57 | -------------------------------------------------------------------------------- /tests/rtl_report.S: -------------------------------------------------------------------------------- 1 | .include "common/header.S" 2 | 3 | .macro CORRUPTION_TEST_FOR_REPORT value 4 | pushq $0x256 5 | popfq 6 | movq $\value, %rsi 7 | 8 | movq $\value, %rdi 9 | callq check_state 10 | cmp $0, %rax 11 | je 1f 12 | ret 13 | 1: 14 | LOG log_test_end 15 | .endm 16 | 17 | .macro TEST id 18 | PREPARE_CORRUPTION_TEST \id 41 19 | CALL_RTL_FUNCTION specfuzz_report 20 | CORRUPTION_TEST_FOR_REPORT 41 21 | .endm 22 | 23 | .data 24 | error_unreachable: .string "Unreachable location\n" 25 | 26 | .text 27 | .globl main 28 | .p2align 4, 0x90 29 | .type main, @function 30 | main: 31 | callq specfuzz_init 32 | RESET_META 33 | movq $42, %rdi 34 | callq set_state 35 | callq store_stack_state 36 | CALL_RTL_FUNCTION specfuzz_chkp 37 | jmp .L1 // normal 38 | jmp .L2 // simulation 39 | 40 | .L1: 41 | EXECUTE_CORRUPTION_TEST 42 0 42 | 43 | movq $0, %rax 44 | ret 45 | 46 | .L2: 47 | // report 48 | TEST 1 49 | TEST 2 // make sure we can call the report repeatedly 50 | 51 | // rollback 52 | movq $-1, instruction_counter 53 | CALL_RTL_FUNCTION specfuzz_rlbk_if_done 54 | jmp .unreachable 55 | 56 | 57 | .unreachable: 58 | xor %rdi, %rdi 59 | movl $error_unreachable, %edi 60 | movq $0, %rax 61 | call printf 62 | movq $1, %rax 63 | ret 64 | 65 | -------------------------------------------------------------------------------- /tests/rtl_chkp_rlbk.S: -------------------------------------------------------------------------------- 1 | .include "common/header.S" 2 | 3 | .data 4 | error_unreachable: .string "Unreachable location\n" 5 | 6 | .text 7 | .globl main 8 | .type main, @function 9 | main: 10 | callq specfuzz_init 11 | RESET_META 12 | 13 | # test executed rollback 14 | movq $250, instruction_counter 15 | PREPARE_CORRUPTION_TEST 1 42 16 | CALL_RTL_FUNCTION specfuzz_chkp 17 | jmp 2f // normal 18 | jmp 1f // simulation 19 | 20 | 1: 21 | // introduce some state corruption 22 | movq $41, %rdi 23 | callq set_state 24 | 25 | // rollback 26 | movq $-1, instruction_counter 27 | CALL_RTL_FUNCTION specfuzz_rlbk_if_done 28 | jmp .unreachable 29 | 30 | 2: 31 | EXECUTE_CORRUPTION_TEST 42 1 32 | 33 | # test skipped rollback 34 | movq $1, disable_speculation 35 | PREPARE_CORRUPTION_TEST 2 42 36 | CALL_RTL_FUNCTION specfuzz_chkp 37 | jmp 2f // normal 38 | jmp 1f // simulation 39 | 40 | 1: 41 | jmp .unreachable 42 | 43 | 2: 44 | movq $41, %rdi 45 | callq set_state 46 | 47 | // rollback 48 | movq $-1, instruction_counter 49 | movq $-1, previous_instruction_counter 50 | CALL_RTL_FUNCTION specfuzz_rlbk_if_done 51 | EXECUTE_CORRUPTION_TEST 41 1 52 | 53 | movq $0, %rax 54 | ret 55 | 56 | .unreachable: 57 | xor %rdi, %rdi 58 | movl $error_unreachable, %edi 59 | movq $0, %rax 60 | call printf 61 | movq $1, %rax 62 | ret -------------------------------------------------------------------------------- /example/usesec20/jsmn/bench.c: -------------------------------------------------------------------------------- 1 | #include "jsmn.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #define MAX_TOKENS 1000 * 1024 7 | jsmntok_t t[MAX_TOKENS]; 8 | 9 | #define MAX_DATA 500 * 1024 * 1024 10 | static char data[MAX_DATA]; 11 | 12 | int main(int argc, char **argv) { 13 | if (argc < 2) { 14 | printf("Usage: bench \n"); 15 | return 1; 16 | } 17 | 18 | // fuzzers usually prefer to get input from a file 19 | FILE *fp; 20 | if (!(fp = fopen(argv[1], "r"))) { 21 | printf("Unable to open %s for reading\n", argv[1]); 22 | return 1; 23 | } 24 | 25 | size_t data_len; 26 | fseek(fp, 0, SEEK_END); 27 | data_len = ftell(fp); 28 | fseek(fp, 0, SEEK_SET); 29 | 30 | // skip super long inputs 31 | if (data_len >= MAX_DATA) { 32 | return 0; 33 | } 34 | 35 | fread(data, 1, data_len, fp); 36 | fclose(fp); 37 | 38 | int i; 39 | int r; 40 | jsmn_parser p; 41 | 42 | for (int j = 0; j < 100; j++) { 43 | jsmn_init(&p); 44 | r = jsmn_parse(&p, data, data_len, t, 45 | sizeof(t) / sizeof(t[0])); 46 | if (r < 0 || r >= MAX_TOKENS) { 47 | printf("Failed to parse JSON: %d\n", r); 48 | return 1; 49 | } 50 | 51 | /* Assume the top-level element is an object */ 52 | if (r < 1 || t[0].type != JSMN_OBJECT) { 53 | printf("Object expected\n"); 54 | return 1; 55 | } 56 | } 57 | 58 | return EXIT_SUCCESS; 59 | } -------------------------------------------------------------------------------- /example/usesec20/libyaml/fuzzer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 8 | yaml_parser_t parser; 9 | yaml_parser_initialize(&parser); 10 | yaml_parser_set_input_string(&parser, data, size); 11 | 12 | int done = 0; 13 | while (!done) { 14 | yaml_event_t event; 15 | if (!yaml_parser_parse(&parser, &event)) { 16 | break; 17 | } 18 | done = (event.type == YAML_STREAM_END_EVENT); 19 | yaml_event_delete(&event); 20 | } 21 | yaml_parser_delete(&parser); 22 | } 23 | 24 | int main(int argc, char **argv) { 25 | if (argc != 2) { 26 | fprintf(stderr, "Exactly one argument is expected.\n"); 27 | exit(EXIT_FAILURE); 28 | } 29 | 30 | FILE *f = fopen(argv[1], "r"); 31 | if (!f) { 32 | fprintf(stderr, "Failed to open input file."); 33 | exit(EXIT_FAILURE); 34 | } 35 | 36 | size_t max_len = 1 << 20; 37 | unsigned char *tmp = (unsigned char *) malloc(max_len); 38 | size_t len = fread(tmp, 1, max_len, f); 39 | if (ferror(f)) { 40 | fclose(f); 41 | fprintf(stderr, "Failed read input file."); 42 | exit(EXIT_FAILURE); 43 | } 44 | /* Make data after the end "inaccessible". */ 45 | unsigned char *data = (unsigned char *) malloc(len); 46 | memcpy(data, tmp, len); 47 | free(tmp); 48 | 49 | LLVMFuzzerTestOneInput(data, len); 50 | free(data); 51 | exit(EXIT_SUCCESS); 52 | } 53 | -------------------------------------------------------------------------------- /postprocessing/aggregate_rlbk_stats.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/gawk -f 2 | 3 | function sorted_print(map, threshold, total, sims, total_simulations) { 4 | for (key in map) { 5 | inverted_map[map[key]/sims[key]] = key 6 | } 7 | 8 | n = asorti(inverted_map, sorted, "@ind_num_desc") 9 | sum = 0.0 10 | for (i = 1; i <= n; i++) { 11 | #rate = (sorted[i] / total) * 100 12 | printf("%s\t%.4f\n", inverted_map[sorted[i]], sorted[i]) 13 | #sum += rate 14 | sum += 1 15 | if (sum > threshold) { 16 | break 17 | } 18 | } 19 | return str 20 | } 21 | 22 | 23 | BEGIN { 24 | simulation_id = -1 25 | } 26 | 27 | /\[SF\] rlbk:/ { 28 | if ($6 != simulation_id) { 29 | simulation_id = $6 30 | simulations[$3] += 1 31 | total_simulations++ 32 | } 33 | rollbacks[$3] += 1 34 | weighted_simulations[$3] += $4 35 | depth[$4 - $4 % 50] += 1; 36 | nesting[$5] += 1; 37 | 38 | total_rollbacks++ 39 | total_depth += $4 40 | } 41 | 42 | END { 43 | print "* Depths:" 44 | for (d in depth) { 45 | #printf("%s: \t%.4f ", (250 - d), (depth[d] / total_rollbacks) * 100) 46 | printf("%s:\t", (250 - d)) 47 | rate = (depth[d] / total_rollbacks) * 100 48 | for (i=0; i < rate ; i++) { 49 | printf("*") 50 | } 51 | printf("\n") 52 | } 53 | 54 | printf("\n* Nestings:\n") 55 | for (n in nesting) { 56 | printf("%s: %.2f%\n", n, (nesting[n] / total_rollbacks) * 100) 57 | } 58 | 59 | printf("\n* rollbacks\n") 60 | sorted_print(rollbacks, threshold, total_rollbacks, simulations, total_simulations) 61 | } 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /example/usesec20/libyaml/Makefile: -------------------------------------------------------------------------------- 1 | SRC:= 2 | LIB_DIR:=. 3 | 4 | include ../common.mk 5 | 6 | ifdef PERF 7 | TARGET=run-loader 8 | else 9 | TARGET=fuzzer 10 | endif 11 | 12 | native: 13 | cd $(LIB_DIR) && \ 14 | CC=$(CC) CXX=$(CXX) CFLAGS="$(CFLAGS) $(NATIVE_FLAGS)" CXXFLAGS="$(CFLAGS) $(NATIVE_FLAGS)" LDFLAGS="$(LDFLAGS) $(NATIVE_LDFLAGS)" \ 15 | ./configure --disable-shared 16 | $(MAKE) run_build 17 | cp $(LIB_DIR)/tests/$(TARGET) $@ 18 | 19 | nativecov: 20 | cd $(LIB_DIR) && \ 21 | CC=$(CCSF) CXX=$(CXXSF) CFLAGS="$(CFLAGS) $(NATIVECOV_FLAGS)" CXXFLAGS="$(CFLAGS) $(NATIVECOV_FLAGS)" LDFLAGS="$(LDFLAGS) $(NATIVECOV_LDFLAGS)" \ 22 | ./configure --disable-shared 23 | $(MAKE) run_build 24 | cp $(LIB_DIR)/tests/$(TARGET) $@ 25 | 26 | sf: 27 | cd $(LIB_DIR) && \ 28 | CC=$(CCSF) CXX=$(CXXSF) CFLAGS="$(CFLAGS) $(SF_FLAGS)" CXXFLAGS="$(CFLAGS) $(SF_FLAGS)" LDFLAGS="$(LDFLAGS) $(SF_LDFLAGS)" \ 29 | ./configure --disable-shared 30 | $(MAKE) run_build 31 | cp $(LIB_DIR)/tests/$(TARGET) $@ 32 | 33 | slh: 34 | cd $(LIB_DIR) && \ 35 | CC=$(CCSLH) CXX=$(CXXSLH) CFLAGS="$(CFLAGS) $(SLH_FLAGS)" CXXFLAGS="$(CFLAGS) $(SLH_FLAGS)" LDFLAGS="$(LDFLAGS) $(SLH_LDFLAGS)" \ 36 | ./configure --disable-shared 37 | $(MAKE) run_build 38 | cp $(LIB_DIR)/tests/$(TARGET) $@ 39 | 40 | patched: 41 | cd $(LIB_DIR) && \ 42 | CC=$(CCSLH) CXX=$(CXXSLH) CFLAGS="$(CFLAGS) $(PATCH_FLAGS)" CXXFLAGS="$(CFLAGS) $(PATCH_FLAGS)" LDFLAGS="$(LDFLAGS) $(PATCH_LDFLAGS)" \ 43 | ./configure --disable-shared 44 | $(MAKE) run_build 45 | cp $(LIB_DIR)/tests/$(TARGET) $@ 46 | 47 | run_build: 48 | $(MAKE) -C $(LIB_DIR) clean 49 | $(MAKE) -j8 -C $(LIB_DIR) 50 | $(MAKE) -j8 -C $(LIB_DIR)/tests $(TARGET) 51 | 52 | clean: 53 | rm -f *.o $(ALL_TYPES) 54 | -------------------------------------------------------------------------------- /example/usesec20/libhtp/Makefile: -------------------------------------------------------------------------------- 1 | SRC:= 2 | LIB_DIR:=. 3 | 4 | include ../common.mk 5 | CFLAGS+=-Wno-mismatched-tags 6 | 7 | ifdef PERF 8 | TARGET=test_bench 9 | else 10 | TARGET=test_fuzz 11 | endif 12 | 13 | native: 14 | cd $(LIB_DIR) && CC=$(CC) CXX=$(CXX) CFLAGS="$(CFLAGS) $(NATIVE_FLAGS)" CXXFLAGS="$(CFLAGS) $(NATIVE_FLAGS)" LDFLAGS="$(LDFLAGS) $(NATIVE_LDFLAGS)" ./configure --disable-shared 15 | $(MAKE) run_build 16 | cp $(LIB_DIR)/test/$(TARGET) $@ 17 | 18 | nativecov: 19 | cd $(LIB_DIR) && CC=$(CCSF) CXX=$(CXXSF) CFLAGS="$(CFLAGS) $(NATIVECOV_FLAGS)" CXXFLAGS="$(CFLAGS) $(NATIVECOV_FLAGS)" LDFLAGS="$(LDFLAGS) $(NATIVECOV_LDFLAGS)" ./configure --disable-shared 20 | $(MAKE) run_build 21 | cp $(LIB_DIR)/test/$(TARGET) $@ 22 | 23 | sf: 24 | cd $(LIB_DIR) && CC=$(CCSF) CXX=$(CXXSF) CFLAGS="$(CFLAGS) $(SF_FLAGS)" CXXFLAGS="$(CFLAGS) $(SF_FLAGS)" LDFLAGS="$(LDFLAGS) $(SF_LDFLAGS)" ./configure --disable-shared 25 | $(MAKE) run_build 26 | cp $(LIB_DIR)/test/$(TARGET) $@ 27 | 28 | slh: 29 | cd $(LIB_DIR) && CC=$(CCSLH) CXX=$(CXXSLH) CFLAGS="$(CFLAGS) $(SLH_FLAGS)" CXXFLAGS="$(CFLAGS) $(SLH_FLAGS)" LDFLAGS="$(LDFLAGS) $(SLH_LDFLAGS)" ./configure --disable-shared 30 | $(MAKE) run_build 31 | cp $(LIB_DIR)/test/$(TARGET) $@ 32 | 33 | patched: 34 | cd $(LIB_DIR) && CC=$(CCSLH) CXX=$(CXXSLH) CFLAGS="$(CFLAGS) $(PATCH_FLAGS)" CXXFLAGS="$(CFLAGS) $(PATCH_FLAGS)" LDFLAGS="$(LDFLAGS) $(PATCH_LDFLAGS)" ./configure --disable-shared 35 | $(MAKE) run_build 36 | cp $(LIB_DIR)/test/$(TARGET) $@ 37 | 38 | run_build: 39 | $(MAKE) -C $(LIB_DIR) clean 40 | $(MAKE) -C $(LIB_DIR)/test clean 41 | ifdef PERF 42 | $(MAKE) -j12 -C $(LIB_DIR) test-compile-only 43 | else 44 | $(MAKE) -j4 -C $(LIB_DIR) 45 | $(MAKE) -j4 -C $(LIB_DIR)/test $(TARGET) 46 | endif 47 | 48 | clean: 49 | rm -f *.o $(ALL_TYPES) -------------------------------------------------------------------------------- /example/usesec20/brotli/perf_function_list.txt: -------------------------------------------------------------------------------- 1 | asan.module_ctor 2 | asan.module_dtor 3 | BrotliBuildCodeLengthsHuffmanTable 4 | BrotliBuildHuffmanTable 5 | BrotliBuildSimpleHuffmanTable 6 | BrotliCalculateRingBufferSize 7 | BrotliDecoderCreateInstance 8 | BrotliDecoderDecompress 9 | BrotliDecoderDecompressStream 10 | BrotliDecoderDestroyInstance 11 | BrotliDecoderErrorString 12 | BrotliDecoderGetErrorCode 13 | BrotliDecoderHasMoreOutput 14 | BrotliDecoderHuffmanTreeGroupInit 15 | BrotliDecoderIsFinished 16 | BrotliDecoderIsUsed 17 | BrotliDecoderSetParameter 18 | BrotliDecoderStateCleanup 19 | BrotliDecoderStateCleanupAfterMetablock 20 | BrotliDecoderStateInit 21 | BrotliDecoderStateMetablockBegin 22 | BrotliDecoderTakeOutput 23 | BrotliDecoderVersion 24 | BrotliDefaultAllocFunc 25 | BrotliDefaultFreeFunc 26 | BrotliEnsureRingBuffer 27 | BrotliGetDictionary 28 | BrotliGetTransforms 29 | BrotliInitBitReader 30 | BrotliSafeReadBits32Slow 31 | BrotliSetDictionaryData 32 | BrotliTransformDictionaryWord 33 | BrotliWarmupBitReader 34 | CalculateDistanceLut 35 | CopyUncompressedBlockToOutput 36 | DecodeCommandBlockSwitch 37 | DecodeContextMap 38 | DecodeDistanceBlockSwitch 39 | DecodeLiteralBlockSwitch 40 | DecodeMetaBlockLength 41 | DecodeVarLenUint8 42 | DecodeWindowBits 43 | HuffmanTreeGroupDecode 44 | InverseMoveToFrontTransform 45 | LLVMFuzzerTestOneInput 46 | main 47 | ProcessCommands 48 | ReadCodeLengthCodeLengths 49 | ReadContextModes 50 | ReadHuffmanCode 51 | ReadSimpleHuffmanSymbols 52 | ReadSymbolCodeLengths 53 | SafeDecodeCommandBlockSwitch 54 | SafeDecodeDistanceBlockSwitch 55 | SafeDecodeLiteralBlockSwitch 56 | SafeDecodeSymbol 57 | SafeProcessCommands 58 | SafeReadSymbolCodeLengths 59 | sancov.module_ctor 60 | SaveErrorCode 61 | Shift 62 | ToUpperCase 63 | UnwrittenBytes 64 | WrapRingBuffer 65 | WriteRingBuffer 66 | -------------------------------------------------------------------------------- /example/usesec20/openssl/Makefile: -------------------------------------------------------------------------------- 1 | SRC:= 2 | LIB_DIR:=. 3 | 4 | include ../common.mk 5 | CFLAGS+=-Wno-mismatched-tags 6 | 7 | CONFIG_FLAGS=no-asm no-shared no-threads no-fips no-legacy no-tests enable-fuzz-afl \ 8 | enable-tls1_3 enable-weak-ssl-ciphers enable-rc5 enable-md2 \ 9 | enable-ssl3 enable-ssl3-method enable-nextprotoneg 10 | 11 | ifdef PERF 12 | TARGET=apps/openssl 13 | else 14 | TARGET=fuzz/server 15 | endif 16 | 17 | 18 | native: 19 | cd $(LIB_DIR) && \ 20 | ./config $(CONFIG_FLAGS) \ 21 | CC=$(CC) CXX=$(CXX) CFLAGS="$(CFLAGS) $(NATIVE_FLAGS)" CXXFLAGS="$(CFLAGS) $(NATIVE_FLAGS)" LDFLAGS="$(LDFLAGS) $(NATIVE_LDFLAGS)" 22 | $(MAKE) run_build 23 | cp $(LIB_DIR)/$(TARGET) $@ 24 | 25 | nativecov: 26 | cd $(LIB_DIR) && \ 27 | ./config $(CONFIG_FLAGS) \ 28 | CC=$(CCSF) CXX=$(CXXSF) CFLAGS="$(CFLAGS) $(NATIVECOV_FLAGS)" CXXFLAGS="$(CFLAGS) $(NATIVECOV_FLAGS)" LDFLAGS="$(LDFLAGS) $(NATIVECOV_LDFLAGS)" 29 | $(MAKE) run_build 30 | cp $(LIB_DIR)/$(TARGET) $@ 31 | 32 | sf: 33 | cd $(LIB_DIR) && \ 34 | ./config $(CONFIG_FLAGS) \ 35 | CC=$(CCSF) CXX=$(CXXSF) CFLAGS="$(CFLAGS) $(SF_FLAGS)" CXXFLAGS="$(CFLAGS) $(SF_FLAGS)" LDFLAGS="$(LDFLAGS) $(SF_LDFLAGS)" 36 | $(MAKE) run_build 37 | cp $(LIB_DIR)/$(TARGET) $@ 38 | 39 | slh: 40 | cd $(LIB_DIR) && \ 41 | ./config $(CONFIG_FLAGS) \ 42 | CC=$(CCSLH) CXX=$(CXXSLH) CFLAGS="$(CFLAGS) $(SLH_FLAGS)" CXXFLAGS="$(CFLAGS) $(SLH_FLAGS)" LDFLAGS="$(LDFLAGS) $(SLH_LDFLAGS)" 43 | $(MAKE) run_build 44 | cp $(LIB_DIR)/$(TARGET) $@ 45 | 46 | patched: 47 | cd $(LIB_DIR) && \ 48 | ./config $(CONFIG_FLAGS) \ 49 | CC=$(CCSLH) CXX=$(CXXSLH) CFLAGS="$(CFLAGS) $(PATCH_FLAGS)" CXXFLAGS="$(CFLAGS) $(PATCH_FLAGS)" LDFLAGS="$(LDFLAGS) $(PATCH_LDFLAGS)" 50 | $(MAKE) run_build 51 | cp $(LIB_DIR)/$(TARGET) $@ 52 | 53 | run_build: 54 | cd $(LIB_DIR) && $(MAKE) clean 55 | cd $(LIB_DIR) && $(MAKE) -j12 56 | 57 | clean: 58 | rm -f *.o $(ALL_TYPES) 59 | -------------------------------------------------------------------------------- /install/llvm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "Installing LLVM..." 4 | if [ -z ${INSTALL_DIR} ] ; then echo "Env. variable INSTALL_DIR must be set!" ; exit 1; fi 5 | # shellcheck source=common.sh 6 | source "$(dirname "$0")"/common.sh 7 | 8 | # == Defaults == 9 | NAME=${NAME:-"llvm"} 10 | VERSION=${VERSION:-"7.0.1"} 11 | CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE:-"Debug"} 12 | 13 | # ============ 14 | # LLVM 15 | # ============ 16 | WORK_DIR="${INSTALL_DIR}/${NAME}-${VERSION}" 17 | SRC_DIR="${WORK_DIR}/src" 18 | BUILD_DIR="${WORK_DIR}/build" 19 | 20 | mkdir -p ${WORK_DIR} 21 | 22 | # download 23 | download_and_untar http://llvm.org/releases/${VERSION}/llvm-${VERSION}.src.tar.xz ${SRC_DIR} 1 24 | 25 | # configure 26 | mkdir -p ${BUILD_DIR} 27 | cd ${BUILD_DIR} || exit 28 | cmake -G "Unix Makefiles" -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_INSTALL_PREFIX=${BUILD_DIR} ../src 29 | 30 | # install 31 | make -j8 32 | make -j8 install 33 | 34 | # ============ 35 | # CLang 36 | # ============ 37 | CLANG_DIR="${SRC_DIR}/tools/cfe-${VERSION}.src" 38 | RT_DIR="${SRC_DIR}/tools/compiler-rt-${VERSION}.src" 39 | 40 | # download 41 | download_and_untar http://llvm.org/releases/${VERSION}/cfe-${VERSION}.src.tar.xz ${CLANG_DIR} 1 42 | download_and_untar http://llvm.org/releases/${VERSION}/compiler-rt-${VERSION}.src.tar.xz ${RT_DIR} 1 43 | 44 | # configure 45 | mkdir -p ${BUILD_DIR} 46 | cd ${BUILD_DIR} || exit 47 | cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_INSTALL_PREFIX=${BUILD_DIR} ../src 48 | 49 | # install 50 | make -j8 51 | make -j8 install 52 | ln -sf ${BUILD_DIR}/bin/clang /usr/bin/clang 53 | ln -sf ${BUILD_DIR}/bin/clang++ /usr/bin/clang++ 54 | 55 | # make the LLVM installation directory discoverable 56 | ln -sf ${BUILD_DIR}/bin/llvm-config /usr/bin/${NAME}-${VERSION}-config 57 | 58 | echo "LLVM installed" 59 | -------------------------------------------------------------------------------- /src/specfuzz_rtl.h: -------------------------------------------------------------------------------- 1 | //===-------- specfuzz_rtl.h ------------------------------------------------===// 2 | // 3 | // Copyright: This file is distributed under the GPL version 3 License. 4 | // See LICENSE for details. 5 | // 6 | //===------------------------------------------------------------------------===// 7 | /// \file 8 | /// 9 | //===------------------------------------------------------------------------===// 10 | #ifndef SPECFUZZ_RTL_H 11 | #define SPECFUZZ_RTL_H 12 | #include 13 | 14 | // global variables declared in specfuzz_rtl.S 15 | extern uint64_t nesting_level; 16 | extern int64_t disable_speculation; 17 | extern uint64_t *store_log_bp; 18 | extern uint64_t branch_execution_count; 19 | 20 | extern uint64_t specfuzz_rtl_frame; 21 | extern uint64_t specfuzz_rtl_frame_bottom; 22 | 23 | extern uint64_t asan_rtl_frame; 24 | extern uint64_t asan_rtl_frame_bottom; 25 | 26 | extern uint64_t *checkpoint_sp; 27 | extern uint64_t checkpoint_stack; 28 | extern uint64_t checkpoint_stack_bottom; 29 | 30 | extern uint64_t stat_max_depth; 31 | extern uint64_t stat_forced_external_call; 32 | extern uint64_t stat_forced_indirect_call; 33 | extern uint64_t stat_forced_serializing_instruction; 34 | extern uint64_t stat_max_nesting; 35 | extern uint64_t stat_asan_overflow; 36 | extern uint64_t stat_signal_overflow; 37 | extern uint64_t stat_corrupted_code_pointer; 38 | extern uint64_t stat_signal_misc; 39 | extern uint64_t stat_simulation_disables; 40 | extern uint64_t stat_skiped_due_to_disabled; 41 | 42 | extern void specfuzz_rlbk_forced(void); 43 | 44 | // Coverage 45 | void specfuzz_cov_init(); 46 | __attribute__((weak)) __attribute__((preserve_most)) 47 | void specfuzz_cov_trace_pc(uintptr_t pc); 48 | __attribute__((weak)) 49 | void specfuzz_cov_vuln(uintptr_t pc); 50 | __attribute__((weak)) __attribute__((preserve_most)) 51 | struct map_entry_t *get_hash_map_entry(uintptr_t pc); 52 | 53 | 54 | #endif //SPECFUZZ_RTL_H 55 | -------------------------------------------------------------------------------- /example/usesec20/README.md: -------------------------------------------------------------------------------- 1 | 2 | This directory contains experiment configurations that we used in our Usenix Security'20 paper. 3 | 4 | 5 | To reproduce the result in the paper: 6 | 1. Pull the benchmarks' source code. Links and versions are below. It's important to checkout the correct version of the software: Otherwise the benchmark may not build with the given makefile or you will get different results. 7 | 2. Copy all the files from the corresponding subdirectory of `example/usesec20`. E.g., copy everything from `example/usesec20/brotli` into the directory with Brotli's source coe. 8 | 3. Follow the steps in the corresponding `experiment.md` file for each benchmark. 9 | 10 | 11 | In the evaluation, we used the following versions of the software: 12 | 13 | | Benchmark | Version | Fuzzing driver | Perf. benchmark | 14 | | ------------- |:-------------:|:-----:| ----:| 15 | | Brotli | v1.0.7 | `fuzz/run_decode_fuzzer` | `tools/brotli` | 16 | | JSMN | commit 18e9fe42cb | custom | custom | 17 | | HTTP | v2.9.2 | custom | `bench.c` | 18 | | libHTP | v0.5.30 | `test/fuzz/fuzz_htp` | `test/test_bench` | 19 | | libYAML | v0.2.2 | custom | `tests/run-loader` | 20 | | OpenSSL | v3.0.0 | `server` | `speed rsa ecdsa dsa` | 21 | 22 | Sources: 23 | * OpenSSL: https://github.com/openssl/openssl 24 | * Brotli: https://github.com/google/brotli 25 | * JSMN: https://github.com/zserge/jsmn 26 | * HTTP: https://github.com/nodejs/http-parser 27 | * libHTP: https://github.com/OISF/libhtp 28 | * libYAML: https://github.com/yaml/libyaml 29 | 30 | # On reproducing SLH results 31 | 32 | For convenience, you could use a compiler wrapper `slh-wrapper.sh` that invokes SLH with all correct flags. To install it, execute the following commands from this directory: 33 | 34 | ```shell script 35 | cp slh-wrapper.sh /usr/bin/clang-slh 36 | cp slh-wrapper.sh /usr/bin/clang-slh++ 37 | sed -i -e 's:/clang$$:/clang++:g' /usr/bin/clang-slh++ 38 | ``` 39 | -------------------------------------------------------------------------------- /example/usesec20/openssl/fuzz/driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * https://www.openssl.org/source/license.html 8 | * or in the file LICENSE in the source distribution. 9 | */ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "fuzzer.h" 16 | 17 | #ifndef OPENSSL_NO_FUZZ_LIBFUZZER 18 | 19 | int LLVMFuzzerInitialize(int *argc, char ***argv); 20 | int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len); 21 | 22 | int LLVMFuzzerInitialize(int *argc, char ***argv) 23 | { 24 | return FuzzerInitialize(argc, argv); 25 | } 26 | 27 | int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) 28 | { 29 | return FuzzerTestOneInput(buf, len); 30 | } 31 | 32 | #elif !defined(OPENSSL_NO_FUZZ_AFL) 33 | 34 | #define BUF_SIZE 65536 35 | 36 | int main(int argc, char** argv) 37 | { 38 | if (argc != 2) { 39 | fprintf(stderr, "Exactly one argument is expected.\n"); 40 | exit(EXIT_FAILURE); 41 | } 42 | 43 | FILE* f = fopen(argv[1], "r"); 44 | if (!f) { 45 | fprintf(stderr, "Failed to open input file."); 46 | exit(EXIT_FAILURE); 47 | } 48 | 49 | uint8_t *buf = malloc(BUF_SIZE); 50 | size_t size = 0; 51 | 52 | size = fread(buf, 1, BUF_SIZE, f); 53 | if (ferror(f)) { 54 | fclose(f); 55 | fprintf(stderr, "Failed read input file."); 56 | exit(EXIT_FAILURE); 57 | } 58 | 59 | FuzzerInitialize(&argc, &argv); 60 | FuzzerTestOneInput(buf, size); 61 | 62 | free(buf); 63 | fclose(f); 64 | FuzzerCleanup(); 65 | return 0; 66 | } 67 | 68 | #else 69 | 70 | #error "Unsupported fuzzer" 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /install/common.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # == Prepare a safe scripting environment == 4 | set -euo pipefail 5 | IFS=$'\n\t' 6 | 7 | # == Define common functions == 8 | function required_str { 9 | if [ -z $1 ]; then 10 | echo "The string argument is empty!" 11 | exit 1 12 | fi 13 | } 14 | 15 | # Download a tar archive from URL $1 16 | # and unpack it to $2 17 | # Set $3 to 1 to skip the uppermost directory of the archive. Otherwise, set to 0 or skip 18 | function download_and_untar { 19 | local url=$1 ; 20 | if [ -z ${url} ]; then 21 | echo "The string argument is empty!" 22 | exit 1 23 | fi 24 | local unpack_path=$2 ; 25 | if [ -z ${unpack_path} ]; then 26 | echo "The string argument is empty!" 27 | exit 1 28 | fi 29 | local strip=${3:-0} ; 30 | 31 | if [ -d ${unpack_path} ] && [ -n "$(ls -A ${unpack_path})" ]; then 32 | echo "The directory ${unpack_path} already exist." 33 | while true; do 34 | read -rp "Do you wish to reinstall ${unpack_path} [Yn]?" yn 35 | case $yn in 36 | [Yy]* ) rm -rf ${unpack_path}; break;; 37 | [Nn]* ) echo "Skip"; return;; 38 | * ) echo "Please answer 'y' or 'n'.";; 39 | esac 40 | done 41 | fi 42 | 43 | wget -N -O tmp.tar ${url} 44 | mkdir -p ${unpack_path} 45 | tar xf tmp.tar -C ${unpack_path} --strip-components=${strip} 46 | rm tmp.tar 47 | } 48 | 49 | # Clone a git repo from URL $1 50 | # to directory $2 51 | # Optionally, checkout $3 52 | # Optionally, apply path $4 53 | function clone_git_repo { 54 | local url=$1 ; required_str ${url} 55 | local path=$2 ; required_str ${path} 56 | local checkout=$3 57 | local applypatch=$4 58 | 59 | if [ -d ${path} ] && [ -n "$(ls -A ${path})" ]; then 60 | echo "The directory ${path} already exist." 61 | while true; do 62 | read -rp "Do you wish to reinstall ${path} [Yn]?" yn 63 | case $yn in 64 | [Yy]* ) rm -rf ${path}; break;; 65 | [Nn]* ) echo "Skip"; return;; 66 | * ) echo "Please answer 'y' or 'n'.";; 67 | esac 68 | done 69 | fi 70 | 71 | set +e 72 | git clone ${url} ${path} 73 | set -e 74 | 75 | pushd ${path} 76 | if [ -n "${checkout}" ]; then 77 | git checkout ${checkout} 78 | fi 79 | if [ -n "${applypatch}" ]; then 80 | git apply ${applypatch} 81 | fi 82 | popd 83 | } 84 | -------------------------------------------------------------------------------- /install/patches/llvm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(LLVM_TARGET_DEFINITIONS X86.td) 2 | 3 | tablegen(LLVM X86GenAsmMatcher.inc -gen-asm-matcher) 4 | tablegen(LLVM X86GenAsmWriter.inc -gen-asm-writer) 5 | tablegen(LLVM X86GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1) 6 | tablegen(LLVM X86GenCallingConv.inc -gen-callingconv) 7 | tablegen(LLVM X86GenDAGISel.inc -gen-dag-isel) 8 | tablegen(LLVM X86GenDisassemblerTables.inc -gen-disassembler) 9 | tablegen(LLVM X86GenEVEX2VEXTables.inc -gen-x86-EVEX2VEX-tables) 10 | tablegen(LLVM X86GenFastISel.inc -gen-fast-isel) 11 | tablegen(LLVM X86GenGlobalISel.inc -gen-global-isel) 12 | tablegen(LLVM X86GenInstrInfo.inc -gen-instr-info) 13 | tablegen(LLVM X86GenRegisterBank.inc -gen-register-bank) 14 | tablegen(LLVM X86GenRegisterInfo.inc -gen-register-info) 15 | tablegen(LLVM X86GenSubtargetInfo.inc -gen-subtarget) 16 | 17 | if (X86_GEN_FOLD_TABLES) 18 | tablegen(LLVM X86GenFoldTables.inc -gen-x86-fold-tables) 19 | endif() 20 | 21 | add_public_tablegen_target(X86CommonTableGen) 22 | 23 | set(sources 24 | ShadowCallStack.cpp 25 | SpecFuzzPass.cpp 26 | X86AsmPrinter.cpp 27 | X86CallFrameOptimization.cpp 28 | X86CallingConv.cpp 29 | X86CallLowering.cpp 30 | X86CmovConversion.cpp 31 | X86DomainReassignment.cpp 32 | X86ExpandPseudo.cpp 33 | X86FastISel.cpp 34 | X86FixupBWInsts.cpp 35 | X86FixupLEAs.cpp 36 | X86AvoidStoreForwardingBlocks.cpp 37 | X86FixupSetCC.cpp 38 | X86FlagsCopyLowering.cpp 39 | X86FloatingPoint.cpp 40 | X86FrameLowering.cpp 41 | X86InstructionSelector.cpp 42 | X86ISelDAGToDAG.cpp 43 | X86ISelLowering.cpp 44 | X86IndirectBranchTracking.cpp 45 | X86InterleavedAccess.cpp 46 | X86InstrFMA3Info.cpp 47 | X86InstrFoldTables.cpp 48 | X86InstrInfo.cpp 49 | X86EvexToVex.cpp 50 | X86LegalizerInfo.cpp 51 | X86MCInstLower.cpp 52 | X86MachineFunctionInfo.cpp 53 | X86MacroFusion.cpp 54 | X86OptimizeLEAs.cpp 55 | X86PadShortFunction.cpp 56 | X86RegisterBankInfo.cpp 57 | X86RegisterInfo.cpp 58 | X86RetpolineThunks.cpp 59 | X86SelectionDAGInfo.cpp 60 | X86ShuffleDecodeConstantPool.cpp 61 | X86SpeculativeLoadHardening.cpp 62 | X86Subtarget.cpp 63 | X86TargetMachine.cpp 64 | X86TargetObjectFile.cpp 65 | X86TargetTransformInfo.cpp 66 | X86VZeroUpper.cpp 67 | X86WinAllocaExpander.cpp 68 | X86WinEHState.cpp 69 | ) 70 | 71 | add_llvm_target(X86CodeGen ${sources}) 72 | 73 | add_subdirectory(AsmParser) 74 | add_subdirectory(Disassembler) 75 | add_subdirectory(InstPrinter) 76 | add_subdirectory(MCTargetDesc) 77 | add_subdirectory(TargetInfo) 78 | add_subdirectory(Utils) 79 | -------------------------------------------------------------------------------- /example/usesec20/http/fuzz.c: -------------------------------------------------------------------------------- 1 | /* Copyright Fedor Indutny. All rights reserved. 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to 5 | * deal in the Software without restriction, including without limitation the 6 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | */ 21 | #include "http_parser.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #define MAX_DATA 1024 * 1024 28 | static char data[MAX_DATA]; 29 | 30 | static http_parser_settings settings = { 31 | .on_message_begin = 0, 32 | .on_headers_complete = 0, 33 | .on_message_complete = 0, 34 | .on_header_field = 0, 35 | .on_header_value = 0, 36 | .on_url = 0, 37 | .on_status = 0, 38 | .on_body = 0 39 | }; 40 | 41 | int main(int argc, char **argv) { 42 | if (argc < 2) { 43 | printf("Usage: fuzz \n"); 44 | return 1; 45 | } 46 | 47 | // fuzzers usually prefer to get input from a file 48 | FILE *fp; 49 | if (!(fp = fopen(argv[1], "r"))) { 50 | printf("Unable to open %s for reading\n", argv[1]); 51 | return 1; 52 | } 53 | 54 | size_t data_len; 55 | fseek(fp, 0, SEEK_END); 56 | data_len = ftell(fp); 57 | fseek(fp, 0, SEEK_SET); 58 | 59 | // skip super long inputs 60 | if (data_len >= MAX_DATA) { 61 | return 0; 62 | } 63 | 64 | fread(data, 1, data_len, fp); 65 | fclose(fp); 66 | 67 | http_parser *parser = malloc(sizeof(http_parser)); 68 | http_parser_init(parser, HTTP_REQUEST); 69 | 70 | size_t parsed; 71 | parsed = http_parser_execute(parser, &settings, data, data_len); 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /example/usesec20/common.mk: -------------------------------------------------------------------------------- 1 | ifndef SRC 2 | $(warning warning: SRC is not specified (ignore this warning if the benchmark overwrites the build targets.)) 3 | endif 4 | 5 | ifndef HONGG_SRC 6 | $(error HONGG_SRC is not specified. Run: `$ export HONGG_SRC=/path/to/honggfuzz/src`) 7 | endif 8 | 9 | CFLAGS += $(if $(OPT),$(OPT),-O3) -ggdb 10 | LDFLAGS += $(if $(OPT),$(OPT),-O3) -ggdb 11 | 12 | .SUFFIXES: # disable built-in rules 13 | .PHONY: all 14 | 15 | all: sf 16 | 17 | # Native builds 18 | CC = /usr/bin/clang 19 | CXX = /usr/bin/clang++ 20 | NATIVE_FLAGS := 21 | NATIVE_LDFLAGS := 22 | 23 | native: $(addsuffix .o, $(SRC)) 24 | $(CC) $(LDFLAGS) $(NATIVE_LDFLAGS) $? -o $@ 25 | 26 | %.o: %.c 27 | $(CC) $(CFLAGS) $(NATIVE_FLAGS) $< -c -o $@ 28 | 29 | 30 | # Native with coverage 31 | CCSF = /usr/bin/clang-sf 32 | CXXSF = /usr/bin/clang-sf++ 33 | NATIVECOV_FLAGS := --coverage-only hongg 34 | NATIVECOV_LDFLAGS := --coverage-only hongg 35 | 36 | nativecov: $(addsuffix .nativecov.o, $(SRC)) 37 | $(CCSF) $(LDFLAGS) $(NATIVECOV_LDFLAGS) $? -o $@ 38 | 39 | %.nativecov.o: %.c 40 | $(CCSF) $(CFLAGS) $(NATIVECOV_FLAGS) $< -c -o $@ 41 | 42 | 43 | # SpecFuzz build 44 | HONGGFUZZ_FLAGS := -L${HONGG_SRC}/libhfuzz/ -L${HONGG_SRC}/libhfcommon -lhfuzz -lhfcommon 45 | SF_COMMON := --function-list $(CURDIR)/function_list.txt --enable-coverage -DNDEBUG 46 | ifdef SF_COLLECT 47 | SF_COMMON := --collect $(CURDIR)/function_list.txt 48 | endif 49 | SF_FLAGS := $(SF_COMMON) 50 | SF_LDFLAGS := $(SF_COMMON) $(HONGGFUZZ_FLAGS) 51 | 52 | sf: $(addsuffix .sf.o, $(SRC)) 53 | $(CCSF) $(LDFLAGS) $(SF_LDFLAGS) $? -o $@ 54 | 55 | %.sf.o: %.c 56 | $(CCSF) $(CFLAGS) $(SF_FLAGS) $< -c -o $@ 57 | 58 | 59 | # SLH pass 60 | CCSLH = /usr/bin/clang-slh 61 | CXXSLH = /usr/bin/clang-slh++ 62 | SLH_COMMON := --whitelist $(CURDIR)/$(WHITELIST) --whitelist-loads $(CURDIR)/loadlist.txt --whitelist-files $(CURDIR)/perf_function_list.txt 63 | SLH_FLAGS := $(SLH_COMMON) 64 | SLH_LDFLAGS := $(SLH_COMMON) 65 | 66 | slh: $(addsuffix .slh.o, $(SRC)) 67 | $(CCSLH) $(LDFLAGS) $(SLH_LDFLAGS) $? -o $@ 68 | 69 | %.slh.o: %.c 70 | $(CCSLH) $(CFLAGS) $(SLH_FLAGS) $< -c -o $@ 71 | 72 | 73 | # Patch with LFENCE based on SpecFuzz results 74 | WHITELIST ?= whitelist.txt # generated by SpecFuzz 75 | PATCH_COMMON := --lfence --whitelist $(CURDIR)/$(WHITELIST) --whitelist-files $(CURDIR)/perf_function_list.txt 76 | ifdef PATCH_BLACKLIST 77 | PATCH_COMMON += --lfence-branches-as-blacklist 78 | endif 79 | PATCH_FLAGS := $(PATCH_COMMON) 80 | PATCH_LDFLAGS := $(PATCH_COMMON) 81 | 82 | patched: $(addsuffix .patched.o, $(SRC)) 83 | $(CCSLH) $(LDFLAGS) $(PATCH_LDFLAGS) $? -o $@ 84 | 85 | %.patched.o: %.c 86 | $(CCSLH) $(CFLAGS) $(PATCH_FLAGS) $< -c -o $@ 87 | -------------------------------------------------------------------------------- /example/usesec20/jsmn/fuzz.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "jsmn.h" 7 | 8 | /* 9 | * Read JSON from a file and printing its content to stdout. 10 | * The output looks like YAML, but I'm not sure if it's really compatible. 11 | */ 12 | 13 | static int dump(const char *js, jsmntok_t *t, size_t count, int indent) { 14 | int i, j, k; 15 | if (count == 0) { 16 | printf("No tokens\n"); 17 | return 0; 18 | } 19 | if (t->type == JSMN_PRIMITIVE) { 20 | printf("%.*s", t->end - t->start, js+t->start); 21 | return 1; 22 | } else if (t->type == JSMN_STRING) { 23 | printf("'%.*s'", t->end - t->start, js+t->start); 24 | return 1; 25 | } else if (t->type == JSMN_OBJECT) { 26 | printf("\n"); 27 | j = 0; 28 | for (i = 0; i < t->size; i++) { 29 | for (k = 0; k < indent; k++) printf(" "); 30 | j += dump(js, t+1+j, count-j, indent+1); 31 | printf(": "); 32 | j += dump(js, t+1+j, count-j, indent+1); 33 | printf("\n"); 34 | } 35 | return j+1; 36 | } else if (t->type == JSMN_ARRAY) { 37 | j = 0; 38 | printf("\n"); 39 | for (i = 0; i < t->size; i++) { 40 | for (k = 0; k < indent-1; k++) printf(" "); 41 | printf(" - "); 42 | j += dump(js, t+1+j, count-j, indent+1); 43 | printf("\n"); 44 | } 45 | return j+1; 46 | } 47 | return 0; 48 | } 49 | 50 | #define MAX_TOKENS 1000 * 1024 51 | jsmntok_t tokens[MAX_TOKENS]; 52 | 53 | #define MAX_DATA 500 * 1024 * 1024 54 | static char data[MAX_DATA]; 55 | 56 | int main(int argc, char **argv) { 57 | if (argc < 2) { 58 | printf("Usage: fuzz \n"); 59 | return 1; 60 | } 61 | 62 | // fuzzers usually prefer to get input from a file 63 | FILE *fp; 64 | if (!(fp = fopen(argv[1], "r"))) { 65 | printf("Unable to open %s for reading\n", argv[1]); 66 | return 1; 67 | } 68 | 69 | size_t data_len; 70 | fseek(fp, 0, SEEK_END); 71 | data_len = ftell(fp); 72 | fseek(fp, 0, SEEK_SET); 73 | 74 | // skip super long inputs 75 | if (data_len >= MAX_DATA) { 76 | return 0; 77 | } 78 | 79 | fread(data, 1, data_len, fp); 80 | fclose(fp); 81 | 82 | int r; 83 | int tok_count = 0; 84 | jsmn_parser p; 85 | 86 | jsmn_init(&p); 87 | tok_count = jsmn_parse(&p, data, data_len, NULL, 1); 88 | if (tok_count < 0) { 89 | printf("Parsing error %d\n", tok_count); 90 | return 1; 91 | } 92 | if (tok_count >= MAX_TOKENS) { 93 | printf("Too many tokens"); 94 | return 0; 95 | } 96 | // printf("Token count %d\n", tok_count); 97 | 98 | jsmn_init(&p); 99 | r = jsmn_parse(&p, data, data_len, tokens, tok_count); 100 | if (r == JSMN_ERROR_NOMEM) { 101 | printf("Out of memory\n"); 102 | return 1; 103 | } else if (r < 0) { 104 | printf("Parsing error %d\n", tok_count); 105 | return 1; 106 | } 107 | 108 | return EXIT_SUCCESS; 109 | } 110 | -------------------------------------------------------------------------------- /postprocessing/build_report.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/gawk -f 2 | function filter(str) { 3 | gsub("killed", "", str) 4 | gsub("renamable", "", str) 5 | gsub("", "", str) 6 | gsub("implicit .[a-z]+,", "", str) 7 | gsub("implicit-def .[a-z]+,", "", str) 8 | gsub("debug-location ![0-9]+", "", str) 9 | gsub(" +", " ", str) 10 | gsub(/^[ \t]+/, "", str) 11 | return str 12 | } 13 | 14 | BEGIN { 15 | bt_initialized = 0; 16 | } 17 | 18 | /\*+ SpecFuzz :/ { 19 | current_function = $4 20 | } 21 | 22 | /Blacklisted/ { 23 | blacklisted[current_function] = 1 24 | } 25 | 26 | /Instrumenting an indirect branch/ { 27 | gsub("Instrumenting an indirect branch:", "", $0) 28 | $0 = filter($0) 29 | indirect_branches[$0] = current_function 30 | } 31 | 32 | /Instrumenting an indirect call/ { 33 | gsub("Instrumenting an indirect call:", "", $0) 34 | $0 = filter($0) 35 | indirect_calls[$0] = current_function 36 | } 37 | 38 | /Instrumenting a call to an external function/ { 39 | gsub("Instrumenting a call to an external function:", "", $0) 40 | $0 = filter($0) 41 | if (match($2, "@") != 0) { 42 | external_calls[$1 " " $2] = current_function 43 | } else { 44 | external_calls[$0] = current_function 45 | } 46 | } 47 | 48 | /Instrumenting a call to an ASan function/ { 49 | gsub("Instrumenting a call to an ASan function:", "", $0) 50 | $0 = filter($0) 51 | if (match($2, "@") != 0) { 52 | asan_calls[$1 " " $2] = current_function 53 | } else { 54 | asan_calls[$0] = current_function 55 | } 56 | } 57 | 58 | /Instrumenting a serializing instruction/ { 59 | $1=""; $2=""; $3=""; $4=""; 60 | $0 = filter($0) 61 | serializing[$0] = current_function 62 | } 63 | 64 | 65 | END { 66 | print "Blacklisted functions:" 67 | for (f in blacklisted) { 68 | print f; 69 | } 70 | 71 | printf "\nBranch Table is initialized: " 72 | if (bt_initialized == 0) { 73 | print "Yes" 74 | } else { 75 | print "No" 76 | } 77 | 78 | printf "\nIndirect branches:\n" 79 | n = asorti(indirect_branches, sorted) 80 | for (i in sorted) { 81 | printf("%s in %s\n", sorted[i], indirect_branches[sorted[i]]) 82 | } 83 | 84 | printf "\nIndirect calls:\n" 85 | n = asorti(indirect_calls, sorted) 86 | for (i in sorted) { 87 | printf("%s in %s\n", sorted[i], indirect_calls[sorted[i]]) 88 | } 89 | 90 | printf "\nExternal calls:\n" 91 | n = asorti(external_calls, sorted) 92 | for (i in sorted) { 93 | printf("%s in %s\n", sorted[i], external_calls[sorted[i]]) 94 | } 95 | 96 | printf "\nASan calls:\n" 97 | n = asorti(asan_calls, sorted) 98 | for (i in sorted) { 99 | printf("%s in %s\n", sorted[i], asan_calls[sorted[i]]) 100 | } 101 | 102 | printf "\nSerializing instructions:\n" 103 | n = asorti(serializing, sorted) 104 | for (i in sorted) { 105 | printf("%s in %s\n", sorted[i], serializing[sorted[i]]) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /example/usesec20/libyaml/perf_function_list.txt: -------------------------------------------------------------------------------- 1 | asan.module_ctor 2 | asan.module_dtor 3 | compare_documents 4 | compare_events 5 | compare_nodes 6 | copy_document 7 | copy_event 8 | get_anchor 9 | get_line 10 | get_tag 11 | get_value 12 | nm_test_func 13 | print_escaped 14 | print_output 15 | yaml_alias_event_initialize 16 | yaml_document_add_mapping 17 | yaml_document_add_scalar 18 | yaml_document_add_sequence 19 | yaml_document_append_mapping_pair 20 | yaml_document_append_sequence_item 21 | yaml_document_delete 22 | yaml_document_end_event_initialize 23 | yaml_document_get_node 24 | yaml_document_get_root_node 25 | yaml_document_initialize 26 | yaml_document_start_event_initialize 27 | yaml_emitter_anchor_node 28 | yaml_emitter_append_tag_directive 29 | yaml_emitter_close 30 | yaml_emitter_delete 31 | yaml_emitter_delete_document_and_anchors 32 | yaml_emitter_dump 33 | yaml_emitter_dump_node 34 | yaml_emitter_emit 35 | yaml_emitter_emit_block_mapping_key 36 | yaml_emitter_emit_block_sequence_item 37 | yaml_emitter_emit_document_start 38 | yaml_emitter_emit_flow_mapping_key 39 | yaml_emitter_emit_flow_sequence_item 40 | yaml_emitter_emit_node 41 | yaml_emitter_flush 42 | yaml_emitter_initialize 43 | yaml_emitter_open 44 | yaml_emitter_process_anchor 45 | yaml_emitter_process_tag 46 | yaml_emitter_set_break 47 | yaml_emitter_set_canonical 48 | yaml_emitter_set_encoding 49 | yaml_emitter_set_indent 50 | yaml_emitter_set_output 51 | yaml_emitter_set_output_file 52 | yaml_emitter_set_output_string 53 | yaml_emitter_set_unicode 54 | yaml_emitter_set_width 55 | yaml_emitter_write_block_scalar_hints 56 | yaml_emitter_write_indent 57 | yaml_emitter_write_indicator 58 | yaml_emitter_write_tag_content 59 | yaml_emitter_write_tag_handle 60 | yaml_event_delete 61 | yaml_file_read_handler 62 | yaml_file_write_handler 63 | yaml_free 64 | yaml_get_version 65 | yaml_get_version_string 66 | yaml_malloc 67 | yaml_mapping_end_event_initialize 68 | yaml_mapping_start_event_initialize 69 | yaml_parser_append_tag_directive 70 | yaml_parser_delete 71 | yaml_parser_fetch_anchor 72 | yaml_parser_fetch_block_scalar 73 | yaml_parser_fetch_document_indicator 74 | yaml_parser_fetch_flow_collection_end 75 | yaml_parser_fetch_flow_collection_start 76 | yaml_parser_fetch_flow_scalar 77 | yaml_parser_fetch_more_tokens 78 | yaml_parser_fetch_next_token 79 | yaml_parser_initialize 80 | yaml_parser_load 81 | yaml_parser_load_node 82 | yaml_parser_parse 83 | yaml_parser_parse_block_mapping_key 84 | yaml_parser_parse_block_sequence_entry 85 | yaml_parser_parse_document_start 86 | yaml_parser_parse_flow_mapping_key 87 | yaml_parser_parse_flow_sequence_entry 88 | yaml_parser_parse_node 89 | yaml_parser_process_directives 90 | yaml_parser_register_anchor 91 | yaml_parser_scan 92 | yaml_parser_scan_block_scalar_breaks 93 | yaml_parser_scan_tag_handle 94 | yaml_parser_scan_tag_uri 95 | yaml_parser_scan_version_directive_number 96 | yaml_parser_set_encoding 97 | yaml_parser_set_input 98 | yaml_parser_set_input_file 99 | yaml_parser_set_input_string 100 | yaml_parser_update_buffer 101 | yaml_queue_extend 102 | yaml_realloc 103 | yaml_scalar_event_initialize 104 | yaml_sequence_end_event_initialize 105 | yaml_sequence_start_event_initialize 106 | yaml_stack_extend 107 | yaml_strdup 108 | yaml_stream_end_event_initialize 109 | yaml_stream_start_event_initialize 110 | yaml_string_extend 111 | yaml_string_join 112 | yaml_string_read_handler 113 | yaml_string_write_handler 114 | yaml_token_delete 115 | -------------------------------------------------------------------------------- /tests/analyzer_unit.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | import json 4 | 5 | sys.path.append('..') 6 | from postprocessing import analyzer 7 | 8 | 9 | class TestCollection(unittest.TestCase): 10 | def setUp(self) -> None: 11 | pass 12 | 13 | def test_minimize_sequences(self): 14 | results = analyzer.CollectedResults() 15 | fault = analyzer.Fault(1) 16 | fault.branch_sequences = { 17 | (1, 2, 3, 6), (1, 2, 3), (1, 2, 4), (2, 3, 1), (1, 1, 2, 3), (1, 2, 3, 4), 18 | (5,), (5, 5), 19 | (6, 8), (6, 7, 8)} 20 | results.faults = {1: fault} 21 | 22 | results.minimize_sequences() 23 | minimized = set([tuple(sorted(s)) for s in results.faults[1].branch_sequences]) 24 | self.assertEqual(minimized, {(1, 2, 3), (1, 2, 4), (5,), (6, 8)}) 25 | 26 | def test_minimize_accessed(self): 27 | results = analyzer.CollectedResults() 28 | fault = analyzer.Fault(1) 29 | fault.accessed_addresses = {1, 2, 3, 4, 100, 200, 300, 301, 400, 401, 402, 500, 501} 30 | results.faults = {1: fault} 31 | 32 | results.minimize_accessed_addresses() 33 | minimized = results.faults[1].accessed_addresses 34 | self.assertEqual(minimized, {1, 4, 100, 200, 300, 301, 400, 402, 500, 501}) 35 | 36 | def test_load_raw(self): 37 | results = analyzer.CollectedResults() 38 | with open("./raw-sample.json", 'r') as in_file: 39 | data = json.load(in_file) 40 | results.load(data) 41 | loaded = results.get_dict() 42 | for key, f in loaded["faults"].items(): 43 | loaded["faults"][key] = f.get_dict() 44 | for key, f in loaded["branches"].items(): 45 | loaded["branches"][key] = f.get_dict() 46 | 47 | self.assertEqual(data["faults"], loaded["faults"]) 48 | self.assertEqual(data["branches"], loaded["branches"]) 49 | 50 | def test_load_aggregated(self): 51 | symbolized_results = analyzer.SymbolizedResults() 52 | with open("./aggregated-sample.json", 'r') as in_file: 53 | data = json.load(in_file) 54 | symbolized_results.load(data) 55 | loaded = symbolized_results.get_dict() 56 | for key, f in loaded["faults"].items(): 57 | loaded["faults"][key] = f.get_dict() 58 | for key, f in loaded["branches"].items(): 59 | loaded["branches"][key] = f.get_dict() 60 | 61 | self.assertEqual(data["faults"], loaded["faults"]) 62 | self.assertEqual(data["branches"], loaded["branches"]) 63 | 64 | def test_whitelist(self): 65 | expected_controlled = ['loc-10b', 'loc-12b', 'loc-13b', 'loc-15b', 'loc-16b', 'loc-17b', 66 | 'loc-18b', 'loc-4b', 'loc-5b', 'loc-6b', 'loc-8b', 'loc-9b'] 67 | expected_controlled_offset = ['loc-10b', 'loc-12b', 'loc-13b', 'loc-15b', 'loc-16b', 68 | 'loc-17b', 'loc-18b', 'loc-4b', 'loc-5b', 'loc-6b', 'loc-8b'] 69 | expected_uncontrolled = ['loc-10b', 'loc-12b', 'loc-13b', 'loc-15b', 'loc-16b', 'loc-17b', 70 | 'loc-18b', 'loc-4b', 'loc-5b', 'loc-6b', 'loc-9b'] 71 | 72 | args = {} 73 | query = analyzer.Query("./aggregated-sample.json", args) 74 | whitelist = query.build_whitelist(exec_threshold=10, fault_threshold=10, include_controlled_offset=False) 75 | self.assertEqual(whitelist, expected_controlled) 76 | 77 | whitelist = query.build_whitelist(exec_threshold=10, fault_threshold=10) 78 | self.assertEqual(whitelist, expected_controlled_offset) 79 | 80 | whitelist = query.build_whitelist(exec_threshold=10, fault_threshold=10, 81 | include_controlled_offset=True, include_uncontrolled=True) 82 | self.assertEqual(whitelist, expected_uncontrolled) 83 | 84 | 85 | if __name__ == '__main__': 86 | unittest.main() 87 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Configuration 2 | ENABLE_PRIORITIZED_SIMULATION ?= 1 3 | REPORT_MEMORY_ERRORS ?= 1 4 | REPORT_CONTROL_FLOW_ERRORS ?= 1 5 | REPORT_WITH_OFFSET ?= 0 6 | ENABLE_COVERAGE ?= 1 7 | COVERAGE_MEMORY_ERRORS ?= 1 8 | COVERAGE_CONTROL_FLOW_ERRORS ?= 1 9 | ENABLE_SANITY_CHECKS ?= 1 10 | ENABLE_STATS ?= 0 11 | ENABLE_SEQUENTIAL_SIMULATION ?= 0 12 | DUMP_COVERAGE_AT_EXIT ?= 0 13 | PRINT_ROLLABACK_STATS ?= 0 14 | MAX_NESTING_LEVEL ?= 1 15 | 16 | RUNTIME_CONFIGURATION := -DMAX_NESTING_LEVEL=$(MAX_NESTING_LEVEL)\ 17 | -DENABLE_PRIORITIZED_SIMULATION=$(ENABLE_PRIORITIZED_SIMULATION)\ 18 | -DREPORT_MEMORY_ERRORS=$(REPORT_MEMORY_ERRORS) -DREPORT_WITH_OFFSET=$(REPORT_WITH_OFFSET)\ 19 | -DENABLE_COVERAGE=$(ENABLE_COVERAGE) -DCOVERAGE_MEMORY_ERRORS=$(COVERAGE_MEMORY_ERRORS)\ 20 | -DCOVERAGE_CONTROL_FLOW_ERRORS=$(COVERAGE_CONTROL_FLOW_ERRORS)\ 21 | -DENABLE_SANITY_CHECKS=$(ENABLE_SANITY_CHECKS)\ 22 | -DENABLE_STATS=$(ENABLE_STATS) -DENABLE_SEQUENTIAL_SIMULATION=$(ENABLE_SEQUENTIAL_SIMULATION)\ 23 | -DDUMP_COVERAGE_AT_EXIT=$(DUMP_COVERAGE_AT_EXIT) -DPRINT_ROLLABACK_STATS=$(PRINT_ROLLABACK_STATS)\ 24 | -DREPORT_CONTROL_FLOW_ERRORS=$(REPORT_CONTROL_FLOW_ERRORS) 25 | 26 | # Paths 27 | LLVM_CONFIG ?= llvm-7.0.1-config 28 | LLVM_SRC := $(shell $(LLVM_CONFIG) --src-root) 29 | COMPILER_RT_SRC ?= $(LLVM_SRC)/tools/compiler-rt-7.0.1.src 30 | LLVM_BUILD := $(shell $(LLVM_CONFIG) --bindir)/.. 31 | CLANG := $(shell $(LLVM_CONFIG) --bindir)/clang 32 | INSTALL_DIR := $(LLVM_SRC)/lib/Target/X86/ 33 | export INSTALL_DIR 34 | 35 | # Files by categories 36 | RUNTIME := src/specfuzz_rtl.S src/specfuzz_init.c src/specfuzz_cov.c 37 | LLVM_PATCH := $(wildcard install/patches/llvm/*) 38 | HONGG_PATCH := $(wildcard install/patches/honggfuzz/*) 39 | 40 | # ============= 41 | # Targets 42 | # ============= 43 | all: pass runtime patch_llvm rebuild_llvm 44 | install: install_specfuzz install_tools 45 | 46 | pass: src/SpecFuzzPass.cpp 47 | cp $< $(INSTALL_DIR)/SpecFuzzPass.cpp 48 | 49 | runtime: $(RUNTIME) 50 | ${CLANG} -O3 src/specfuzz_init.c -o specfuzz_init.o -c -ggdb3 $(RUNTIME_CONFIGURATION) 51 | ${CLANG} -O3 src/specfuzz_rtl.S -o specfuzz_rtl.o -c -ggdb3 $(RUNTIME_CONFIGURATION) 52 | ${CLANG} -O3 src/specfuzz_cov.c -o specfuzz_cov.o -c -ggdb3 $(RUNTIME_CONFIGURATION) 53 | ar rc $(LLVM_BUILD)/lib/libspecfuzz.a specfuzz_init.o specfuzz_rtl.o specfuzz_cov.o 54 | rm specfuzz_rtl.o specfuzz_init.o 55 | 56 | patch_llvm: $(LLVM_PATCH) 57 | # Connect SpecFuzz 58 | cp install/patches/llvm/CMakeLists.txt install/patches/llvm/X86.h install/patches/llvm/X86TargetMachine.cpp $(LLVM_SRC)/lib/Target/X86/ 59 | 60 | # ASan patch 61 | cp install/patches/llvm/asan_poisoning.cc install/patches/llvm/asan_rtl.cc $(COMPILER_RT_SRC)/lib/asan/ 62 | cp install/patches/llvm/sanitizer_coverage_libcdep_new.cc $(COMPILER_RT_SRC)/lib/sanitizer_common/ 63 | 64 | # SLH patch 65 | cp install/patches/llvm/X86SpeculativeLoadHardening.cpp $(LLVM_SRC)/lib/Target/X86/ 66 | 67 | rebuild_llvm: 68 | make -j -C $(LLVM_BUILD) 69 | 70 | install_specfuzz: 71 | cp -u install/wrapper.sh /usr/bin/clang-sf 72 | cp -u install/wrapper.sh /usr/bin/clang-sf++ 73 | sed -i -e 's:/clang$$:/clang++:g' /usr/bin/clang-sf++ 74 | 75 | install_tools: analyzer hongg 76 | 77 | analyzer: postprocessing/analyzer.py 78 | cp $< /usr/bin/analyzer 79 | 80 | hongg: check_hongg_path patch_hongg rebuild_hongg 81 | 82 | check_hongg_path: 83 | ifndef HONGG_SRC 84 | $(error HONGG_SRC is not set) 85 | else 86 | @echo "" 87 | endif 88 | 89 | patch_hongg: $(HONGG_PATCH) 90 | cp install/patches/honggfuzz/instrument.c $(HONGG_SRC)/libhfuzz/instrument.c 91 | cp install/patches/honggfuzz/fuzz.c $(HONGG_SRC)/fuzz.c 92 | cp install/patches/honggfuzz/honggfuzz.h $(HONGG_SRC)/honggfuzz.h 93 | cp install/patches/honggfuzz/trace.c $(HONGG_SRC)/linux/trace.c 94 | sed -i -e 's:_HF_PERSISTENT_SIG:"":g' $(HONGG_SRC)/libhfuzz/fetch.c 95 | 96 | rebuild_hongg: 97 | CC=${CLANG} CFLAGS=-ggdb make -C $(HONGG_SRC) -j4 98 | make -C $(HONGG_SRC) install 99 | 100 | test: 101 | cd tests && ./run.bats 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SpecFuzz 2 | A tool to enable fuzzing for Spectre vulnerabilities. See our [Technical Report](https://arxiv.org/abs/1905.10311) for details. 3 | 4 | SpecFuzz is no longer maintained. 5 | 6 | # Getting started 7 | 8 | ## Dependencies 9 | * Python 3.6+: [Install Python](https://www.python.org/downloads/) 10 | * Cmake: [Install CMake](https://cmake.org/install/) 11 | * LLVM 7.0.1., built from sources: 12 | ```bash 13 | $ INSTALL_DIR=/llvm/installation/directory/ ./install/llvm.sh 14 | $ /llvm/installation/directory/clang -v 15 | clang version 7.0.1 (tags/RELEASE_701/final) 16 | ... 17 | ``` 18 | 19 | If you have trouble compiling LLVM 7.0.1 with the newest glibc, try applying this patch: https://github.com/llvm/llvm-project/commit/947f9692440836dcb8d88b74b69dd379d85974ce 20 | 21 | * HonggFuzz, built from sources: 22 | ```bash 23 | $ apt-get install -y libbfd-dev libunwind8-dev binutils-dev libblocksruntime-dev 24 | $ INSTALL_DIR=/honggfuzz/installation/directory/ ./install/honggfuzz.sh 25 | $ honggfuzz 26 | Usage: honggfuzz [options] -- path_to_command [args] 27 | Options: 28 | ... 29 | ``` 30 | ## Build it 31 | ```bash 32 | $ make 33 | $ export HONGG_SRC=/honggfuzz/installation/directory/src/ 34 | $ make install 35 | $ make install_tools 36 | ``` 37 | ## Try it 38 | Build a sample vulnerable program: 39 | ```bash 40 | $ cd example 41 | $ make sf 42 | clang-sf -fsanitize=address -O1 demo.c -c -o main.sf.o 43 | clang-sf -fsanitize=address -O1 sizes.c -c -o sizes.sf.o 44 | clang-sf -fsanitize=address -O1 main.sf.o sizes.sf.o -o demo-sf 45 | ``` 46 | Try running it: 47 | ```bash 48 | $ ./demo-sf 11 49 | [SF] Starting 50 | [SF], 1, 0x123, 0x456, 0, 0x789 51 | r = 0 52 | ``` 53 | Here, the line `[SF], 1, 0x123, 0x456, 0, 0x789` means that SpecFuzz detected that the instruction 54 | at address `0x123` tried to access an invalid address `0x456`, and the speculation was triggered 55 | by a misprediction of a branch at the address `0x789`. 56 | ## Fuzz it 57 | Build a fuzzing driver: 58 | ```bash 59 | $ cd example 60 | $ export HONGG_SRC=/honggfuzz/installation/directory/src/ 61 | $ make fuzz 62 | ``` 63 | Fuzzing: 64 | ```bash 65 | $ honggfuzz --run_time 10 -Q -n 1 -f ./ -l fuzzing.log -- ./fuzz ___FILE___ 2>&1 | analyzer collect -r fuzzing.log -o results.json -b ./fuzz 66 | $ cat results.json # raw results of fuzzing 67 | { 68 | "errors": [], 69 | "statistics": { 70 | "coverage": [ 71 | 75.0, 72 | 6 73 | ], 74 | "branches": 6, 75 | "faults": 1 76 | }, 77 | "branches": { 78 | "5443896": { 79 | "address": "0x531138", 80 | "faults": [ 81 | "0x530a48" 82 | ``` 83 | 84 | **Important**: fuzz only on a single thread (`-n 1`). In the current implementation, the detected errors are reported into `stderr` and the analyzer cannot correctly separate results from different threads. 85 | 86 | Process the results: 87 | ```bash 88 | $ analyzer aggregate results.json -s $(llvm-7.0.1-config --bindir)/llvm-symbolizer -b ./fuzz -o aggregated.json 89 | ``` 90 | The final, aggregated results are in `aggregated.json`. 91 | 92 | # Development 93 | 94 | ## Testing 95 | Tests depend on bats ([Install bats](https://github.com/sstephenson/bats/wiki/Install-Bats-Using-a-Package)). 96 | ```bash 97 | $ cd tests 98 | $ ./run.sh 99 | ``` 100 | 101 | 102 | # Cite us! 103 | 104 | Paper: 105 | 106 | ``` 107 | @InProceedings{Oleksenko:2020, 108 | author={Oleksenko, Oleksii and Trach, Bohdan and Silberstein, Mark and Fetzer, Christof}, 109 | title={{SpecFuzz: Bringing Spectre-type vulnerabilities to the surface}}, 110 | booktitle={29th USENIX Security Symposium (USENIX Security)}, 111 | year={2020} 112 | } 113 | ``` 114 | 115 | Technical Report: 116 | 117 | ``` 118 | @Article{Oleksenko:2019, 119 | author={Oleksenko, Oleksii and Trach, Bohdan and Silberstein, Mark and Fetzer, Christof}, 120 | title={{SpecFuzz: Bringing Spectre-type vulnerabilities to the surface}}, 121 | journal = "", 122 | archivePrefix = "arXiv", 123 | eprint = {1905.10311}, 124 | primaryClass = "", 125 | year = {2019}, 126 | } 127 | ``` 128 | -------------------------------------------------------------------------------- /example/usesec20/slh-wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | LLVM_CONFIG=${LLVM_CONFIG:-"llvm-7.0.1-config"} 5 | CLANG_BINDIR=$(${LLVM_CONFIG} --bindir) 6 | 7 | CC=${CLANG_BINDIR}/clang 8 | LLC=${CLANG_BINDIR}/llc 9 | 10 | # make sure that external variables do not corrupt our compilation 11 | CFLAGS="" 12 | LDFLAGS="" 13 | LANGUAGE="" 14 | GGDB="" 15 | I="" 16 | INPUT="" 17 | OUTPUT="" 18 | OPT="" 19 | 20 | # configure the compiler 21 | LLCFLAGS="-x86-speculative-load-hardening -x86-speculative-load-hardening-indirect=false" 22 | 23 | flag_branch_list=0 24 | flag_load_list=0 25 | debug=0 26 | flag_lfence=0 27 | flag_file_list=0 28 | 29 | while [ "$#" -gt 0 ]; do 30 | case $1 in 31 | -o) 32 | if (($# > 1)); then 33 | OUTPUT=$2 34 | if [ "$2" == "/dev/null" ]; then 35 | DEVNULL=1 36 | fi 37 | shift 38 | fi 39 | ;; 40 | *.c|*.cc|*.cpp|-) 41 | INPUT="$INPUT $1" 42 | SOURCE=1 43 | ;; 44 | *.o|*.s|*.S|*.a) 45 | INPUT="$INPUT $1" 46 | ;; 47 | -pattern-detection|-stats|-debug) 48 | OPTFLAGS="$OPTFLAGS $1" 49 | ;; 50 | -x) 51 | LANGUAGE="$1 $2" 52 | if [ "$2" == "assembler" ]; then 53 | ASM=1 54 | fi 55 | shift 56 | ;; 57 | -c) 58 | CFLAGS="$CFLAGS $1" 59 | CREATE_OBJECT=1 60 | ;; 61 | -I|-include|-isystem) 62 | I="$I $1 $2" 63 | shift 64 | ;; 65 | -I*) 66 | I="$I $1" 67 | ;; 68 | -ggdb*|-g) 69 | GGDB="-g -gcolumn-info" 70 | ;; 71 | -O?) 72 | CFLAGS="$CFLAGS $1" 73 | OPT="$1" 74 | ;; 75 | -S) 76 | CREATE_ASM=1 77 | ;; 78 | --echo) 79 | ECHO=1 80 | ;; 81 | --debug-pass) 82 | if [ $debug == 0 ]; then 83 | LLCFLAGS+=" -debug-only=x86-speculative-load-hardening -stats" 84 | debug=1 85 | fi 86 | ;; 87 | --no-wrapper-cleanup) 88 | NO_CLEANUP=1 89 | ;; 90 | --whitelist) 91 | if [ $flag_branch_list == 0 ]; then 92 | LLCFLAGS+=" -x86-speculative-load-hardening-whitelist-branches=$2" 93 | flag_branch_list=1 94 | fi 95 | shift 96 | ;; 97 | --whitelist-loads) 98 | if [ $flag_load_list == 0 ]; then 99 | LLCFLAGS+=" -x86-speculative-load-hardening-whitelist-loads=$2" 100 | flag_load_list=1 101 | fi 102 | shift 103 | ;; 104 | --whitelist-files) 105 | if [ $flag_file_list == 0 ]; then 106 | LLCFLAGS+=" -x86-speculative-load-hardening-whitelist-modules=$2" 107 | flag_file_list=1 108 | fi 109 | shift 110 | ;; 111 | --lfence) 112 | if [ $flag_lfence == 0 ]; then 113 | LLCFLAGS+=" -x86-speculative-load-hardening-lfence" 114 | flag_lfence=1 115 | fi 116 | ;; 117 | -V|-v|-qversion) 118 | $CC -v 119 | exit $? 120 | ;; 121 | *) 122 | if [ -z "$OUTPUT" ]; then 123 | CFLAGS="$CFLAGS $1" 124 | else 125 | LDFLAGS="$LDFLAGS $1" 126 | fi 127 | ;; 128 | esac 129 | shift 130 | done 131 | 132 | if [ -z "$OUTPUT" ]; then 133 | if [ $CREATE_OBJECT ]; then 134 | OUTPUT=$(basename ${INPUT%.c*}.o) 135 | else 136 | OUTPUT="a.out" 137 | fi 138 | fi 139 | 140 | if [ -n "$SOURCE" ] && [ -z "$ASM" ] && [ -z "$DEVNULL" ]; then 141 | cmd=( $CC $CFLAGS $GGDB $I $LANGUAGE -c -emit-llvm $INPUT -o ${OUTPUT%.o}.bc ) 142 | if [ -n "$ECHO" ]; then echo "${cmd[@]}"; fi 143 | "${cmd[@]}" 144 | 145 | cmd=( $LLC $LLCFLAGS $OPT ${OUTPUT%.o}.bc -o ${OUTPUT%.o}.s ) 146 | if [ -n "$ECHO" ]; then echo "${cmd[@]}"; fi 147 | "${cmd[@]}" 148 | if [ -z "$NO_CLEANUP" ]; then rm ${OUTPUT%.o}.bc; fi 149 | 150 | if [ -z "$CREATE_ASM" ]; then 151 | cmd=( $CC -Wno-unused-command-line-argument $CFLAGS ${OUTPUT%.o}.s -o $OUTPUT $LDFLAGS ) 152 | if [ -n "$ECHO" ]; then echo "${cmd[@]}"; fi 153 | "${cmd[@]}" 154 | else 155 | cp ${OUTPUT%.o}.s ${OUTPUT%.o} 156 | fi 157 | 158 | if [ -z "$NO_CLEANUP" ]; then rm ${OUTPUT%.o}.s; fi 159 | if [ -n "$ECHO" ]; then echo "==========================================================="; fi 160 | else 161 | if [ -z "$SOURCE" ]; then 162 | I= 163 | fi 164 | 165 | cmd=( $CC $CFLAGS $GGDB $I $LANGUAGE $INPUT -o $OUTPUT $LDFLAGS ) 166 | if [ -n "$ECHO" ]; then echo "${cmd[@]}"; fi 167 | "${cmd[@]}" 168 | fi 169 | -------------------------------------------------------------------------------- /tests/common/process_state.S: -------------------------------------------------------------------------------- 1 | .data 2 | 3 | .extern printf 4 | 5 | .set EFLAGS_VALUE, 0x256 6 | 7 | .globl previous_rsp 8 | .globl previous_rbp 9 | previous_rsp: .quad 0 10 | previous_rbp: .quad 0 11 | 12 | .globl previous_instruction_counter 13 | .globl previous_nesting_level 14 | .globl previous_disable_speculation 15 | .globl previous_specfuzz_call_type_stack_sp 16 | previous_instruction_counter: .quad 0 17 | previous_nesting_level: .quad 0 18 | previous_disable_speculation: .quad 0 19 | previous_specfuzz_call_type_stack_sp: .quad 0 20 | 21 | .globl fx_frame 22 | .align 64 23 | fx_frame: .zero 512 24 | 25 | corruption_id: .quad 0 26 | error_corruption: .string "Corrupted state with id %d. See process_state.S:check_state() for details\n" 27 | 28 | // ----------------------------------------- 29 | .text 30 | /// set_state: Sets all GPRs to the same value 31 | /// rdi: the value 32 | /// 33 | .globl set_state 34 | .type set_state, @function 35 | set_state: 36 | // - FPU and SIMD states 37 | movq $0, %rax 38 | .L1: cmpq $512, %rax 39 | je .L2 40 | movq %rdi, fx_frame(%rax) 41 | addq $8, %rax 42 | jmp .L1 43 | .L2: 44 | fxrstor64 fx_frame 45 | 46 | // GPRs 47 | movq %rdi, %rax 48 | movq %rdi, %rbx 49 | movq %rdi, %rcx 50 | movq %rdi, %rdx 51 | movq %rdi, %rsi 52 | movq %rdi, %r8 53 | movq %rdi, %r9 54 | movq %rdi, %r10 55 | movq %rdi, %r11 56 | movq %rdi, %r12 57 | movq %rdi, %r13 58 | movq %rdi, %r14 59 | movq %rdi, %r15 60 | 61 | // Flags 62 | pushq $EFLAGS_VALUE 63 | popfq 64 | ret 65 | 66 | .globl store_stack_state 67 | .type store_stack_state, @function 68 | store_stack_state: 69 | movq %rsp, previous_rsp 70 | movq %rbp, previous_rbp 71 | ret 72 | 73 | .globl store_metadata 74 | .type store_metadata, @function 75 | store_metadata: 76 | pushq %rax 77 | movq instruction_counter, %rax 78 | movq %rax, previous_instruction_counter 79 | movq nesting_level, %rax 80 | movq %rax, previous_nesting_level 81 | movq disable_speculation, %rax 82 | movq %rax, previous_disable_speculation 83 | movq specfuzz_call_type_stack_sp, %rax 84 | movq %rax, previous_specfuzz_call_type_stack_sp 85 | popq %rax 86 | ret 87 | 88 | 89 | /// check_state: Check if all GPR values match the value in the argument 90 | /// rdi: the value 91 | /// 92 | .globl check_state 93 | .type check_state, @function 94 | check_state: 95 | .macro CHECK_VALUE id, register, value 96 | movq \id, corruption_id 97 | cmp \register, \value 98 | jne check_state.fail 99 | .endm 100 | 101 | // Flags 102 | pushfq 103 | cmpq $EFLAGS_VALUE, (%rsp) 104 | je .L5 105 | popfq 106 | movq $0, corruption_id 107 | jmp check_state.fail 108 | .L5: popfq 109 | 110 | // stack 111 | CHECK_VALUE $1, %rsp, previous_rsp 112 | CHECK_VALUE $2, %rbp, previous_rbp 113 | 114 | // GPRs 115 | CHECK_VALUE $3, %rdi, %rax 116 | CHECK_VALUE $4, %rdi, %rbx 117 | CHECK_VALUE $5, %rdi, %rcx 118 | CHECK_VALUE $6, %rdi, %rdx 119 | CHECK_VALUE $7, %rdi, %rsi 120 | CHECK_VALUE $8, %rdi, %r8 121 | CHECK_VALUE $9, %rdi, %r9 122 | CHECK_VALUE $10, %rdi, %r10 123 | CHECK_VALUE $11, %rdi, %r11 124 | CHECK_VALUE $12, %rdi, %r12 125 | CHECK_VALUE $13, %rdi, %r13 126 | CHECK_VALUE $14, %rdi, %r14 127 | CHECK_VALUE $15, %rdi, %r15 128 | 129 | // FPU 130 | // TODO: this code does not work - sometimes fxsave64 introduces random corruptions 131 | // needs further investigation 132 | //fxsave64 fx_frame 133 | //movq $0, %rax 134 | //.L3: addq $8, %rax // skip the first element, it's always corrupted 135 | //cmpq $512, %rax 136 | //je .L4 137 | // cmpq $24, %rax // 3rd element also always gets corrupted 138 | // je .L3 139 | // CHECK_VALUE $16, %rdi, fx_frame(%rax) 140 | // jmp .L3 141 | //.L4: 142 | 143 | check_state.success: 144 | movq $0, %rax 145 | ret 146 | 147 | check_state.fail: 148 | pushq $0x246 # just in case, overwrite EFLAGS to avoid problems with printf 149 | popfq 150 | 151 | movq corruption_id, %rsi 152 | xor %rdi, %rdi 153 | movl $error_corruption, %edi 154 | movq $0, %rax 155 | call printf 156 | 157 | movq $1, %rax 158 | ret 159 | 160 | /// Check integrity of global variables 161 | /// 162 | .globl check_metadata 163 | .type check_metadata, @function 164 | check_metadata: 165 | .macro CHECK_GLOBAL id, value, prev_value 166 | movq \id, corruption_id 167 | movq \prev_value, %rax 168 | cmp %rax, \value 169 | jne check_metadata.fail 170 | .endm 171 | 172 | CHECK_GLOBAL $16, previous_instruction_counter, instruction_counter 173 | CHECK_GLOBAL $17, previous_nesting_level, nesting_level 174 | CHECK_GLOBAL $18, previous_disable_speculation, disable_speculation 175 | CHECK_GLOBAL $19, previous_specfuzz_call_type_stack_sp, specfuzz_call_type_stack_sp 176 | ret 177 | 178 | check_metadata.fail: 179 | pushq $0x246 # just in case, overwrite EFLAGS to avoid problems with printf 180 | popfq 181 | 182 | movq corruption_id, %rsi 183 | xor %rdi, %rdi 184 | movl $error_corruption, %edi 185 | movq $0, %rax 186 | call printf 187 | 188 | movq $1, %rax 189 | ret -------------------------------------------------------------------------------- /install/patches/llvm/X86.h: -------------------------------------------------------------------------------- 1 | //===-- X86.h - Top-level interface for X86 representation ------*- C++ -*-===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file contains the entry points for global functions defined in the x86 11 | // target library, as used by the LLVM JIT. 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #ifndef LLVM_LIB_TARGET_X86_X86_H 16 | #define LLVM_LIB_TARGET_X86_X86_H 17 | 18 | #include "llvm/Support/CodeGen.h" 19 | 20 | namespace llvm { 21 | 22 | class FunctionPass; 23 | class ImmutablePass; 24 | class InstructionSelector; 25 | class ModulePass; 26 | class PassRegistry; 27 | class X86RegisterBankInfo; 28 | class X86Subtarget; 29 | class X86TargetMachine; 30 | 31 | /// This pass converts a legalized DAG into a X86-specific DAG, ready for 32 | /// instruction scheduling. 33 | FunctionPass *createX86ISelDag(X86TargetMachine &TM, 34 | CodeGenOpt::Level OptLevel); 35 | 36 | /// This pass initializes a global base register for PIC on x86-32. 37 | FunctionPass *createX86GlobalBaseRegPass(); 38 | 39 | /// This pass combines multiple accesses to local-dynamic TLS variables so that 40 | /// the TLS base address for the module is only fetched once per execution path 41 | /// through the function. 42 | FunctionPass *createCleanupLocalDynamicTLSPass(); 43 | 44 | /// This function returns a pass which converts floating-point register 45 | /// references and pseudo instructions into floating-point stack references and 46 | /// physical instructions. 47 | FunctionPass *createX86FloatingPointStackifierPass(); 48 | 49 | /// This pass inserts AVX vzeroupper instructions before each call to avoid 50 | /// transition penalty between functions encoded with AVX and SSE. 51 | FunctionPass *createX86IssueVZeroUpperPass(); 52 | 53 | /// This pass instruments the function prolog to save the return address to a 54 | /// 'shadow call stack' and the function epilog to check that the return address 55 | /// did not change during function execution. 56 | FunctionPass *createShadowCallStackPass(); 57 | 58 | /// This pass inserts ENDBR instructions before indirect jump/call 59 | /// destinations as part of CET IBT mechanism. 60 | FunctionPass *createX86IndirectBranchTrackingPass(); 61 | 62 | /// Return a pass that pads short functions with NOOPs. 63 | /// This will prevent a stall when returning on the Atom. 64 | FunctionPass *createX86PadShortFunctions(); 65 | 66 | /// Return a pass that selectively replaces certain instructions (like add, 67 | /// sub, inc, dec, some shifts, and some multiplies) by equivalent LEA 68 | /// instructions, in order to eliminate execution delays in some processors. 69 | FunctionPass *createX86FixupLEAs(); 70 | 71 | /// Return a pass that removes redundant LEA instructions and redundant address 72 | /// recalculations. 73 | FunctionPass *createX86OptimizeLEAs(); 74 | 75 | /// Return a pass that transforms setcc + movzx pairs into xor + setcc. 76 | FunctionPass *createX86FixupSetCC(); 77 | 78 | /// Return a pass that avoids creating store forward block issues in the hardware. 79 | FunctionPass *createX86AvoidStoreForwardingBlocks(); 80 | 81 | /// Return a pass that lowers EFLAGS copy pseudo instructions. 82 | FunctionPass *createX86FlagsCopyLoweringPass(); 83 | 84 | /// Return a pass that expands WinAlloca pseudo-instructions. 85 | FunctionPass *createX86WinAllocaExpander(); 86 | 87 | /// Return a pass that optimizes the code-size of x86 call sequences. This is 88 | /// done by replacing esp-relative movs with pushes. 89 | FunctionPass *createX86CallFrameOptimization(); 90 | 91 | /// Return an IR pass that inserts EH registration stack objects and explicit 92 | /// EH state updates. This pass must run after EH preparation, which does 93 | /// Windows-specific but architecture-neutral preparation. 94 | FunctionPass *createX86WinEHStatePass(); 95 | 96 | /// Return a Machine IR pass that expands X86-specific pseudo 97 | /// instructions into a sequence of actual instructions. This pass 98 | /// must run after prologue/epilogue insertion and before lowering 99 | /// the MachineInstr to MC. 100 | FunctionPass *createX86ExpandPseudoPass(); 101 | 102 | /// This pass converts X86 cmov instructions into branch when profitable. 103 | FunctionPass *createX86CmovConverterPass(); 104 | 105 | /// Return a Machine IR pass that selectively replaces 106 | /// certain byte and word instructions by equivalent 32 bit instructions, 107 | /// in order to eliminate partial register usage, false dependences on 108 | /// the upper portions of registers, and to save code size. 109 | FunctionPass *createX86FixupBWInsts(); 110 | 111 | /// Return a Machine IR pass that reassigns instruction chains from one domain 112 | /// to another, when profitable. 113 | FunctionPass *createX86DomainReassignmentPass(); 114 | 115 | void initializeFixupBWInstPassPass(PassRegistry &); 116 | 117 | /// This pass replaces EVEX encoded of AVX-512 instructiosn by VEX 118 | /// encoding when possible in order to reduce code size. 119 | FunctionPass *createX86EvexToVexInsts(); 120 | 121 | /// This pass creates the thunks for the retpoline feature. 122 | FunctionPass *createX86RetpolineThunksPass(); 123 | 124 | InstructionSelector *createX86InstructionSelector(const X86TargetMachine &TM, 125 | X86Subtarget &, 126 | X86RegisterBankInfo &); 127 | 128 | void initializeEvexToVexInstPassPass(PassRegistry &); 129 | 130 | FunctionPass *createX86SpeculativeLoadHardeningPass(); 131 | 132 | FunctionPass *createX86SpecFuzzPass(); 133 | 134 | } // End llvm namespace 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /install/wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # TODO: this script is in a dire need of documentation 3 | 4 | set -e 5 | 6 | LLVM_CONFIG=${LLVM_CONFIG:-"llvm-7.0.1-config"} 7 | CLANG_BINDIR=$(${LLVM_CONFIG} --bindir) 8 | 9 | CC=${CLANG_BINDIR}/clang 10 | LLC=${CLANG_BINDIR}/llc 11 | 12 | # make sure that external variables do not corrupt our compilation 13 | CFLAGS="" 14 | LDFLAGS="" 15 | LANGUAGE="" 16 | GGDB="" 17 | I="" 18 | INPUT="" 19 | OUTPUT="" 20 | OPT="" 21 | 22 | # configure the compiler 23 | LLCFLAGS="-x86-specfuzz -disable-tail-calls" 24 | ASAN_CFLAGS="-fsanitize=address -mllvm -asan-instrumentation-with-call-threshold=0 -mllvm -asan-use-after-scope=0 " 25 | ASAN_LDFLAGS="-fsanitize=address" 26 | COVERAGE_FLAGS="" 27 | 28 | flag_coverage_only=0 29 | flag_coverage=0 30 | flag_collect=0 31 | flag_function_list=0 32 | flag_branch_list=0 33 | flag_serialization_list=0 34 | 35 | while [ "$#" -gt 0 ]; do 36 | case $1 in 37 | -o) 38 | if (($# > 1)); then 39 | OUTPUT=$2 40 | if [ "$2" == "/dev/null" ]; then 41 | DEVNULL=1 42 | fi 43 | shift 44 | fi 45 | ;; 46 | *.c|*.cc|*.cpp|-) 47 | INPUT="$INPUT $1" 48 | SOURCE=1 49 | ;; 50 | *.o|*.s|*.S|*.a) 51 | INPUT="$INPUT $1" 52 | ;; 53 | -x) 54 | LANGUAGE="$1 $2" 55 | if [ "$2" == "assembler" ]; then 56 | ASM=1 57 | fi 58 | shift 59 | ;; 60 | -c) 61 | CFLAGS="$CFLAGS $1" 62 | CREATE_OBJECT=1 63 | ;; 64 | -I|-include|-isystem) 65 | I="$I $1 $2" 66 | shift 67 | ;; 68 | -I*) 69 | I="$I $1" 70 | ;; 71 | -ggdb*|-g) 72 | GGDB="-g -gcolumn-info" 73 | ;; 74 | -O?) 75 | CFLAGS="$CFLAGS $1" 76 | OPT="$1" 77 | ;; 78 | -S) 79 | CREATE_ASM=1 80 | ;; 81 | --collect) 82 | if [ $flag_collect == 0 ]; then 83 | if [ ! -f $2 ]; then 84 | touch $2 85 | fi 86 | LLCFLAGS+=" -x86-specfuzz-collect-functions-into=$2" 87 | flag_collect=1 88 | fi 89 | shift 90 | ;; 91 | --function-list) 92 | if [ $flag_function_list == 0 ]; then 93 | LLCFLAGS+=" -x86-specfuzz-function-list=$2" 94 | flag_function_list=1 95 | fi 96 | shift 97 | ;; 98 | --branch-list) 99 | if [ $flag_branch_list == 0 ]; then 100 | LLCFLAGS+=" -x86-specfuzz-branch-list=$2" 101 | flag_branch_list=1 102 | fi 103 | shift 104 | ;; 105 | --serialization-list) 106 | if [ $flag_serialization_list == 0 ]; then 107 | LLCFLAGS+=" -x86-specfuzz-serialization-list=$2" 108 | flag_serialization_list=1 109 | fi 110 | shift 111 | ;; 112 | --echo) 113 | ECHO=1 114 | ;; 115 | --debug-pass) 116 | LLCFLAGS+=" -debug-only=x86-specfuzz" 117 | ;; 118 | --no-wrapper-cleanup) 119 | NO_CLEANUP=1 120 | ;; 121 | --disable-asan) 122 | ASAN_CFLAGS= 123 | ASAN_LDFLAGS= 124 | ;; 125 | --enable-coverage) 126 | if [ $flag_coverage == 0 ]; then 127 | ASAN_CFLAGS="$ASAN_CFLAGS $COVERAGE_FLAGS" 128 | ASAN_LDFLAGS="$ASAN_LDFLAGS $COVERAGE_FLAGS" 129 | flag_coverage=1 130 | fi 131 | ;; 132 | --coverage-only) 133 | if [ $flag_coverage_only == 0 ]; then 134 | ASAN_CFLAGS="$ASAN_CFLAGS $COVERAGE_FLAGS" 135 | ASAN_LDFLAGS="$ASAN_LDFLAGS $COVERAGE_FLAGS" 136 | LLCFLAGS+=" -x86-specfuzz-coverage-only" 137 | flag_coverage_only=1 138 | fi 139 | ;; 140 | -V|-v|-qversion) 141 | $CC -v 142 | exit $? 143 | ;; 144 | *) 145 | if [ -z "$OUTPUT" ]; then 146 | CFLAGS="$CFLAGS $1" 147 | else 148 | LDFLAGS="$LDFLAGS $1" 149 | fi 150 | ;; 151 | esac 152 | shift 153 | done 154 | 155 | if [ -z "$OUTPUT" ]; then 156 | if [ $CREATE_OBJECT ]; then 157 | OUTPUT=$(basename ${INPUT%.c*}.o) 158 | else 159 | OUTPUT="a.out" 160 | fi 161 | fi 162 | 163 | CFLAGS="$CFLAGS -mno-red-zone" 164 | CFLAGS="$CFLAGS -mno-avx -mno-avx2 " 165 | 166 | 167 | if ! [ $CREATE_OBJECT ]; then 168 | LDFLAGS="$LDFLAGS -rdynamic" 169 | fi 170 | 171 | if [ -n "$SOURCE" ] && [ -z "$ASM" ] && [ -z "$DEVNULL" ]; then 172 | cmd=( $CC $ASAN_CFLAGS $CFLAGS $GGDB $I $LANGUAGE -c -emit-llvm $INPUT -o ${OUTPUT%.o}.bc ) 173 | if [ -n "$ECHO" ]; then echo "${cmd[@]}"; fi 174 | "${cmd[@]}" 175 | 176 | cmd=( $LLC $LLCFLAGS $OPT ${OUTPUT%.o}.bc -o ${OUTPUT%.o}.s ) 177 | if [ -n "$ECHO" ]; then echo "${cmd[@]}"; fi 178 | "${cmd[@]}" 179 | if [ -z "$NO_CLEANUP" ]; then rm ${OUTPUT%.o}.bc; fi 180 | 181 | if [ -z "$CREATE_ASM" ]; then 182 | cmd=( $CC -Wno-unused-command-line-argument -Wl,--undefined=specfuzz_cov_trace_pc $CFLAGS $ASAN_LDFLAGS ${OUTPUT%.o}.s -o $OUTPUT $LDFLAGS -lspecfuzz) 183 | if [ -n "$ECHO" ]; then echo "${cmd[@]}"; fi 184 | "${cmd[@]}" 185 | else 186 | cp ${OUTPUT%.o}.s ${OUTPUT%.o} 187 | fi 188 | 189 | if [ -z "$NO_CLEANUP" ]; then rm ${OUTPUT%.o}.s; fi 190 | if [ -n "$ECHO" ]; then echo "==========================================================="; fi 191 | else 192 | if [ -z "$SOURCE" ]; then 193 | I= 194 | fi 195 | 196 | cmd=( $CC -Wl,--undefined=specfuzz_cov_trace_pc $ASAN_LDFLAGS $CFLAGS $GGDB $I $LANGUAGE $INPUT -o $OUTPUT $LDFLAGS -lspecfuzz) 197 | if [ -n "$ECHO" ]; then echo "${cmd[@]}"; fi 198 | "${cmd[@]}" 199 | fi 200 | -------------------------------------------------------------------------------- /install/patches/honggfuzz/instrument.c: -------------------------------------------------------------------------------- 1 | #include "instrument.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "honggfuzz.h" 18 | #include "libhfcommon/common.h" 19 | #include "libhfcommon/log.h" 20 | #include "libhfcommon/util.h" 21 | 22 | extern uint64_t branch_execution_count; 23 | 24 | __attribute__((visibility("default"))) __attribute__((used)) 25 | const char *const LIBHFUZZ_module_instrument = "LIBHFUZZ_module_instrument"; 26 | 27 | typedef struct { 28 | unsigned long pointer : 48U; 29 | uint16_t count : 16U; 30 | } packed_pointer; 31 | 32 | uint16_t cmpMapPcLocal[COVERAGE_MAP_SIZE] = {0}; 33 | packed_pointer cmpMapPcCache[COVERAGE_MAP_HASHMAP_SIZE] = {{0, 0}}; 34 | __attribute__((preserve_most)) static map_entry_t *get_hash_map_entry(uintptr_t pc); 35 | 36 | /* 37 | * If there's no _HF_BITMAP_FD available (running without the honggfuzz 38 | * supervisor), use a dummy bitmap and control structure located in the BSS 39 | */ 40 | static feedback_t bbMapFb; 41 | feedback_t *feedback = &bbMapFb; 42 | uint32_t my_thread_no = 0; 43 | 44 | __attribute__((constructor)) static void initializeInstrument(void) { 45 | if (fcntl(_HF_LOG_FD, F_GETFD) != -1) { 46 | enum llevel_t ll = INFO; 47 | const char *llstr = getenv(_HF_LOG_LEVEL_ENV); 48 | if (llstr) { 49 | ll = atoi(llstr); 50 | } 51 | logInitLogFile(NULL, _HF_LOG_FD, ll); 52 | } 53 | 54 | char *my_thread_no_str = getenv(_HF_THREAD_NO_ENV); 55 | if (my_thread_no_str == NULL) { 56 | LOG_D("The '%s' envvar is not set", _HF_THREAD_NO_ENV); 57 | return; 58 | } 59 | my_thread_no = atoi(my_thread_no_str); 60 | 61 | if (my_thread_no >= _HF_THREAD_MAX) { 62 | LOG_F("Received (via envvar) my_thread_no > _HF_THREAD_MAX (%" PRIu32 " > %d)\n", 63 | my_thread_no, _HF_THREAD_MAX); 64 | } 65 | 66 | struct stat st; 67 | if (fstat(_HF_BITMAP_FD, &st) == -1) { 68 | return; 69 | } 70 | if (st.st_size != sizeof(feedback_t)) { 71 | LOG_F( 72 | "size of the feedback structure mismatch: st.size != sizeof(feedback_t) (%zu != %zu). " 73 | "Link your fuzzed binaries with the newest honggfuzz sources via hfuzz-clang(++)", 74 | (size_t) st.st_size, sizeof(feedback_t)); 75 | } 76 | if ((feedback = mmap(NULL, sizeof(feedback_t), PROT_READ | PROT_WRITE, MAP_SHARED, 77 | _HF_BITMAP_FD, 0)) == MAP_FAILED) { 78 | PLOG_F("mmap(fd=%d, size=%zu) of the feedback structure failed", _HF_BITMAP_FD, 79 | sizeof(feedback_t)); 80 | } 81 | 82 | /* Reset coverage counters to their initial state */ 83 | instrumentClearNewCov(); 84 | } 85 | 86 | /* Reset the counters of newly discovered edges/pcs/features */ 87 | void instrumentClearNewCov() { 88 | feedback->pidFeedbackPc[my_thread_no] = 0U; 89 | feedback->pidFeedbackEdge[my_thread_no] = 0U; 90 | feedback->pidFeedbackCmp[my_thread_no] = 0U; 91 | } 92 | 93 | void specfuzz_cov_vuln(uintptr_t pc) { 94 | uint64_t index = (pc & VULN_MAP_INDEX_MASK) >> VULN_MAP_INDEX_OFFSET; 95 | uint8_t prev = feedback->vulnMap[index]; 96 | if (prev == 0U) { 97 | ATOMIC_PRE_INC_RELAXED(feedback->pidFeedbackPc[my_thread_no]); 98 | feedback->vulnMap[index] = 1U; 99 | } 100 | } 101 | 102 | __attribute__((preserve_most)) 103 | void specfuzz_cov_trace_pc(uintptr_t pc) { 104 | // quick path - check the cache 105 | uint64_t index = pc & COVERAGE_INDEX_MASK; 106 | if (cmpMapPcCache[index].pointer == pc) { 107 | branch_execution_count = cmpMapPcCache[index].count; 108 | return; 109 | } 110 | 111 | // Update the cache and proceed with slow path 112 | cmpMapPcCache[index].pointer = pc; 113 | 114 | // slow path: get an entry from the global coverage map 115 | map_entry_t *entry = get_hash_map_entry(pc); 116 | int localMapIndex = entry - (map_entry_t *) &feedback->cmpMapPc[0]; 117 | uint16_t *localEntry = &cmpMapPcLocal[localMapIndex]; 118 | uint16_t count = *localEntry; 119 | 120 | if (count != 0) { 121 | // already covered; nothing to do here 122 | cmpMapPcCache[index].count = count; 123 | branch_execution_count = count; 124 | return; 125 | } 126 | 127 | // sloth path: we see this CMP the first time in this run 128 | uint64_t prev = entry->count; 129 | entry->count++; 130 | if (prev == 0) { 131 | ATOMIC_PRE_INC_RELAXED(feedback->pidFeedbackCmp[my_thread_no]); 132 | } 133 | count = ((uint16_t) prev) + 1; 134 | *localEntry = count; 135 | cmpMapPcCache[index].count = count; 136 | branch_execution_count = count; 137 | return; 138 | } 139 | 140 | /// A helper function for accessing the coverage map 141 | /// 142 | /// Warning: This function is not safe for parallel fuzzing. 143 | /// To support it, the function needs to be re-written with atomics 144 | __attribute__((always_inline)) __attribute__((preserve_most)) 145 | static map_entry_t *get_hash_map_entry(uintptr_t pc) { 146 | map_entry_t *coverage_map = (map_entry_t *) feedback->cmpMapPc; 147 | uint64_t index = pc & COVERAGE_INDEX_MASK; 148 | uint64_t tag = (pc & COVERAGE_TAG_MASK) >> COVERAGE_INDEX_WIDTH; 149 | map_entry_t *entry = &(coverage_map[index]); 150 | map_entry_t *next; 151 | 152 | if (entry->tag == 0) { 153 | entry->tag = tag; 154 | return entry; 155 | } else if (entry->tag == tag) { 156 | return entry; 157 | } 158 | 159 | // hash conflict 160 | map_entry_t *coverage_map_conflicts = &coverage_map[COVERAGE_MAP_HASHMAP_SIZE]; 161 | do { 162 | if (entry->next == 0) { // create a new entry 163 | uint32_t top = feedback->cmpMapPcTop; 164 | next = &(coverage_map_conflicts[top]); 165 | entry->next = (uint16_t) top; 166 | next->tag = tag; 167 | 168 | if (top + 1 > COVERAGE_MAP_CONFLICTS_SIZE) { 169 | LOG_F("Error: coverage map overflow"); 170 | exit(1); 171 | } 172 | feedback->cmpMapPcTop = top + 1; 173 | return next; 174 | } 175 | entry = &coverage_map_conflicts[entry->next]; 176 | } while (entry->tag != tag); 177 | return entry; 178 | } -------------------------------------------------------------------------------- /tests/run.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bats 2 | 3 | export CLANG_DIR=$(llvm-7.0.1-config --bindir) 4 | export RTFLAGS="-lspecfuzz -L$CLANG_DIR/../lib" 5 | 6 | msg () { 7 | echo "[BATS] " $* 8 | } 9 | 10 | setup () { 11 | make clean 12 | } 13 | 14 | teardown() { 15 | make clean 16 | } 17 | 18 | function asm_test { 19 | CC=clang make ${NAME} 20 | run bash -c "./${NAME} 2>&1" 21 | if [ "$status" -ne 0 ]; then 22 | echo "status: $status" 23 | printf "output: $output\n" 24 | echo " output end" 25 | fi 26 | } 27 | 28 | @test "[$BATS_TEST_NUMBER] Acceptance: The pass is enabled and compiles correctly" { 29 | NAME=dummy 30 | CC=clang-sf make ${NAME} 31 | run bash -c "./${NAME}" 32 | [ "$status" -eq 0 ] 33 | [ "$output" = "[SF] Starting 34 | Hello World!" ] 35 | } 36 | 37 | @test "[$BATS_TEST_NUMBER] Acceptance: Detection of a speculative overflow with ASan" { 38 | NAME=acceptance-basic 39 | CC=clang-sf make ${NAME} 40 | run bash -c "ASAN_OPTIONS=allow_user_segv_handler=1:detect_leaks=0 ./${NAME} 100" 41 | [ "$status" -eq 0 ] 42 | [[ "$output" == *"[SF], 1,"* ]] 43 | } 44 | 45 | @test "[$BATS_TEST_NUMBER] Acceptance: Detection of a speculative overflow with signal handler" { 46 | NAME=acceptance-basic 47 | CC=clang-sf make ${NAME} 48 | run bash -c "ASAN_OPTIONS=allow_user_segv_handler=1:detect_leaks=0 ./${NAME} 5000" 49 | [ "$status" -eq 0 ] 50 | [[ "$output" == *"[SF], 11,"* ]] 51 | } 52 | 53 | @test "[$BATS_TEST_NUMBER] Acceptance: mmul" { 54 | NAME=acceptance-mmul 55 | 56 | CC=clang make ${NAME} 57 | run bash -c "./${NAME}" 58 | [ "$status" -eq 0 ] 59 | [[ "$output" == *"70" ]] 60 | 61 | CC=clang-sf make ${NAME} 62 | run bash -c "./${NAME}" 63 | [ "$status" -eq 0 ] 64 | [[ "$output" == *"70" ]] 65 | 66 | CC=clang-sf CFLAGS="-O1" make ${NAME} 67 | run bash -c "./${NAME}" 68 | [ "$status" -eq 0 ] 69 | [[ "$output" == *"70" ]] 70 | 71 | CC=clang-sf CFLAGS="-O2" make ${NAME} 72 | run bash -c "./${NAME}" 73 | [ "$status" -eq 0 ] 74 | [[ "$output" == *"70" ]] 75 | 76 | CC=clang-sf CFLAGS="-O3" make ${NAME} 77 | run bash -c "./${NAME}" 78 | [ "$status" -eq 0 ] 79 | [[ "$output" == *"70" ]] 80 | } 81 | 82 | @test "[$BATS_TEST_NUMBER] Acceptance: Indirect Jump" { 83 | NAME=acceptance-switch 84 | 85 | CC=clang-sf CFLAGS="-O0" make ${NAME} 86 | run bash -c "./${NAME} 0" 87 | [ "$status" -eq 0 ] 88 | run bash -c "./${NAME} 3" 89 | [ "$status" -eq 7 ] 90 | 91 | CC=clang-sf CFLAGS="-O3" make ${NAME} 92 | run bash -c "./${NAME} 0" 93 | [ "$status" -eq 0 ] 94 | run bash -c "./${NAME} 3" 95 | [ "$status" -eq 7 ] 96 | 97 | } 98 | 99 | @test "[$BATS_TEST_NUMBER] Runtime: Checkpointing function does not introduce corruptions" { 100 | NAME=rtl_chkp 101 | asm_test 102 | [ "$status" -eq 0 ] 103 | } 104 | 105 | @test "[$BATS_TEST_NUMBER] Runtime: Rollback function does not introduce corruptions" { 106 | NAME=rtl_rlbk 107 | asm_test 108 | [ "$status" -eq 0 ] 109 | } 110 | 111 | @test "[$BATS_TEST_NUMBER] Runtime: Rollback functions correctly" { 112 | NAME=rtl_chkp_rlbk 113 | asm_test 114 | [ "$status" -eq 0 ] 115 | } 116 | 117 | @test "[$BATS_TEST_NUMBER] Runtime: Reporting does not introduce corruptions" { 118 | NAME=rtl_report 119 | asm_test 120 | [ "$status" -eq 0 ] 121 | } 122 | 123 | @test "[$BATS_TEST_NUMBER] Runtime: Reporting functions correctly" { 124 | NAME=rtl_report 125 | asm_test 126 | [[ "${lines[1]}" == "[SF], 1, 0x29, 0x29, 0, "* ]] || [[ "${lines[1]}" == "[SF], 1, 0x29, 0x0, -8, "* ]] 127 | } 128 | 129 | @test "[$BATS_TEST_NUMBER] Wrapper: mmul compiled with a wrapper script" { 130 | NAME=acceptance-mmul 131 | CC=clang-sf CFLAGS=" --disable-asan -O3 -ggdb" make ${NAME} 132 | run bash -c "./${NAME}" 133 | [ "$status" -eq 0 ] 134 | [[ "$output" == *"70" ]] 135 | } 136 | 137 | @test "[$BATS_TEST_NUMBER] Wrapper: mmul compiled with a c++ wrapper script" { 138 | NAME=acceptance-mmul 139 | CC=clang-sf++ CFLAGS=" --disable-asan -O3 -ggdb" make ${NAME} 140 | run bash -c "./${NAME}" 141 | [ "$status" -eq 0 ] 142 | [[ "$output" == *"70" ]] 143 | } 144 | 145 | @test "[$BATS_TEST_NUMBER] Pass: Collecting functions" { 146 | NAME=dummy 147 | CC=clang-sf CFLAGS=" --collect list.txt --disable-asan -O3 -ggdb" make ${NAME} 148 | uniq list.txt | sort > t && mv t list.txt 149 | run cat list.txt 150 | [ "$output" == "main" ] 151 | rm list.txt 152 | } 153 | 154 | @test "[$BATS_TEST_NUMBER] Analyzer: Unit tests" { 155 | run bash -c "python3 -m unittest -v analyzer_unit" 156 | if [ "$status" -ne 0 ]; then 157 | printf "$output\n" 158 | fi 159 | [ "$status" -eq 0 ] 160 | } 161 | 162 | 163 | # Below are our old tests. They probably won't work anymore 164 | 165 | #@test "[$BATS_TEST_NUMBER] Analyzer: Correctly aggregates values" { 166 | # skip 167 | # touch tmp 168 | # data="[SF], 0, 0x1, 0x1, 10\n[SF], 0, 0x1, 0x2, 20\n[SF], 0, 0x2, 0x2, 10\n" 169 | # run bash -c "printf \"$data\" | analyzer coverage -c tmp -o tmp" 170 | # [ "$status" -eq 0 ] 171 | # [ "$output" == "|1 |1 |False |1 | 172 | #|2 |1,2 |False |1 |" ] 173 | # rm tmp 174 | #} 175 | # 176 | #@test "[$BATS_TEST_NUMBER] Analyzer: Correctly combines experiments" { 177 | # skip 178 | # touch tmp 179 | # experiment1="[SF] Starting\n[SF], 0, 0x1, 0x1, 10\n" 180 | # experiment2="[SF] Starting\n[SF], 1, 0x1, 0x1, 10\n[SF], 0, 0x2, 0x1, 10\n" 181 | # data="$experiment1$experiment2" 182 | # run bash -c "printf \"$data\" | analyzer coverage -c tmp -o tmp" 183 | # [ "$status" -eq 0 ] 184 | # echo "$output" 185 | # [ "$output" == "|1 |1,2 |False |2 |" ] 186 | # rm tmp 187 | #} 188 | # 189 | #@test "[$BATS_TEST_NUMBER] Analyzer: Correctly detects control" { 190 | # skip 191 | # touch tmp 192 | # experiment1="[SF] Starting\n[SF], 0, 0x1, 0x1, 10\n[SF] Starting\n[SF], 1, 0x1, 0x1, 20\n[SF], 0, 0x2, 0x1, 10\n" 193 | # data="$experiment1" 194 | # run bash -c "printf \"$data\" | analyzer coverage -c tmp -o tmp" 195 | # [ "$status" -eq 0 ] 196 | # echo "$output" 197 | # [ "$output" == "|1 |1,2 |True |2 |" ] 198 | # rm tmp 199 | #} 200 | # 201 | #@test "[$BATS_TEST_NUMBER] Analyzer: Detects errors" { 202 | # skip 203 | # touch tmp 204 | # data='[SF] Error: foo bar\n[SF], 0, a, b, 20\n[SF], 0, b, b, 10\n' 205 | # printf "$data" | analyzer coverage -c tmp -o tmp 206 | # run grep "[SF] Error: foo bar" tmp 207 | # [ "$status" -ne 0 ] 208 | # rm tmp 209 | #} 210 | -------------------------------------------------------------------------------- /src/specfuzz_init.c: -------------------------------------------------------------------------------- 1 | //===-------- specfuzz_init.c -----------------------------------------------===// 2 | // 3 | // Copyright: This file is distributed under the GPL version 3 License. 4 | // See LICENSE for details. 5 | // 6 | //===------------------------------------------------------------------------===// 7 | /// \file 8 | /// 9 | /// - Initialization of the SpecFuzz runtime. 10 | /// - A signal handler that records the signal and does a rollback 11 | //===------------------------------------------------------------------------===// 12 | #ifndef _GNU_SOURCE 13 | #define _GNU_SOURCE 14 | #endif 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "specfuzz_rtl.h" 23 | 24 | #if ENABLE_STATS == 1 25 | #define STAT_INCREMENT(X) X++ 26 | #else 27 | #define STAT_INCREMENT(X) 28 | #endif 29 | 30 | // a disjoint stack frame for a signal handler 31 | stack_t signal_stack_descr; 32 | char signal_stack[SIGSTKSZ]; 33 | 34 | // a global variable for detecting errors in RTL 35 | char inside_handler = 0; 36 | 37 | // output buffer 38 | #define OUTPUT_SIZE 1000000 39 | char output[OUTPUT_SIZE]; 40 | 41 | /// Signal handler to catch exceptions on simulated paths 42 | /// 43 | void specfuzz_handler(int signo, siginfo_t *siginfo, void *ucontext) { 44 | ucontext_t *context = ((ucontext_t *) ucontext); 45 | greg_t *uc_gregs = context->uc_mcontext.gregs; 46 | long long int instruction = context->uc_mcontext.gregs[REG_RIP]; 47 | 48 | #if ENABLE_SANITY_CHECKS == 1 49 | if (inside_handler != 0) { 50 | fprintf(stderr, "\n[SF] Error: Fault inside the signal handler\n"); 51 | abort(); 52 | } 53 | inside_handler = 1; 54 | 55 | if (nesting_level <= 0x0) { 56 | fprintf(stderr, "[SF] Error: Signal handler called outside speculation\n"); 57 | abort(); 58 | } 59 | 60 | if (checkpoint_sp > &checkpoint_stack || checkpoint_sp < &checkpoint_stack_bottom) { 61 | fprintf(stderr, "[SF] Error: checkpoint_sp is corrupted\n"); 62 | abort(); 63 | } 64 | 65 | if ((uint64_t *) uc_gregs[REG_RSP] <= &specfuzz_rtl_frame 66 | && (uint64_t *) uc_gregs[REG_RSP] >= &specfuzz_rtl_frame_bottom) { 67 | fprintf(stderr, "[SF] Error: a signal caught within the SpecFuzz runtime\n"); 68 | abort(); 69 | } 70 | #endif 71 | 72 | if (siginfo->si_signo == SIGFPE) { 73 | STAT_INCREMENT(stat_signal_misc); 74 | } else if (context->uc_mcontext.gregs[REG_RSP] >= (long long) &asan_rtl_frame_bottom && 75 | context->uc_mcontext.gregs[REG_RSP] <= (long long) &asan_rtl_frame) { 76 | // When we detect an overflow in ASan RTL, recovering the offending address is tricky 77 | // For the time being, we ignore these cases 78 | STAT_INCREMENT(stat_signal_overflow); 79 | } else { 80 | #if REPORT_MEMORY_ERRORS == 1 81 | // Print information about the signal 82 | // Note: the calls to fprintf are not multithreading-safe 83 | 84 | // the speculated branch's PC is stored in the second entry of 85 | // the current checkpoint stack frame, or the 16's entry if we go backwards 86 | // TODO: these indexes are ugly. Use a structure instead 87 | uint64_t last_branch_address = store_log_bp[20 + 64 + 1]; 88 | fprintf(stderr, 89 | "[SF], %d, 0x%llx, 0x%lx, 0, 0x%lx", 90 | siginfo->si_signo, 91 | instruction, 92 | (unsigned long int) siginfo->si_addr, 93 | last_branch_address); 94 | uint64_t *next_frame = (uint64_t *) store_log_bp[22 + 64 + 1]; 95 | while (next_frame) { 96 | fprintf(stderr, ", 0x%lx", next_frame[20 + 64 + 1]); 97 | next_frame = (uint64_t *) next_frame[22 + 64 + 1]; 98 | } 99 | fprintf(stderr, "\n"); 100 | #endif 101 | 102 | #if COVERAGE_MEMORY_ERRORS == 1 103 | specfuzz_cov_vuln(instruction); 104 | #endif 105 | STAT_INCREMENT(stat_signal_overflow); 106 | } 107 | 108 | // Redirect the flow into the recovery function 109 | uc_gregs[REG_RSP] = (greg_t) &specfuzz_rtl_frame; 110 | uc_gregs[REG_RIP] = (greg_t) &specfuzz_rlbk_forced; 111 | inside_handler = 0; 112 | } 113 | 114 | /// Catch all hardware signals with our handler 115 | /// 116 | void setup_handler() { 117 | // Establish an alternate stack for the handler 118 | signal_stack_descr.ss_sp = &signal_stack; 119 | signal_stack_descr.ss_size = SIGSTKSZ; 120 | signal_stack_descr.ss_flags = 0; 121 | 122 | if (sigaltstack(&signal_stack_descr, NULL) == -1) { 123 | perror("sigaltstack"); 124 | _exit(1); 125 | } 126 | 127 | // Configure the signal handler 128 | struct sigaction action; 129 | action.sa_sigaction = specfuzz_handler; 130 | sigemptyset(&action.sa_mask); // do not mask any signals while handling 131 | 132 | // pass signal info, use alternate stack, and catch it's own signals 133 | action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER; 134 | 135 | // Register the handler 136 | if (sigaction(SIGSEGV, &action, NULL) == -1 || 137 | sigaction(SIGBUS, &action, NULL) == -1 || 138 | sigaction(SIGILL, &action, NULL) == -1 || 139 | sigaction(SIGTRAP, &action, NULL) == -1 || 140 | sigaction(SIGFPE, &action, NULL) == -1) { 141 | perror("sigaction"); 142 | _exit(1); 143 | } 144 | } 145 | 146 | /// Prints runtime statistics 147 | /// 148 | #define print_stat(MSG, VAR, TOTAL) fprintf(stderr, MSG, VAR, (VAR * 100) / TOTAL) 149 | void specfuzz_dump_stats() { 150 | uint64_t total = stat_max_depth + stat_corrupted_code_pointer + stat_forced_external_call 151 | + stat_forced_serializing_instruction + stat_forced_indirect_call + stat_asan_overflow 152 | + stat_signal_overflow + stat_signal_misc; 153 | fprintf(stderr, "[SF] Statistics:\n"); 154 | print_stat(" Max speculation depth reached: %lu (%lu%%)\n", stat_max_depth, total); 155 | print_stat(" of them, with max nesting %lu (%lu%%)\n", stat_max_nesting, total); 156 | print_stat(" External function call: %lu (%lu%%)\n", stat_forced_external_call, total); 157 | print_stat(" Indirect function call: %lu (%lu%%)\n", stat_forced_indirect_call, total); 158 | print_stat(" Serializing: %lu (%lu%%)\n", stat_forced_serializing_instruction, total); 159 | print_stat(" Bounds violation (ASan): %lu (%lu%%)\n", stat_asan_overflow, total); 160 | print_stat(" Bounds violation (signal): %lu (%lu%%)\n", stat_signal_overflow, total); 161 | print_stat(" Corrupted code pointer: %lu (%lu%%)\n", stat_corrupted_code_pointer, total); 162 | print_stat(" Other signals: %lu (%lu%%)\n", stat_signal_misc, total); 163 | fprintf(stderr, " Simulation disables: %lu\n", stat_simulation_disables); 164 | fprintf(stderr, " Skipped CMP due to disabled simulation: %lu\n", stat_skiped_due_to_disabled); 165 | } 166 | 167 | /// The initialization function. Called before main 168 | /// 169 | __attribute__((preserve_most)) 170 | void specfuzz_init() { 171 | // _IOFBF behaves funky. IDK why. Gave up on it for the time being 172 | setvbuf(stderr, output, _IOLBF, OUTPUT_SIZE); 173 | fprintf(stderr, "[SF] Starting\n"); 174 | setup_handler(); 175 | #if ENABLE_STATS == 1 176 | atexit(specfuzz_dump_stats); 177 | #endif 178 | #if ENABLE_COVERAGE == 1 179 | specfuzz_cov_init(); 180 | #endif 181 | 182 | } 183 | -------------------------------------------------------------------------------- /install/patches/llvm/sanitizer_coverage_libcdep_new.cc: -------------------------------------------------------------------------------- 1 | //===-- sanitizer_coverage_libcdep_new.cc ---------------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // Sanitizer Coverage Controller for Trace PC Guard. 10 | 11 | #include "sanitizer_platform.h" 12 | 13 | #if !SANITIZER_FUCHSIA 14 | #include "sancov_flags.h" 15 | #include "sanitizer_allocator_internal.h" 16 | #include "sanitizer_atomic.h" 17 | #include "sanitizer_common.h" 18 | #include "sanitizer_file.h" 19 | 20 | #include 21 | 22 | using namespace __sanitizer; 23 | 24 | using AddressRange = LoadedModule::AddressRange; 25 | 26 | namespace __sancov { 27 | namespace { 28 | 29 | static const u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL; 30 | static const u64 Magic32 = 0xC0BFFFFFFFFFFF32ULL; 31 | static const u64 Magic = SANITIZER_WORDSIZE == 64 ? Magic64 : Magic32; 32 | 33 | static fd_t OpenFile(const char* path) { 34 | error_t err; 35 | fd_t fd = OpenFile(path, WrOnly, &err); 36 | if (fd == kInvalidFd) 37 | Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n", 38 | path, err); 39 | return fd; 40 | } 41 | 42 | static void GetCoverageFilename(char* path, const char* name, 43 | const char* extension) { 44 | CHECK(name); 45 | internal_snprintf(path, kMaxPathLength, "%s/%s.%zd.%s", 46 | common_flags()->coverage_dir, name, internal_getpid(), 47 | extension); 48 | } 49 | 50 | static void WriteModuleCoverage(char* file_path, const char* module_name, 51 | const uptr* pcs, uptr len) { 52 | GetCoverageFilename(file_path, StripModuleName(module_name), "sancov"); 53 | fd_t fd = OpenFile(file_path); 54 | WriteToFile(fd, &Magic, sizeof(Magic)); 55 | WriteToFile(fd, pcs, len * sizeof(*pcs)); 56 | CloseFile(fd); 57 | Printf("SanitizerCoverage: %s: %zd PCs written\n", file_path, len); 58 | } 59 | 60 | static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) { 61 | if (!len) return; 62 | 63 | char* file_path = static_cast(InternalAlloc(kMaxPathLength)); 64 | char* module_name = static_cast(InternalAlloc(kMaxPathLength)); 65 | uptr* pcs = static_cast(InternalAlloc(len * sizeof(uptr))); 66 | 67 | internal_memcpy(pcs, unsorted_pcs, len * sizeof(uptr)); 68 | Sort(pcs, len); 69 | 70 | bool module_found = false; 71 | uptr last_base = 0; 72 | uptr module_start_idx = 0; 73 | 74 | for (uptr i = 0; i < len; ++i) { 75 | const uptr pc = pcs[i]; 76 | if (!pc) continue; 77 | 78 | if (!__sanitizer_get_module_and_offset_for_pc(pc, nullptr, 0, &pcs[i])) { 79 | Printf("ERROR: unknown pc 0x%x (may happen if dlclose is used)\n", pc); 80 | continue; 81 | } 82 | uptr module_base = pc - pcs[i]; 83 | 84 | if (module_base != last_base || !module_found) { 85 | if (module_found) { 86 | WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], 87 | i - module_start_idx); 88 | } 89 | 90 | last_base = module_base; 91 | module_start_idx = i; 92 | module_found = true; 93 | __sanitizer_get_module_and_offset_for_pc(pc, module_name, kMaxPathLength, 94 | &pcs[i]); 95 | } 96 | } 97 | 98 | if (module_found) { 99 | WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx], 100 | len - module_start_idx); 101 | } 102 | 103 | InternalFree(file_path); 104 | InternalFree(module_name); 105 | InternalFree(pcs); 106 | } 107 | 108 | // Collects trace-pc guard coverage. 109 | // This class relies on zero-initialization. 110 | class TracePcGuardController { 111 | public: 112 | long* nesting_level; 113 | long* disable_speculation; 114 | 115 | void Initialize() { 116 | CHECK(!initialized); 117 | 118 | initialized = true; 119 | InitializeSancovFlags(); 120 | 121 | pc_vector.Initialize(0); 122 | nesting_level = (long *) dlsym(RTLD_DEFAULT, "nesting_level"); 123 | disable_speculation = (long *) dlsym(RTLD_DEFAULT, "disable_speculation"); 124 | } 125 | 126 | void InitTracePcGuard(u32* start, u32* end) { 127 | if (!initialized) Initialize(); 128 | CHECK(!*start); 129 | CHECK_NE(start, end); 130 | 131 | u32 i = pc_vector.size(); 132 | for (u32* p = start; p < end; p++) *p = ++i; 133 | pc_vector.resize(i); 134 | } 135 | 136 | void TracePcGuard(u32* guard, uptr pc) { 137 | u32 idx = *guard; 138 | if (!idx) return; 139 | // we start indices from 1. 140 | atomic_uintptr_t* pc_ptr = 141 | reinterpret_cast(&pc_vector[idx - 1]); 142 | if (atomic_load(pc_ptr, memory_order_relaxed) == 0) 143 | atomic_store(pc_ptr, pc, memory_order_relaxed); 144 | } 145 | 146 | void Reset() { 147 | internal_memset(&pc_vector[0], 0, sizeof(pc_vector[0]) * pc_vector.size()); 148 | } 149 | 150 | void Dump() { 151 | if (!initialized || !common_flags()->coverage) return; 152 | __sanitizer_dump_coverage(pc_vector.data(), pc_vector.size()); 153 | } 154 | 155 | private: 156 | bool initialized; 157 | InternalMmapVectorNoCtor pc_vector; 158 | }; 159 | 160 | static TracePcGuardController pc_guard_controller; 161 | 162 | } // namespace 163 | } // namespace __sancov 164 | 165 | namespace __sanitizer { 166 | void InitializeCoverage(bool enabled, const char *dir) { 167 | static bool coverage_enabled = false; 168 | if (coverage_enabled) 169 | return; // May happen if two sanitizer enable coverage in the same process. 170 | coverage_enabled = enabled; 171 | Atexit(__sanitizer_cov_dump); 172 | AddDieCallback(__sanitizer_cov_dump); 173 | } 174 | } // namespace __sanitizer 175 | 176 | extern "C" { 177 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT 178 | const uptr* pcs, uptr len) { 179 | return __sancov::SanitizerDumpCoverage(pcs, len); 180 | } 181 | 182 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32* guard) { 183 | if (!*guard) return; 184 | if (*__sancov::pc_guard_controller.nesting_level != 0) return; 185 | if (*__sancov::pc_guard_controller.disable_speculation > 0) return; 186 | __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1); 187 | } 188 | 189 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, 190 | u32* start, u32* end) { 191 | if (start == end || *start) return; 192 | __sancov::pc_guard_controller.InitTracePcGuard(start, end); 193 | } 194 | 195 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { 196 | __sancov::pc_guard_controller.Dump(); 197 | } 198 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { 199 | __sanitizer_dump_trace_pc_guard_coverage(); 200 | } 201 | SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_reset() { 202 | __sancov::pc_guard_controller.Reset(); 203 | } 204 | // Default empty implementations (weak). Users should redefine them. 205 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} 206 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} 207 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} 208 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} 209 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} 210 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} 211 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} 212 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} 213 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} 214 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} 215 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} 216 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} 217 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} 218 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} 219 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {} 220 | SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} 221 | } // extern "C" 222 | // Weak definition for code instrumented with -fsanitize-coverage=stack-depth 223 | // and later linked with code containing a strong definition. 224 | // E.g., -fsanitize=fuzzer-no-link 225 | SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 226 | SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE uptr __sancov_lowest_stack; 227 | 228 | #endif // !SANITIZER_FUCHSIA 229 | -------------------------------------------------------------------------------- /tests/aggregated-sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "branches": { 3 | "loc-1b": {"location": "", "branches": [{"address": "1b", "nonspeculative_execution_count": 0}], "symbolized_faults": [], "fault_counts": [0], "nonspeculative_execution_counts": [0]}, 4 | "loc-2b": {"location": "", "branches": [{"address": "2b", "nonspeculative_execution_count": 0}], "symbolized_faults": [], "fault_counts": [1, 0], "nonspeculative_execution_counts": [0, 11]}, 5 | "loc-3b": {"location": "", "branches": [{"address": "3b", "nonspeculative_execution_count": 2}], "symbolized_faults": [], "fault_counts": [0], "nonspeculative_execution_counts": [2]}, 6 | "loc-4b": {"location": "", "branches": [{"address": "4b", "nonspeculative_execution_count": 11}], "symbolized_faults": [], "fault_counts": [0], "nonspeculative_execution_counts": [11]}, 7 | "loc-5b": {"location": "", "branches": [{"address": "5b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 8 | "loc-6b": {"location": "", "branches": [{"address": "6b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 9 | "loc-7b": {"location": "", "branches": [{"address": "7b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 10 | "loc-8b": {"location": "", "branches": [{"address": "8b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 11 | "loc-9b": {"location": "", "branches": [{"address": "9b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 12 | "loc-10b": {"location": "", "branches": [{"address": "10b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 13 | "loc-11b": {"location": "", "branches": [{"address": "11b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 14 | "loc-12b": {"location": "", "branches": [{"address": "12b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 15 | "loc-13b": {"location": "", "branches": [{"address": "13b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 16 | "loc-14b": {"location": "", "branches": [{"address": "14b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 17 | "loc-15b": {"location": "", "branches": [{"address": "15b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 18 | "loc-16b": {"location": "", "branches": [{"address": "16b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 19 | "loc-17b": {"location": "", "branches": [{"address": "17b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 20 | "loc-18b": {"location": "", "branches": [{"address": "18b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]}, 21 | "loc-19b": {"location": "", "branches": [{"address": "19b", "nonspeculative_execution_count": 101}], "symbolized_faults": [], "fault_counts": [101], "nonspeculative_execution_counts": [101]} 22 | }, 23 | "faults": { 24 | "f1": { 25 | "location": "", 26 | "faults": [ 27 | { 28 | "address": "", 29 | "accessed_addresses": [], 30 | "offsets": [], 31 | "branch_sequences": [ 32 | [ 33 | "5b", 34 | "6b", 35 | "7b" 36 | ] 37 | ], 38 | "order": 1, 39 | "fault_count": 1, 40 | "controlled": false, 41 | "controlled_offset": false, 42 | "types": [ 43 | 11 44 | ] 45 | } 46 | ], 47 | "accessed_addresses": [], 48 | "offsets": [], 49 | "fault_counts": [ 50 | 1 51 | ], 52 | "controlled": false, 53 | "controlled_offset": false, 54 | "types": [ 55 | 1 56 | ], 57 | "order": 1 58 | }, 59 | "f2": { 60 | "location": "", 61 | "faults": [ 62 | { 63 | "address": "", 64 | "accessed_addresses": [], 65 | "offsets": [], 66 | "branch_sequences": [ 67 | [ 68 | "6b", 69 | "7b", 70 | "8b" 71 | ] 72 | ], 73 | "order": 1, 74 | "fault_count": 11, 75 | "controlled": false, 76 | "controlled_offset": false, 77 | "types": [ 78 | 11 79 | ] 80 | } 81 | ], 82 | "accessed_addresses": [], 83 | "offsets": [], 84 | "fault_counts": [ 85 | 11 86 | ], 87 | "controlled": false, 88 | "controlled_offset": false, 89 | "types": [ 90 | 1 91 | ], 92 | "order": 1 93 | }, 94 | "f3": { 95 | "location": "", 96 | "faults": [ 97 | { 98 | "address": "", 99 | "accessed_addresses": [], 100 | "offsets": [], 101 | "branch_sequences": [ 102 | [ 103 | "7b", 104 | "8b", 105 | "9b" 106 | ], 107 | [ 108 | "8b", 109 | "9b", 110 | "10b" 111 | ] 112 | ], 113 | "order": 1, 114 | "fault_count": 11, 115 | "controlled": false, 116 | "controlled_offset": true, 117 | "types": [ 118 | 11 119 | ] 120 | } 121 | ], 122 | "accessed_addresses": [], 123 | "offsets": [], 124 | "fault_counts": [ 125 | 11 126 | ], 127 | "controlled": false, 128 | "controlled_offset": true, 129 | "types": [ 130 | 1 131 | ], 132 | "order": 1 133 | }, 134 | "f4": { 135 | "location": "", 136 | "faults": [ 137 | { 138 | "address": "", 139 | "accessed_addresses": [], 140 | "offsets": [], 141 | "branch_sequences": [ 142 | [ 143 | "11b", 144 | "12b", 145 | "13b" 146 | ], 147 | [ 148 | "11b", 149 | "12b", 150 | "14b" 151 | ] 152 | ], 153 | "order": 1, 154 | "fault_count": 11, 155 | "controlled": true, 156 | "controlled_offset": true, 157 | "types": [ 158 | 11 159 | ] 160 | } 161 | ], 162 | "accessed_addresses": [], 163 | "offsets": [], 164 | "fault_counts": [ 165 | 11 166 | ], 167 | "controlled": true, 168 | "controlled_offset": true, 169 | "types": [ 170 | 1 171 | ], 172 | "order": 1 173 | }, 174 | "f5": { 175 | "location": "", 176 | "faults": [ 177 | { 178 | "address": "", 179 | "accessed_addresses": [], 180 | "offsets": [], 181 | "branch_sequences": [ 182 | [ 183 | "14b", 184 | "15b", 185 | "16b" 186 | ], 187 | [ 188 | "14b", 189 | "15b", 190 | "17b" 191 | ] 192 | ], 193 | "order": 1, 194 | "fault_count": 11, 195 | "controlled": true, 196 | "controlled_offset": true, 197 | "types": [ 198 | 11 199 | ] 200 | }, 201 | { 202 | "address": "", 203 | "accessed_addresses": [], 204 | "offsets": [], 205 | "branch_sequences": [ 206 | [ 207 | "11b", 208 | "17b" 209 | ], 210 | [ 211 | "11b", 212 | "18b" 213 | ] 214 | ], 215 | "order": 1, 216 | "fault_count": 11, 217 | "controlled": true, 218 | "controlled_offset": true, 219 | "types": [ 220 | 11 221 | ] 222 | } 223 | ], 224 | "accessed_addresses": [], 225 | "offsets": [], 226 | "fault_counts": [ 227 | 11 228 | ], 229 | "controlled": true, 230 | "controlled_offset": true, 231 | "types": [ 232 | 1 233 | ], 234 | "order": 1 235 | }, 236 | "f6": { 237 | "location": "", 238 | "faults": [ 239 | { 240 | "address": "", 241 | "accessed_addresses": [], 242 | "offsets": [], 243 | "branch_sequences": [ 244 | [ 245 | "1b", 246 | "6b", 247 | "7b" 248 | ] 249 | ], 250 | "order": 1, 251 | "fault_count": 1, 252 | "controlled": false, 253 | "controlled_offset": false, 254 | "types": [ 255 | 11 256 | ] 257 | } 258 | ], 259 | "accessed_addresses": [], 260 | "offsets": [], 261 | "fault_counts": [ 262 | 1 263 | ], 264 | "controlled": false, 265 | "controlled_offset": false, 266 | "types": [ 267 | 1 268 | ], 269 | "order": 1 270 | }, 271 | "f7": { 272 | "location": "", 273 | "faults": [ 274 | { 275 | "address": "", 276 | "accessed_addresses": [], 277 | "offsets": [], 278 | "branch_sequences": [ 279 | [ 280 | "19b" 281 | ] 282 | ], 283 | "order": 1, 284 | "fault_count": 1, 285 | "controlled": false, 286 | "controlled_offset": false, 287 | "types": [ 288 | 2 289 | ] 290 | } 291 | ], 292 | "accessed_addresses": [], 293 | "offsets": [], 294 | "fault_counts": [ 295 | 101 296 | ], 297 | "controlled": false, 298 | "controlled_offset": false, 299 | "types": [ 300 | 2 301 | ], 302 | "order": 1 303 | } 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /example/usesec20/libhtp/perf_function_list.txt: -------------------------------------------------------------------------------- 1 | asan.module_ctor 2 | asan.module_dtor 3 | bstr_add 4 | bstr_add_c 5 | bstr_add_c_noex 6 | bstr_add_mem 7 | bstr_add_mem_noex 8 | bstr_add_noex 9 | bstr_adjust_len 10 | bstr_adjust_realptr 11 | bstr_adjust_size 12 | bstr_alloc 13 | bstr_begins_with 14 | bstr_begins_with_c 15 | bstr_begins_with_c_nocase 16 | bstr_begins_with_mem 17 | bstr_begins_with_mem_nocase 18 | bstr_begins_with_nocase 19 | bstr_builder_append_c 20 | bstr_builder_append_mem 21 | bstr_builder_appendn 22 | bstr_builder_clear 23 | bstr_builder_create 24 | bstr_builder_destroy 25 | bstr_builder_size 26 | bstr_builder_to_str 27 | bstr_char_at 28 | bstr_char_at_end 29 | bstr_chop 30 | bstr_chr 31 | bstr_cmp 32 | bstr_cmp_c 33 | bstr_cmp_c_nocase 34 | bstr_cmp_mem 35 | bstr_cmp_mem_nocase 36 | bstr_cmp_nocase 37 | bstr_dup 38 | bstr_dup_c 39 | bstr_dup_ex 40 | bstr_dup_lower 41 | bstr_dup_mem 42 | bstr_expand 43 | bstr_free 44 | bstr_index_of 45 | bstr_index_of_c 46 | bstr_index_of_c_nocase 47 | bstr_index_of_mem 48 | bstr_index_of_mem_nocase 49 | bstr_index_of_nocase 50 | bstr_rchr 51 | bstr_to_lowercase 52 | bstr_util_cmp_mem 53 | bstr_util_cmp_mem_nocase 54 | bstr_util_memdup_to_c 55 | bstr_util_mem_index_of_c 56 | bstr_util_mem_index_of_c_nocase 57 | bstr_util_mem_index_of_mem 58 | bstr_util_mem_index_of_mem_nocase 59 | bstr_util_mem_to_pint 60 | bstr_util_mem_trim 61 | bstr_util_strdup_to_c 62 | bstr_wrap_c 63 | bstr_wrap_mem 64 | decode_u_encoding_path 65 | fprint_bstr 66 | fprint_raw_data 67 | fprint_raw_data_ex 68 | htp_base64_decode 69 | htp_base64_decode_bstr 70 | htp_base64_decode_mem 71 | htp_base64_decoder_init 72 | htp_base64_decode_single 73 | htp_ch_multipart_callback_request_body_data 74 | htp_ch_multipart_callback_request_headers 75 | htp_chomp 76 | htp_ch_urlencoded_callback_request_body_data 77 | htp_ch_urlencoded_callback_request_headers 78 | htp_ch_urlencoded_callback_request_line 79 | htp_config_copy 80 | htp_config_create 81 | htp_config_destroy 82 | htp_config_get_user_data 83 | htp_config_register_log 84 | htp_config_register_multipart_parser 85 | htp_config_register_request_body_data 86 | htp_config_register_request_complete 87 | htp_config_register_request_file_data 88 | htp_config_register_request_header_data 89 | htp_config_register_request_headers 90 | htp_config_register_request_line 91 | htp_config_register_request_start 92 | htp_config_register_request_trailer 93 | htp_config_register_request_trailer_data 94 | htp_config_register_request_uri_normalize 95 | htp_config_register_response_body_data 96 | htp_config_register_response_complete 97 | htp_config_register_response_header_data 98 | htp_config_register_response_headers 99 | htp_config_register_response_line 100 | htp_config_register_response_start 101 | htp_config_register_response_trailer 102 | htp_config_register_response_trailer_data 103 | htp_config_register_transaction_complete 104 | htp_config_register_urlencoded_parser 105 | htp_config_set_backslash_convert_slashes 106 | htp_config_set_bestfit_map 107 | htp_config_set_bestfit_replacement_byte 108 | htp_config_set_control_chars_unwanted 109 | htp_config_set_convert_lowercase 110 | htp_config_set_extract_request_files 111 | htp_config_set_field_limits 112 | htp_config_set_log_level 113 | htp_config_set_nul_encoded_terminates 114 | htp_config_set_nul_encoded_unwanted 115 | htp_config_set_nul_raw_terminates 116 | htp_config_set_nul_raw_unwanted 117 | htp_config_set_parse_request_auth 118 | htp_config_set_parse_request_cookies 119 | htp_config_set_path_separators_compress 120 | htp_config_set_path_separators_decode 121 | htp_config_set_path_separators_encoded_unwanted 122 | htp_config_set_plusspace_decode 123 | htp_config_set_requestline_leading_whitespace_unwanted 124 | htp_config_set_response_decompression 125 | htp_config_set_response_decompression_layer_limit 126 | htp_config_set_server_personality 127 | htp_config_set_tmpdir 128 | htp_config_set_tx_auto_destroy 129 | htp_config_set_u_encoding_decode 130 | htp_config_set_u_encoding_unwanted 131 | htp_config_set_url_encoding_invalid_handling 132 | htp_config_set_url_encoding_invalid_unwanted 133 | htp_config_set_user_data 134 | htp_config_set_utf8_convert_bestfit 135 | htp_config_set_utf8_invalid_unwanted 136 | htp_conn_close 137 | htp_conn_create 138 | htp_conn_destroy 139 | htp_conn_open 140 | htp_connp_clear_error 141 | htp_connp_close 142 | htp_connp_create 143 | htp_connp_destroy 144 | htp_connp_destroy_all 145 | htp_connp_destroy_decompressors 146 | htp_connp_get_connection 147 | htp_connp_get_in_tx 148 | htp_connp_get_last_error 149 | htp_connp_get_out_tx 150 | htp_connp_get_user_data 151 | htp_connp_in_reset 152 | htp_connp_in_state_as_string 153 | htp_connp_is_line_folded 154 | htp_connp_is_line_ignorable 155 | htp_connp_is_line_terminator 156 | htp_connp_open 157 | htp_connp_out_state_as_string 158 | htp_connp_REQ_BODY_CHUNKED_DATA 159 | htp_connp_REQ_BODY_CHUNKED_DATA_END 160 | htp_connp_REQ_BODY_CHUNKED_LENGTH 161 | htp_connp_REQ_BODY_DETERMINE 162 | htp_connp_REQ_BODY_IDENTITY 163 | htp_connp_req_buffer 164 | htp_connp_REQ_CONNECT_CHECK 165 | htp_connp_REQ_CONNECT_PROBE_DATA 166 | htp_connp_REQ_CONNECT_WAIT_RESPONSE 167 | htp_connp_req_data 168 | htp_connp_req_data_consumed 169 | htp_connp_REQ_FINALIZE 170 | htp_connp_REQ_HEADERS 171 | htp_connp_REQ_IDLE 172 | htp_connp_REQ_IGNORE_DATA_AFTER_HTTP_0_9 173 | htp_connp_REQ_LINE 174 | htp_connp_REQ_LINE_complete 175 | htp_connp_REQ_PROTOCOL 176 | htp_connp_req_receiver_finalize_clear 177 | htp_connp_RES_BODY_CHUNKED_DATA 178 | htp_connp_RES_BODY_CHUNKED_DATA_END 179 | htp_connp_RES_BODY_CHUNKED_LENGTH 180 | htp_connp_RES_BODY_DETERMINE 181 | htp_connp_RES_BODY_IDENTITY_CL_KNOWN 182 | htp_connp_RES_BODY_IDENTITY_STREAM_CLOSE 183 | htp_connp_res_buffer 184 | htp_connp_res_data 185 | htp_connp_res_data_consumed 186 | htp_connp_RES_FINALIZE 187 | htp_connp_RES_HEADERS 188 | htp_connp_RES_IDLE 189 | htp_connp_RES_LINE 190 | htp_connp_res_receiver_finalize_clear 191 | htp_connp_set_user_data 192 | htp_connp_tx_create 193 | htp_connp_tx_remove 194 | htp_conn_remove_tx 195 | htp_conn_track_inbound_data 196 | htp_conn_track_outbound_data 197 | htp_convert_method_to_number 198 | htp_decode_path_inplace 199 | htp_extract_quoted_string_as_bstr 200 | htp_get_version 201 | htp_gzip_decompressor_create 202 | htp_gzip_decompressor_decompress 203 | htp_gzip_decompressor_destroy 204 | htp_hook_copy 205 | htp_hook_create 206 | htp_hook_destroy 207 | htp_hook_register 208 | htp_hook_run_all 209 | htp_hook_run_one 210 | htp_is_folding_char 211 | htp_is_line_empty 212 | htp_is_line_whitespace 213 | htp_is_lws 214 | htp_is_separator 215 | htp_is_space 216 | htp_is_text 217 | htp_is_token 218 | htp_list_array_clear 219 | htp_list_array_create 220 | htp_list_array_destroy 221 | htp_list_array_get 222 | htp_list_array_pop 223 | htp_list_array_push 224 | htp_list_array_replace 225 | htp_list_array_shift 226 | htp_list_array_size 227 | htp_log 228 | htp_martp_process_aside 229 | htp_mpart_part_create 230 | htp_mpart_part_destroy 231 | htp_mpart_part_finalize_data 232 | htp_mpart_part_handle_data 233 | htp_mpart_part_parse_c_d 234 | htp_mpart_part_process_headers 235 | htp_mpartp_create 236 | htp_mpartp_destroy 237 | htp_mpartp_finalize 238 | htp_mpartp_find_boundary 239 | htp_mpartp_get_multipart 240 | htp_mpartp_handle_boundary 241 | htp_mpartp_handle_data 242 | htp_mpartp_parse 243 | htp_mpartp_parse_header 244 | htp_mpartp_run_request_file_data_hook 245 | htp_normalize_hostname_inplace 246 | htp_normalize_parsed_uri 247 | htp_normalize_uri_path_inplace 248 | htp_parse_authorization 249 | htp_parse_authorization_basic 250 | htp_parse_authorization_digest 251 | htp_parse_chunked_length 252 | htp_parse_content_length 253 | htp_parse_cookies_v0 254 | htp_parse_ct_header 255 | htp_parse_header_hostport 256 | htp_parse_hostport 257 | htp_parse_positive_integer_whitespace 258 | htp_parse_protocol 259 | htp_parse_request_header_generic 260 | htp_parse_request_line_apache_2_2 261 | htp_parse_request_line_generic 262 | htp_parse_request_line_generic_ex 263 | htp_parse_response_header_generic 264 | htp_parse_response_line_generic 265 | htp_parse_single_cookie_v0 266 | htp_parse_status 267 | htp_parse_uri 268 | htp_parse_uri_hostport 269 | htp_php_parameter_processor 270 | htp_process_request_header_apache_2_2 271 | htp_process_request_header_generic 272 | htp_process_response_header_generic 273 | htp_req_run_hook_body_data 274 | htp_res_run_hook_body_data 275 | htp_table_add 276 | htp_table_addk 277 | htp_table_addn 278 | htp_table_clear 279 | htp_table_clear_ex 280 | htp_table_create 281 | htp_table_destroy 282 | htp_table_destroy_ex 283 | htp_table_get 284 | htp_table_get_c 285 | htp_table_get_index 286 | htp_table_get_mem 287 | htp_table_size 288 | htp_transcode_bstr 289 | htp_transcode_params 290 | htp_treat_response_line_as_body 291 | htp_tx_create 292 | htp_tx_destroy 293 | htp_tx_destroy_incomplete 294 | htp_tx_finalize 295 | htp_tx_get_is_config_shared 296 | htp_tx_get_user_data 297 | htp_tx_is_complete 298 | htp_tx_register_request_body_data 299 | htp_tx_register_response_body_data 300 | htp_tx_req_add_param 301 | htp_tx_req_get_param 302 | htp_tx_req_get_param_ex 303 | htp_tx_req_has_body 304 | htp_tx_req_process_body_data 305 | htp_tx_req_process_body_data_ex 306 | htp_tx_req_set_header 307 | htp_tx_req_set_headers_clear 308 | htp_tx_req_set_line 309 | htp_tx_req_set_method 310 | htp_tx_req_set_method_number 311 | htp_tx_req_set_parsed_uri 312 | htp_tx_req_set_protocol 313 | htp_tx_req_set_protocol_0_9 314 | htp_tx_req_set_protocol_number 315 | htp_tx_req_set_uri 316 | htp_tx_request_progress_as_string 317 | htp_tx_response_progress_as_string 318 | htp_tx_res_process_body_data 319 | htp_tx_res_process_body_data_decompressor_callback 320 | htp_tx_res_process_body_data_ex 321 | htp_tx_res_set_header 322 | htp_tx_res_set_headers_clear 323 | htp_tx_res_set_protocol_number 324 | htp_tx_res_set_status_code 325 | htp_tx_res_set_status_line 326 | htp_tx_res_set_status_message 327 | htp_tx_set_config 328 | htp_tx_set_user_data 329 | htp_tx_state_request_complete 330 | htp_tx_state_request_complete_partial 331 | htp_tx_state_request_headers 332 | htp_tx_state_request_line 333 | htp_tx_state_request_start 334 | htp_tx_state_response_complete 335 | htp_tx_state_response_complete_ex 336 | htp_tx_state_response_headers 337 | htp_tx_state_response_line 338 | htp_tx_state_response_start 339 | htp_tx_urldecode_params_inplace 340 | htp_tx_urldecode_uri_inplace 341 | htp_unparse_uri_noencode 342 | htp_uri_alloc 343 | htp_uri_free 344 | htp_urldecode_inplace 345 | htp_urldecode_inplace_ex 346 | htp_urlenp_add_field_piece 347 | htp_urlenp_create 348 | htp_urlenp_destroy 349 | htp_urlenp_finalize 350 | htp_urlenp_parse_complete 351 | htp_urlenp_parse_partial 352 | htp_utf8_decode 353 | htp_utf8_decode_allow_overlong 354 | htp_utf8_decode_path_inplace 355 | htp_utf8_validate_path 356 | htp_validate_hostname 357 | strlcat 358 | strlcpy -------------------------------------------------------------------------------- /install/patches/honggfuzz/honggfuzz.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * honggfuzz - core structures and macros 4 | * ----------------------------------------- 5 | * 6 | * Author: Robert Swiecki 7 | * 8 | * Copyright 2010-2018 by Google Inc. All Rights Reserved. 9 | * 10 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 11 | * not use this file except in compliance with the License. You may obtain 12 | * a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, software 17 | * distributed under the License is distributed on an "AS IS" BASIS, 18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 19 | * implied. See the License for the specific language governing 20 | * permissions and limitations under the License. 21 | * 22 | */ 23 | 24 | #ifndef _HF_HONGGFUZZ_H_ 25 | #define _HF_HONGGFUZZ_H_ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "libhfcommon/util.h" 39 | 40 | #define PROG_NAME "honggfuzz" 41 | #define PROG_VERSION "1.9" 42 | 43 | /* Name of the template which will be replaced with the proper name of the file */ 44 | #define _HF_FILE_PLACEHOLDER "___FILE___" 45 | 46 | /* Default name of the report created with some architectures */ 47 | #define _HF_REPORT_FILE "HONGGFUZZ.REPORT.TXT" 48 | 49 | /* Default stack-size of created threads. */ 50 | #define _HF_PTHREAD_STACKSIZE (1024ULL * 1024ULL * 2ULL) /* 2MB */ 51 | 52 | /* Name of envvar which indicates sequential number of fuzzer */ 53 | #define _HF_THREAD_NO_ENV "HFUZZ_THREAD_NO" 54 | 55 | /* Name of envvar which indicates that the netDriver should be used */ 56 | #define _HF_THREAD_NETDRIVER_ENV "HFUZZ_USE_NETDRIVER" 57 | 58 | /* Name of envvar which indicates honggfuzz's log level in use */ 59 | #define _HF_LOG_LEVEL_ENV "HFUZZ_LOG_LEVEL" 60 | 61 | /* Number of crash verifier iterations before tag crash as stable */ 62 | #define _HF_VERIFIER_ITER 5 63 | 64 | /* Size (in bytes) for report data to be stored in stack before written to file */ 65 | #define _HF_REPORT_SIZE 8192 66 | 67 | /* Perf bitmap size */ 68 | #define _HF_PERF_BITMAP_SIZE_16M (1024U * 1024U * 16U) 69 | #define _HF_PERF_BITMAP_BITSZ_MASK 0x7FFFFFFULL 70 | /* Maximum number of PC guards (=trace-pc-guard) we support */ 71 | #define _HF_PC_GUARD_MAX (1024ULL * 1024ULL * 64ULL) 72 | 73 | /* Maximum size of the input file in bytes (128 MiB) */ 74 | #define _HF_INPUT_MAX_SIZE (1024ULL * 1024ULL * 128ULL) 75 | 76 | /* FD used to log inside the child process */ 77 | #define _HF_LOG_FD 1020 78 | /* FD used to represent the input file */ 79 | #define _HF_INPUT_FD 1021 80 | /* FD used to pass feedback bitmap a process */ 81 | #define _HF_BITMAP_FD 1022 82 | /* FD used to pass data to a persistent process */ 83 | #define _HF_PERSISTENT_FD 1023 84 | 85 | /* Message indicating that the fuzzed process is ready for new data */ 86 | static const uint8_t HFReadyTag = 'R'; 87 | 88 | /* Maximum number of active fuzzing threads */ 89 | #define _HF_THREAD_MAX 1024U 90 | 91 | /* Persistent-binary signature - if found within file, it means it's a persistent mode binary */ 92 | #define _HF_PERSISTENT_SIG "\x01_LIBHFUZZ_PERSISTENT_BINARY_SIGNATURE_\x02\xFF" 93 | /* HF NetDriver signature - if found within file, it means it's a NetDriver-based binary */ 94 | #define _HF_NETDRIVER_SIG "\x01_LIBHFUZZ_NETDRIVER_BINARY_SIGNATURE_\x02\xFF" 95 | 96 | typedef enum { 97 | _HF_DYNFILE_NONE = 0x0, 98 | _HF_DYNFILE_INSTR_COUNT = 0x1, 99 | _HF_DYNFILE_BRANCH_COUNT = 0x2, 100 | _HF_DYNFILE_BTS_EDGE = 0x10, 101 | _HF_DYNFILE_IPT_BLOCK = 0x20, 102 | _HF_DYNFILE_SOFT = 0x40, 103 | } dynFileMethod_t; 104 | 105 | typedef struct { 106 | uint64_t cpuInstrCnt; 107 | uint64_t cpuBranchCnt; 108 | uint64_t bbCnt; 109 | uint64_t newBBCnt; 110 | uint64_t softCntPc; 111 | uint64_t softCntEdge; 112 | uint64_t softCntCmp; 113 | } hwcnt_t; 114 | 115 | typedef struct { 116 | uint32_t capacity; 117 | uint32_t* pChunks; 118 | uint32_t nChunks; 119 | } bitmap_t; 120 | 121 | /* Memory map struct */ 122 | typedef struct __attribute__((packed)) { 123 | uint64_t start; // region start addr 124 | uint64_t end; // region end addr 125 | uint64_t base; // region base addr 126 | char mapName[NAME_MAX]; // bin/DSO name 127 | uint64_t bbCnt; 128 | uint64_t newBBCnt; 129 | } memMap_t; 130 | 131 | /* Trie node data struct */ 132 | typedef struct __attribute__((packed)) { 133 | bitmap_t* pBM; 134 | } trieData_t; 135 | 136 | /* Trie node struct */ 137 | typedef struct node { 138 | char key; 139 | trieData_t data; 140 | struct node* next; 141 | struct node* prev; 142 | struct node* children; 143 | struct node* parent; 144 | } node_t; 145 | 146 | /* EOF Sanitizer coverage specific data structures */ 147 | 148 | typedef enum { 149 | _HF_STATE_UNSET = 0, 150 | _HF_STATE_STATIC = 1, 151 | _HF_STATE_DYNAMIC_DRY_RUN = 2, 152 | _HF_STATE_DYNAMIC_SWITCH_TO_MAIN = 3, 153 | _HF_STATE_DYNAMIC_MAIN = 4, 154 | } fuzzState_t; 155 | 156 | struct dynfile_t { 157 | uint8_t* data; 158 | size_t size; 159 | TAILQ_ENTRY(dynfile_t) 160 | pointers; 161 | }; 162 | 163 | struct strings_t { 164 | char* s; 165 | size_t len; 166 | TAILQ_ENTRY(strings_t) 167 | pointers; 168 | }; 169 | 170 | 171 | /* Coverage map interface */ 172 | #define COVERAGE_INDEX_WIDTH 16U 173 | #define COVERAGE_TAG_WIDTH (48U - COVERAGE_INDEX_WIDTH) 174 | #define COVERAGE_CONFLICTS_INDEX_WIDTH 12U 175 | #define COVERAGE_MAP_HASHMAP_SIZE (1U << COVERAGE_INDEX_WIDTH) 176 | #define COVERAGE_MAP_CONFLICTS_SIZE (1U << COVERAGE_CONFLICTS_INDEX_WIDTH) 177 | #define COVERAGE_MAP_SIZE (COVERAGE_MAP_HASHMAP_SIZE + COVERAGE_MAP_CONFLICTS_SIZE) 178 | #define COVERAGE_INDEX_MASK ((1U << COVERAGE_INDEX_WIDTH) - 1) 179 | #define COVERAGE_TAG_MASK (0xffffffffffffffU - COVERAGE_INDEX_MASK) 180 | typedef struct { 181 | unsigned long tag : COVERAGE_TAG_WIDTH; 182 | uint16_t next : COVERAGE_CONFLICTS_INDEX_WIDTH; 183 | unsigned count : (64U - COVERAGE_TAG_WIDTH - COVERAGE_CONFLICTS_INDEX_WIDTH); 184 | } map_entry_t; 185 | 186 | /* Vulnerability map interface */ 187 | #define VULN_MAP_INDEX_WIDTH 16U 188 | #define VULN_MAP_INDEX_OFFSET 5U 189 | #define VULN_MAP_INDEX_MASK (((1U << VULN_MAP_INDEX_WIDTH) - 1) << VULN_MAP_INDEX_OFFSET) 190 | #define VULN_MAP_SIZE (1U << VULN_MAP_INDEX_WIDTH) 191 | 192 | typedef struct { 193 | uint32_t cmpMapPcTop; 194 | map_entry_t cmpMapPc[COVERAGE_MAP_SIZE]; 195 | uint8_t vulnMap[VULN_MAP_SIZE]; 196 | uint8_t bbMapPc[_HF_PERF_BITMAP_SIZE_16M]; 197 | uint64_t pidFeedbackPc[_HF_THREAD_MAX]; 198 | uint64_t pidFeedbackEdge[_HF_THREAD_MAX]; 199 | uint64_t pidFeedbackCmp[_HF_THREAD_MAX]; 200 | } feedback_t; 201 | 202 | typedef struct { 203 | struct { 204 | size_t threadsMax; 205 | size_t threadsFinished; 206 | uint32_t threadsActiveCnt; 207 | pthread_t mainThread; 208 | pid_t mainPid; 209 | pthread_t threads[_HF_THREAD_MAX]; 210 | } threads; 211 | struct { 212 | const char* inputDir; 213 | DIR* inputDirPtr; 214 | size_t fileCnt; 215 | const char* fileExtn; 216 | bool fileCntDone; 217 | const char* workDir; 218 | const char* crashDir; 219 | const char* covDirAll; 220 | const char* covDirNew; 221 | bool saveUnique; 222 | size_t dynfileqCnt; 223 | pthread_rwlock_t dynfileq_mutex; 224 | TAILQ_HEAD(dyns_t, dynfile_t) dynfileq; 225 | } io; 226 | struct { 227 | int argc; 228 | const char* const* cmdline; 229 | bool nullifyStdio; 230 | bool fuzzStdin; 231 | const char* externalCommand; 232 | const char* postExternalCommand; 233 | const char* feedbackMutateCommand; 234 | bool netDriver; 235 | bool persistent; 236 | uint64_t asLimit; 237 | uint64_t rssLimit; 238 | uint64_t dataLimit; 239 | uint64_t coreLimit; 240 | bool clearEnv; 241 | char* envs[128]; 242 | sigset_t waitSigSet; 243 | } exe; 244 | struct { 245 | time_t timeStart; 246 | time_t runEndTime; 247 | time_t tmOut; 248 | time_t lastCovUpdate; 249 | bool tmoutVTALRM; 250 | } timing; 251 | struct { 252 | const char* dictionaryFile; 253 | TAILQ_HEAD(strq_t, strings_t) dictq; 254 | size_t dictionaryCnt; 255 | size_t mutationsMax; 256 | unsigned mutationsPerRun; 257 | size_t maxFileSz; 258 | } mutate; 259 | struct { 260 | bool useScreen; 261 | char cmdline_txt[65]; 262 | int64_t lastDisplayMillis; 263 | } display; 264 | struct { 265 | bool useVerifier; 266 | bool exitUponCrash; 267 | const char* reportFile; 268 | pthread_mutex_t report_mutex; 269 | bool monitorSIGABRT; 270 | size_t dynFileIterExpire; 271 | bool only_printable; 272 | } cfg; 273 | struct { 274 | bool enable; 275 | } sanitizer; 276 | struct { 277 | fuzzState_t state; 278 | feedback_t* feedbackMap; 279 | int bbFd; 280 | pthread_mutex_t feedback_mutex; 281 | const char* blacklistFile; 282 | uint64_t* blacklist; 283 | size_t blacklistCnt; 284 | bool skipFeedbackOnTimeout; 285 | dynFileMethod_t dynFileMethod; 286 | } feedback; 287 | struct { 288 | size_t mutationsCnt; 289 | size_t crashesCnt; 290 | size_t uniqueCrashesCnt; 291 | size_t verifiedCrashesCnt; 292 | size_t blCrashesCnt; 293 | size_t timeoutedCnt; 294 | } cnts; 295 | struct { 296 | bool enabled; 297 | int serverSocket; 298 | int clientSocket; 299 | } socketFuzzer; 300 | /* For the Linux code */ 301 | struct { 302 | int exeFd; 303 | hwcnt_t hwCnts; 304 | uint64_t dynamicCutOffAddr; 305 | bool disableRandomization; 306 | void* ignoreAddr; 307 | size_t numMajorFrames; 308 | const char* symsBlFile; 309 | char** symsBl; 310 | size_t symsBlCnt; 311 | const char* symsWlFile; 312 | char** symsWl; 313 | size_t symsWlCnt; 314 | uintptr_t cloneFlags; 315 | bool kernelOnly; 316 | bool useClone; 317 | } linux; 318 | /* For the NetBSD code */ 319 | struct { 320 | void* ignoreAddr; 321 | size_t numMajorFrames; 322 | const char* symsBlFile; 323 | char** symsBl; 324 | size_t symsBlCnt; 325 | const char* symsWlFile; 326 | char** symsWl; 327 | size_t symsWlCnt; 328 | } netbsd; 329 | } honggfuzz_t; 330 | 331 | typedef enum { 332 | _HF_RS_UNKNOWN = 0, 333 | _HF_RS_WAITING_FOR_INITIAL_READY = 1, 334 | _HF_RS_WAITING_FOR_READY = 2, 335 | _HF_RS_SEND_DATA = 3, 336 | } runState_t; 337 | 338 | typedef struct { 339 | honggfuzz_t* global; 340 | pid_t pid; 341 | int64_t timeStartedMillis; 342 | char origFileName[PATH_MAX]; 343 | char crashFileName[PATH_MAX]; 344 | uint64_t pc; 345 | uint64_t backtrace; 346 | uint64_t access; 347 | int exception; 348 | char report[_HF_REPORT_SIZE]; 349 | bool mainWorker; 350 | unsigned mutationsPerRun; 351 | struct dynfile_t* dynfileqCurrent; 352 | uint8_t* dynamicFile; 353 | size_t dynamicFileSz; 354 | int dynamicFileFd; 355 | int dynamicFileCopyFd; 356 | uint32_t fuzzNo; 357 | int persistentSock; 358 | bool waitingForReady; 359 | runState_t runState; 360 | bool tmOutSignaled; 361 | #if !defined(_HF_ARCH_DARWIN) 362 | timer_t timerId; 363 | #endif // !defined(_HF_ARCH_DARWIN) 364 | 365 | struct { 366 | /* For Linux code */ 367 | uint8_t* perfMmapBuf; 368 | uint8_t* perfMmapAux; 369 | hwcnt_t hwCnts; 370 | int cpuInstrFd; 371 | int cpuBranchFd; 372 | int cpuIptBtsFd; 373 | } linux; 374 | 375 | struct { 376 | /* For NetBSD code */ 377 | uint8_t* perfMmapBuf; 378 | uint8_t* perfMmapAux; 379 | hwcnt_t hwCnts; 380 | int cpuInstrFd; 381 | int cpuBranchFd; 382 | int cpuIptBtsFd; 383 | } netbsd; 384 | } run_t; 385 | 386 | /* 387 | * Go-style defer scoped implementation 388 | * 389 | * When compiled with clang, use: -fblocks -lBlocksRuntime 390 | * 391 | * Example of use: 392 | * 393 | * { 394 | * int fd = open(fname, O_RDONLY); 395 | * if (fd == -1) { 396 | * error(....); 397 | * return; 398 | * } 399 | * defer { close(fd); }; 400 | * ssize_t sz = read(fd, buf, sizeof(buf)); 401 | * ... 402 | * ... 403 | * } 404 | * 405 | */ 406 | 407 | #define __STRMERGE(a, b) a##b 408 | #define _STRMERGE(a, b) __STRMERGE(a, b) 409 | #ifdef __clang__ 410 | #if __has_extension(blocks) 411 | static void __attribute__((unused)) __clang_cleanup_func(void (^*dfunc)(void)) { 412 | (*dfunc)(); 413 | } 414 | 415 | #define defer \ 416 | void (^_STRMERGE(__defer_f_, __COUNTER__))(void) \ 417 | __attribute__((cleanup(__clang_cleanup_func))) __attribute__((unused)) = ^ 418 | 419 | #else /* __has_extension(blocks) */ 420 | #define defer UNIMPLEMENTED - NO - SUPPORT - FOR - BLOCKS - IN - YOUR - CLANG - ENABLED 421 | #endif /* __has_extension(blocks) */ 422 | #else /* !__clang__, e.g.: gcc */ 423 | 424 | #define __block 425 | #define _DEFER(a, count) \ 426 | auto void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused))); \ 427 | int _STRMERGE(__defer_var_, count) __attribute__((cleanup(_STRMERGE(__defer_f_, count)))) \ 428 | __attribute__((unused)); \ 429 | void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused))) 430 | #define defer _DEFER(a, __COUNTER__) 431 | #endif /* ifdef __clang__ */ 432 | 433 | /* Block scoped mutexes */ 434 | #define MX_SCOPED_LOCK(m) \ 435 | MX_LOCK(m); \ 436 | defer { \ 437 | MX_UNLOCK(m); \ 438 | } 439 | 440 | #define MX_SCOPED_RWLOCK_READ(m) \ 441 | MX_RWLOCK_READ(m); \ 442 | defer { \ 443 | MX_RWLOCK_UNLOCK(m); \ 444 | } 445 | #define MX_SCOPED_RWLOCK_WRITE(m) \ 446 | MX_RWLOCK_WRITE(m); \ 447 | defer { \ 448 | MX_RWLOCK_UNLOCK(m); \ 449 | } 450 | 451 | #endif 452 | -------------------------------------------------------------------------------- /install/patches/llvm/asan_poisoning.cc: -------------------------------------------------------------------------------- 1 | //===-- asan_poisoning.cc -------------------------------------------------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file is a part of AddressSanitizer, an address sanity checker. 11 | // 12 | // Shadow memory poisoning by ASan RTL and by user application. 13 | //===----------------------------------------------------------------------===// 14 | 15 | #include "asan_poisoning.h" 16 | #include "asan_report.h" 17 | #include "asan_stack.h" 18 | #include "sanitizer_common/sanitizer_atomic.h" 19 | #include "sanitizer_common/sanitizer_libc.h" 20 | #include "sanitizer_common/sanitizer_flags.h" 21 | 22 | namespace __asan { 23 | 24 | static atomic_uint8_t can_poison_memory; 25 | extern long* nesting_level; 26 | 27 | void SetCanPoisonMemory(bool value) { 28 | atomic_store(&can_poison_memory, value, memory_order_release); 29 | } 30 | 31 | bool CanPoisonMemory() { 32 | return atomic_load(&can_poison_memory, memory_order_acquire); 33 | } 34 | 35 | void PoisonShadow(uptr addr, uptr size, u8 value) { 36 | if (value && !CanPoisonMemory()) return; 37 | CHECK(AddrIsAlignedByGranularity(addr)); 38 | CHECK(AddrIsInMem(addr)); 39 | CHECK(AddrIsAlignedByGranularity(addr + size)); 40 | CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY)); 41 | CHECK(REAL(memset)); 42 | FastPoisonShadow(addr, size, value); 43 | } 44 | 45 | void PoisonShadowPartialRightRedzone(uptr addr, 46 | uptr size, 47 | uptr redzone_size, 48 | u8 value) { 49 | if (!CanPoisonMemory()) return; 50 | CHECK(AddrIsAlignedByGranularity(addr)); 51 | CHECK(AddrIsInMem(addr)); 52 | FastPoisonShadowPartialRightRedzone(addr, size, redzone_size, value); 53 | } 54 | 55 | struct ShadowSegmentEndpoint { 56 | u8 *chunk; 57 | s8 offset; // in [0, SHADOW_GRANULARITY) 58 | s8 value; // = *chunk; 59 | 60 | explicit ShadowSegmentEndpoint(uptr address) { 61 | chunk = (u8*)MemToShadow(address); 62 | offset = address & (SHADOW_GRANULARITY - 1); 63 | value = *chunk; 64 | } 65 | }; 66 | 67 | void FlushUnneededASanShadowMemory(uptr p, uptr size) { 68 | // Since asan's mapping is compacting, the shadow chunk may be 69 | // not page-aligned, so we only flush the page-aligned portion. 70 | ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); 71 | } 72 | 73 | void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) { 74 | uptr end = ptr + size; 75 | if (Verbosity()) { 76 | Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n", 77 | poison ? "" : "un", ptr, end, size); 78 | if (Verbosity() >= 2) 79 | PRINT_CURRENT_STACK(); 80 | } 81 | CHECK(size); 82 | CHECK_LE(size, 4096); 83 | CHECK(IsAligned(end, SHADOW_GRANULARITY)); 84 | if (!IsAligned(ptr, SHADOW_GRANULARITY)) { 85 | *(u8 *)MemToShadow(ptr) = 86 | poison ? static_cast(ptr % SHADOW_GRANULARITY) : 0; 87 | ptr |= SHADOW_GRANULARITY - 1; 88 | ptr++; 89 | } 90 | for (; ptr < end; ptr += SHADOW_GRANULARITY) 91 | *(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0; 92 | } 93 | 94 | } // namespace __asan 95 | 96 | // ---------------------- Interface ---------------- {{{1 97 | using namespace __asan; // NOLINT 98 | 99 | // Current implementation of __asan_(un)poison_memory_region doesn't check 100 | // that user program (un)poisons the memory it owns. It poisons memory 101 | // conservatively, and unpoisons progressively to make sure asan shadow 102 | // mapping invariant is preserved (see detailed mapping description here: 103 | // https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm). 104 | // 105 | // * if user asks to poison region [left, right), the program poisons 106 | // at least [left, AlignDown(right)). 107 | // * if user asks to unpoison region [left, right), the program unpoisons 108 | // at most [AlignDown(left), right). 109 | void __asan_poison_memory_region(void const volatile *addr, uptr size) { 110 | if (!flags()->allow_user_poisoning || size == 0) return; 111 | if (*nesting_level != 0) { 112 | UNREACHABLE("poisoning shadow memory within SpecFuzz simulation"); 113 | return; 114 | } 115 | 116 | uptr beg_addr = (uptr)addr; 117 | uptr end_addr = beg_addr + size; 118 | VPrintf(3, "Trying to poison memory region [%p, %p)\n", (void *)beg_addr, 119 | (void *)end_addr); 120 | ShadowSegmentEndpoint beg(beg_addr); 121 | ShadowSegmentEndpoint end(end_addr); 122 | if (beg.chunk == end.chunk) { 123 | CHECK_LT(beg.offset, end.offset); 124 | s8 value = beg.value; 125 | CHECK_EQ(value, end.value); 126 | // We can only poison memory if the byte in end.offset is unaddressable. 127 | // No need to re-poison memory if it is poisoned already. 128 | if (value > 0 && value <= end.offset) { 129 | if (beg.offset > 0) { 130 | *beg.chunk = Min(value, beg.offset); 131 | } else { 132 | *beg.chunk = kAsanUserPoisonedMemoryMagic; 133 | } 134 | } 135 | return; 136 | } 137 | CHECK_LT(beg.chunk, end.chunk); 138 | if (beg.offset > 0) { 139 | // Mark bytes from beg.offset as unaddressable. 140 | if (beg.value == 0) { 141 | *beg.chunk = beg.offset; 142 | } else { 143 | *beg.chunk = Min(beg.value, beg.offset); 144 | } 145 | beg.chunk++; 146 | } 147 | REAL(memset)(beg.chunk, kAsanUserPoisonedMemoryMagic, end.chunk - beg.chunk); 148 | // Poison if byte in end.offset is unaddressable. 149 | if (end.value > 0 && end.value <= end.offset) { 150 | *end.chunk = kAsanUserPoisonedMemoryMagic; 151 | } 152 | } 153 | 154 | void __asan_unpoison_memory_region(void const volatile *addr, uptr size) { 155 | if (!flags()->allow_user_poisoning || size == 0) return; 156 | uptr beg_addr = (uptr)addr; 157 | uptr end_addr = beg_addr + size; 158 | VPrintf(3, "Trying to unpoison memory region [%p, %p)\n", (void *)beg_addr, 159 | (void *)end_addr); 160 | ShadowSegmentEndpoint beg(beg_addr); 161 | ShadowSegmentEndpoint end(end_addr); 162 | if (beg.chunk == end.chunk) { 163 | CHECK_LT(beg.offset, end.offset); 164 | s8 value = beg.value; 165 | CHECK_EQ(value, end.value); 166 | // We unpoison memory bytes up to enbytes up to end.offset if it is not 167 | // unpoisoned already. 168 | if (value != 0) { 169 | *beg.chunk = Max(value, end.offset); 170 | } 171 | return; 172 | } 173 | CHECK_LT(beg.chunk, end.chunk); 174 | if (beg.offset > 0) { 175 | *beg.chunk = 0; 176 | beg.chunk++; 177 | } 178 | REAL(memset)(beg.chunk, 0, end.chunk - beg.chunk); 179 | if (end.offset > 0 && end.value != 0) { 180 | *end.chunk = Max(end.value, end.offset); 181 | } 182 | } 183 | 184 | int __asan_address_is_poisoned(void const volatile *addr) { 185 | return __asan::AddressIsPoisoned((uptr)addr); 186 | } 187 | 188 | uptr __asan_region_is_poisoned(uptr beg, uptr size) { 189 | if (!size) return 0; 190 | uptr end = beg + size; 191 | if (SANITIZER_MYRIAD2) { 192 | // On Myriad, address not in DRAM range need to be treated as 193 | // unpoisoned. 194 | if (!AddrIsInMem(beg) && !AddrIsInShadow(beg)) return 0; 195 | if (!AddrIsInMem(end) && !AddrIsInShadow(end)) return 0; 196 | } else { 197 | if (!AddrIsInMem(beg)) return beg; 198 | if (!AddrIsInMem(end)) return end; 199 | } 200 | CHECK_LT(beg, end); 201 | uptr aligned_b = RoundUpTo(beg, SHADOW_GRANULARITY); 202 | uptr aligned_e = RoundDownTo(end, SHADOW_GRANULARITY); 203 | uptr shadow_beg = MemToShadow(aligned_b); 204 | uptr shadow_end = MemToShadow(aligned_e); 205 | // First check the first and the last application bytes, 206 | // then check the SHADOW_GRANULARITY-aligned region by calling 207 | // mem_is_zero on the corresponding shadow. 208 | if (!__asan::AddressIsPoisoned(beg) && 209 | !__asan::AddressIsPoisoned(end - 1) && 210 | (shadow_end <= shadow_beg || 211 | __sanitizer::mem_is_zero((const char *)shadow_beg, 212 | shadow_end - shadow_beg))) 213 | return 0; 214 | // The fast check failed, so we have a poisoned byte somewhere. 215 | // Find it slowly. 216 | for (; beg < end; beg++) 217 | if (__asan::AddressIsPoisoned(beg)) 218 | return beg; 219 | UNREACHABLE("mem_is_zero returned false, but poisoned byte was not found"); 220 | return 0; 221 | } 222 | 223 | #define CHECK_SMALL_REGION(p, size, isWrite) \ 224 | do { \ 225 | uptr __p = reinterpret_cast(p); \ 226 | uptr __size = size; \ 227 | if (UNLIKELY(__asan::AddressIsPoisoned(__p) || \ 228 | __asan::AddressIsPoisoned(__p + __size - 1))) { \ 229 | GET_CURRENT_PC_BP_SP; \ 230 | uptr __bad = __asan_region_is_poisoned(__p, __size); \ 231 | __asan_report_error(pc, bp, sp, __bad, isWrite, __size, 0);\ 232 | } \ 233 | } while (false) 234 | 235 | 236 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE 237 | u16 __sanitizer_unaligned_load16(const uu16 *p) { 238 | CHECK_SMALL_REGION(p, sizeof(*p), false); 239 | return *p; 240 | } 241 | 242 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE 243 | u32 __sanitizer_unaligned_load32(const uu32 *p) { 244 | CHECK_SMALL_REGION(p, sizeof(*p), false); 245 | return *p; 246 | } 247 | 248 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE 249 | u64 __sanitizer_unaligned_load64(const uu64 *p) { 250 | CHECK_SMALL_REGION(p, sizeof(*p), false); 251 | return *p; 252 | } 253 | 254 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE 255 | void __sanitizer_unaligned_store16(uu16 *p, u16 x) { 256 | CHECK_SMALL_REGION(p, sizeof(*p), true); 257 | *p = x; 258 | } 259 | 260 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE 261 | void __sanitizer_unaligned_store32(uu32 *p, u32 x) { 262 | CHECK_SMALL_REGION(p, sizeof(*p), true); 263 | *p = x; 264 | } 265 | 266 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE 267 | void __sanitizer_unaligned_store64(uu64 *p, u64 x) { 268 | CHECK_SMALL_REGION(p, sizeof(*p), true); 269 | *p = x; 270 | } 271 | 272 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE 273 | void __asan_poison_cxx_array_cookie(uptr p) { 274 | if (SANITIZER_WORDSIZE != 64) return; 275 | if (!flags()->poison_array_cookie) return; 276 | if (*nesting_level != 0) { 277 | UNREACHABLE("poisoning shadow memory within SpecFuzz simulation"); 278 | return; 279 | } 280 | uptr s = MEM_TO_SHADOW(p); 281 | *reinterpret_cast(s) = kAsanArrayCookieMagic; 282 | } 283 | 284 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE 285 | uptr __asan_load_cxx_array_cookie(uptr *p) { 286 | if (SANITIZER_WORDSIZE != 64) return *p; 287 | if (!flags()->poison_array_cookie) return *p; 288 | uptr s = MEM_TO_SHADOW(reinterpret_cast(p)); 289 | u8 sval = *reinterpret_cast(s); 290 | if (sval == kAsanArrayCookieMagic) return *p; 291 | // If sval is not kAsanArrayCookieMagic it can only be freed memory, 292 | // which means that we are going to get double-free. So, return 0 to avoid 293 | // infinite loop of destructors. We don't want to report a double-free here 294 | // though, so print a warning just in case. 295 | // CHECK_EQ(sval, kAsanHeapFreeMagic); 296 | if (sval == kAsanHeapFreeMagic) { 297 | Report("AddressSanitizer: loaded array cookie from free-d memory; " 298 | "expect a double-free report\n"); 299 | return 0; 300 | } 301 | // The cookie may remain unpoisoned if e.g. it comes from a custom 302 | // operator new defined inside a class. 303 | return *p; 304 | } 305 | 306 | // This is a simplified version of __asan_(un)poison_memory_region, which 307 | // assumes that left border of region to be poisoned is properly aligned. 308 | static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) { 309 | if (size == 0) return; 310 | uptr aligned_size = size & ~(SHADOW_GRANULARITY - 1); 311 | PoisonShadow(addr, aligned_size, 312 | do_poison ? kAsanStackUseAfterScopeMagic : 0); 313 | if (size == aligned_size) 314 | return; 315 | s8 end_offset = (s8)(size - aligned_size); 316 | s8* shadow_end = (s8*)MemToShadow(addr + aligned_size); 317 | s8 end_value = *shadow_end; 318 | if (do_poison) { 319 | // If possible, mark all the bytes mapping to last shadow byte as 320 | // unaddressable. 321 | if (end_value > 0 && end_value <= end_offset) 322 | *shadow_end = (s8)kAsanStackUseAfterScopeMagic; 323 | } else { 324 | // If necessary, mark few first bytes mapping to last shadow byte 325 | // as addressable 326 | if (end_value != 0) 327 | *shadow_end = Max(end_value, end_offset); 328 | } 329 | } 330 | 331 | void __asan_set_shadow_00(uptr addr, uptr size) { 332 | REAL(memset)((void *)addr, 0, size); 333 | } 334 | 335 | void __asan_set_shadow_f1(uptr addr, uptr size) { 336 | REAL(memset)((void *)addr, 0xf1, size); 337 | } 338 | 339 | void __asan_set_shadow_f2(uptr addr, uptr size) { 340 | REAL(memset)((void *)addr, 0xf2, size); 341 | } 342 | 343 | void __asan_set_shadow_f3(uptr addr, uptr size) { 344 | REAL(memset)((void *)addr, 0xf3, size); 345 | } 346 | 347 | void __asan_set_shadow_f5(uptr addr, uptr size) { 348 | REAL(memset)((void *)addr, 0xf5, size); 349 | } 350 | 351 | void __asan_set_shadow_f8(uptr addr, uptr size) { 352 | REAL(memset)((void *)addr, 0xf8, size); 353 | } 354 | 355 | void __asan_poison_stack_memory(uptr addr, uptr size) { 356 | if (*nesting_level != 0) { 357 | UNREACHABLE("poisoning shadow memory within SpecFuzz simulation"); 358 | return; 359 | } 360 | VReport(1, "poisoning: %p %zx\n", (void *)addr, size); 361 | PoisonAlignedStackMemory(addr, size, true); 362 | } 363 | 364 | void __asan_unpoison_stack_memory(uptr addr, uptr size) { 365 | VReport(1, "unpoisoning: %p %zx\n", (void *)addr, size); 366 | PoisonAlignedStackMemory(addr, size, false); 367 | } 368 | 369 | void __sanitizer_annotate_contiguous_container(const void *beg_p, 370 | const void *end_p, 371 | const void *old_mid_p, 372 | const void *new_mid_p) { 373 | if (!flags()->detect_container_overflow) return; 374 | VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p, 375 | new_mid_p); 376 | uptr beg = reinterpret_cast(beg_p); 377 | uptr end = reinterpret_cast(end_p); 378 | uptr old_mid = reinterpret_cast(old_mid_p); 379 | uptr new_mid = reinterpret_cast(new_mid_p); 380 | uptr granularity = SHADOW_GRANULARITY; 381 | if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end && 382 | IsAligned(beg, granularity))) { 383 | GET_STACK_TRACE_FATAL_HERE; 384 | ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid, 385 | &stack); 386 | } 387 | CHECK_LE(end - beg, 388 | FIRST_32_SECOND_64(1UL << 30, 1ULL << 34)); // Sanity check. 389 | 390 | uptr a = RoundDownTo(Min(old_mid, new_mid), granularity); 391 | uptr c = RoundUpTo(Max(old_mid, new_mid), granularity); 392 | uptr d1 = RoundDownTo(old_mid, granularity); 393 | // uptr d2 = RoundUpTo(old_mid, granularity); 394 | // Currently we should be in this state: 395 | // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good. 396 | // Make a quick sanity check that we are indeed in this state. 397 | // 398 | // FIXME: Two of these three checks are disabled until we fix 399 | // https://github.com/google/sanitizers/issues/258. 400 | // if (d1 != d2) 401 | // CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1); 402 | if (a + granularity <= d1) 403 | CHECK_EQ(*(u8*)MemToShadow(a), 0); 404 | // if (d2 + granularity <= c && c <= end) 405 | // CHECK_EQ(*(u8 *)MemToShadow(c - granularity), 406 | // kAsanContiguousContainerOOBMagic); 407 | 408 | uptr b1 = RoundDownTo(new_mid, granularity); 409 | uptr b2 = RoundUpTo(new_mid, granularity); 410 | // New state: 411 | // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good. 412 | PoisonShadow(a, b1 - a, 0); 413 | PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic); 414 | if (b1 != b2) { 415 | CHECK_EQ(b2 - b1, granularity); 416 | *(u8*)MemToShadow(b1) = static_cast(new_mid - b1); 417 | } 418 | } 419 | 420 | const void *__sanitizer_contiguous_container_find_bad_address( 421 | const void *beg_p, const void *mid_p, const void *end_p) { 422 | if (!flags()->detect_container_overflow) 423 | return nullptr; 424 | uptr beg = reinterpret_cast(beg_p); 425 | uptr end = reinterpret_cast(end_p); 426 | uptr mid = reinterpret_cast(mid_p); 427 | CHECK_LE(beg, mid); 428 | CHECK_LE(mid, end); 429 | // Check some bytes starting from beg, some bytes around mid, and some bytes 430 | // ending with end. 431 | uptr kMaxRangeToCheck = 32; 432 | uptr r1_beg = beg; 433 | uptr r1_end = Min(beg + kMaxRangeToCheck, mid); 434 | uptr r2_beg = Max(beg, mid - kMaxRangeToCheck); 435 | uptr r2_end = Min(end, mid + kMaxRangeToCheck); 436 | uptr r3_beg = Max(end - kMaxRangeToCheck, mid); 437 | uptr r3_end = end; 438 | for (uptr i = r1_beg; i < r1_end; i++) 439 | if (AddressIsPoisoned(i)) 440 | return reinterpret_cast(i); 441 | for (uptr i = r2_beg; i < mid; i++) 442 | if (AddressIsPoisoned(i)) 443 | return reinterpret_cast(i); 444 | for (uptr i = mid; i < r2_end; i++) 445 | if (!AddressIsPoisoned(i)) 446 | return reinterpret_cast(i); 447 | for (uptr i = r3_beg; i < r3_end; i++) 448 | if (!AddressIsPoisoned(i)) 449 | return reinterpret_cast(i); 450 | return nullptr; 451 | } 452 | 453 | int __sanitizer_verify_contiguous_container(const void *beg_p, 454 | const void *mid_p, 455 | const void *end_p) { 456 | return __sanitizer_contiguous_container_find_bad_address(beg_p, mid_p, 457 | end_p) == nullptr; 458 | } 459 | 460 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE 461 | void __asan_poison_intra_object_redzone(uptr ptr, uptr size) { 462 | if (*nesting_level != 0) { 463 | UNREACHABLE("poisoning shadow memory within SpecFuzz simulation"); 464 | return; 465 | } 466 | AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true); 467 | } 468 | 469 | extern "C" SANITIZER_INTERFACE_ATTRIBUTE 470 | void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) { 471 | AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false); 472 | } 473 | 474 | // --- Implementation of LSan-specific functions --- {{{1 475 | namespace __lsan { 476 | bool WordIsPoisoned(uptr addr) { 477 | return (__asan_region_is_poisoned(addr, sizeof(uptr)) != 0); 478 | } 479 | } 480 | -------------------------------------------------------------------------------- /install/patches/llvm/X86TargetMachine.cpp: -------------------------------------------------------------------------------- 1 | //===-- X86TargetMachine.cpp - Define TargetMachine for the X86 -----------===// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===----------------------------------------------------------------------===// 9 | // 10 | // This file defines the X86 specific subclass of TargetMachine. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #include "X86TargetMachine.h" 15 | #include "MCTargetDesc/X86MCTargetDesc.h" 16 | #include "X86.h" 17 | #include "X86CallLowering.h" 18 | #include "X86LegalizerInfo.h" 19 | #include "X86MacroFusion.h" 20 | #include "X86Subtarget.h" 21 | #include "X86TargetObjectFile.h" 22 | #include "X86TargetTransformInfo.h" 23 | #include "llvm/ADT/Optional.h" 24 | #include "llvm/ADT/STLExtras.h" 25 | #include "llvm/ADT/SmallString.h" 26 | #include "llvm/ADT/StringRef.h" 27 | #include "llvm/ADT/Triple.h" 28 | #include "llvm/Analysis/TargetTransformInfo.h" 29 | #include "llvm/CodeGen/ExecutionDomainFix.h" 30 | #include "llvm/CodeGen/GlobalISel/CallLowering.h" 31 | #include "llvm/CodeGen/GlobalISel/IRTranslator.h" 32 | #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" 33 | #include "llvm/CodeGen/GlobalISel/Legalizer.h" 34 | #include "llvm/CodeGen/GlobalISel/RegBankSelect.h" 35 | #include "llvm/CodeGen/MachineScheduler.h" 36 | #include "llvm/CodeGen/Passes.h" 37 | #include "llvm/CodeGen/TargetPassConfig.h" 38 | #include "llvm/IR/Attributes.h" 39 | #include "llvm/IR/DataLayout.h" 40 | #include "llvm/IR/Function.h" 41 | #include "llvm/Pass.h" 42 | #include "llvm/Support/CodeGen.h" 43 | #include "llvm/Support/CommandLine.h" 44 | #include "llvm/Support/ErrorHandling.h" 45 | #include "llvm/Support/TargetRegistry.h" 46 | #include "llvm/Target/TargetLoweringObjectFile.h" 47 | #include "llvm/Target/TargetOptions.h" 48 | #include 49 | #include 50 | 51 | using namespace llvm; 52 | 53 | static cl::opt EnableMachineCombinerPass("x86-machine-combiner", 54 | cl::desc("Enable the machine combiner pass"), 55 | cl::init(true), cl::Hidden); 56 | 57 | static cl::opt EnableSpeculativeLoadHardening( 58 | "x86-speculative-load-hardening", 59 | cl::desc("Enable speculative load hardening"), cl::init(false), cl::Hidden); 60 | 61 | static cl::opt EnableSpecFuzz( 62 | "x86-specfuzz", 63 | cl::desc("Enable SpecFuzz"), cl::init(false), cl::Hidden); 64 | 65 | namespace llvm { 66 | 67 | void initializeWinEHStatePassPass(PassRegistry &); 68 | void initializeFixupLEAPassPass(PassRegistry &); 69 | void initializeShadowCallStackPass(PassRegistry &); 70 | void initializeX86CallFrameOptimizationPass(PassRegistry &); 71 | void initializeX86CmovConverterPassPass(PassRegistry &); 72 | void initializeX86ExecutionDomainFixPass(PassRegistry &); 73 | void initializeX86DomainReassignmentPass(PassRegistry &); 74 | void initializeX86AvoidSFBPassPass(PassRegistry &); 75 | void initializeX86FlagsCopyLoweringPassPass(PassRegistry &); 76 | 77 | } // end namespace llvm 78 | 79 | extern "C" void LLVMInitializeX86Target() { 80 | // Register the target. 81 | RegisterTargetMachine X(getTheX86_32Target()); 82 | RegisterTargetMachine Y(getTheX86_64Target()); 83 | 84 | PassRegistry &PR = *PassRegistry::getPassRegistry(); 85 | initializeGlobalISel(PR); 86 | initializeWinEHStatePassPass(PR); 87 | initializeFixupBWInstPassPass(PR); 88 | initializeEvexToVexInstPassPass(PR); 89 | initializeFixupLEAPassPass(PR); 90 | initializeShadowCallStackPass(PR); 91 | initializeX86CallFrameOptimizationPass(PR); 92 | initializeX86CmovConverterPassPass(PR); 93 | initializeX86ExecutionDomainFixPass(PR); 94 | initializeX86DomainReassignmentPass(PR); 95 | initializeX86AvoidSFBPassPass(PR); 96 | initializeX86FlagsCopyLoweringPassPass(PR); 97 | } 98 | 99 | static std::unique_ptr createTLOF(const Triple &TT) { 100 | if (TT.isOSBinFormatMachO()) { 101 | if (TT.getArch() == Triple::x86_64) 102 | return llvm::make_unique(); 103 | return llvm::make_unique(); 104 | } 105 | 106 | if (TT.isOSFreeBSD()) 107 | return llvm::make_unique(); 108 | if (TT.isOSLinux() || TT.isOSNaCl() || TT.isOSIAMCU()) 109 | return llvm::make_unique(); 110 | if (TT.isOSSolaris()) 111 | return llvm::make_unique(); 112 | if (TT.isOSFuchsia()) 113 | return llvm::make_unique(); 114 | if (TT.isOSBinFormatELF()) 115 | return llvm::make_unique(); 116 | if (TT.isOSBinFormatCOFF()) 117 | return llvm::make_unique(); 118 | llvm_unreachable("unknown subtarget type"); 119 | } 120 | 121 | static std::string computeDataLayout(const Triple &TT) { 122 | // X86 is little endian 123 | std::string Ret = "e"; 124 | 125 | Ret += DataLayout::getManglingComponent(TT); 126 | // X86 and x32 have 32 bit pointers. 127 | if ((TT.isArch64Bit() && 128 | (TT.getEnvironment() == Triple::GNUX32 || TT.isOSNaCl())) || 129 | !TT.isArch64Bit()) 130 | Ret += "-p:32:32"; 131 | 132 | // Some ABIs align 64 bit integers and doubles to 64 bits, others to 32. 133 | if (TT.isArch64Bit() || TT.isOSWindows() || TT.isOSNaCl()) 134 | Ret += "-i64:64"; 135 | else if (TT.isOSIAMCU()) 136 | Ret += "-i64:32-f64:32"; 137 | else 138 | Ret += "-f64:32:64"; 139 | 140 | // Some ABIs align long double to 128 bits, others to 32. 141 | if (TT.isOSNaCl() || TT.isOSIAMCU()) 142 | ; // No f80 143 | else if (TT.isArch64Bit() || TT.isOSDarwin()) 144 | Ret += "-f80:128"; 145 | else 146 | Ret += "-f80:32"; 147 | 148 | if (TT.isOSIAMCU()) 149 | Ret += "-f128:32"; 150 | 151 | // The registers can hold 8, 16, 32 or, in x86-64, 64 bits. 152 | if (TT.isArch64Bit()) 153 | Ret += "-n8:16:32:64"; 154 | else 155 | Ret += "-n8:16:32"; 156 | 157 | // The stack is aligned to 32 bits on some ABIs and 128 bits on others. 158 | if ((!TT.isArch64Bit() && TT.isOSWindows()) || TT.isOSIAMCU()) 159 | Ret += "-a:0:32-S32"; 160 | else 161 | Ret += "-S128"; 162 | 163 | return Ret; 164 | } 165 | 166 | static Reloc::Model getEffectiveRelocModel(const Triple &TT, 167 | bool JIT, 168 | Optional RM) { 169 | bool is64Bit = TT.getArch() == Triple::x86_64; 170 | if (!RM.hasValue()) { 171 | // JIT codegen should use static relocations by default, since it's 172 | // typically executed in process and not relocatable. 173 | if (JIT) 174 | return Reloc::Static; 175 | 176 | // Darwin defaults to PIC in 64 bit mode and dynamic-no-pic in 32 bit mode. 177 | // Win64 requires rip-rel addressing, thus we force it to PIC. Otherwise we 178 | // use static relocation model by default. 179 | if (TT.isOSDarwin()) { 180 | if (is64Bit) 181 | return Reloc::PIC_; 182 | return Reloc::DynamicNoPIC; 183 | } 184 | if (TT.isOSWindows() && is64Bit) 185 | return Reloc::PIC_; 186 | return Reloc::Static; 187 | } 188 | 189 | // ELF and X86-64 don't have a distinct DynamicNoPIC model. DynamicNoPIC 190 | // is defined as a model for code which may be used in static or dynamic 191 | // executables but not necessarily a shared library. On X86-32 we just 192 | // compile in -static mode, in x86-64 we use PIC. 193 | if (*RM == Reloc::DynamicNoPIC) { 194 | if (is64Bit) 195 | return Reloc::PIC_; 196 | if (!TT.isOSDarwin()) 197 | return Reloc::Static; 198 | } 199 | 200 | // If we are on Darwin, disallow static relocation model in X86-64 mode, since 201 | // the Mach-O file format doesn't support it. 202 | if (*RM == Reloc::Static && TT.isOSDarwin() && is64Bit) 203 | return Reloc::PIC_; 204 | 205 | return *RM; 206 | } 207 | 208 | static CodeModel::Model getEffectiveCodeModel(Optional CM, 209 | bool JIT, bool Is64Bit) { 210 | if (CM) 211 | return *CM; 212 | if (JIT) 213 | return Is64Bit ? CodeModel::Large : CodeModel::Small; 214 | return CodeModel::Small; 215 | } 216 | 217 | /// Create an X86 target. 218 | /// 219 | X86TargetMachine::X86TargetMachine(const Target &T, const Triple &TT, 220 | StringRef CPU, StringRef FS, 221 | const TargetOptions &Options, 222 | Optional RM, 223 | Optional CM, 224 | CodeGenOpt::Level OL, bool JIT) 225 | : LLVMTargetMachine( 226 | T, computeDataLayout(TT), TT, CPU, FS, Options, 227 | getEffectiveRelocModel(TT, JIT, RM), 228 | getEffectiveCodeModel(CM, JIT, TT.getArch() == Triple::x86_64), OL), 229 | TLOF(createTLOF(getTargetTriple())) { 230 | // Windows stack unwinder gets confused when execution flow "falls through" 231 | // after a call to 'noreturn' function. 232 | // To prevent that, we emit a trap for 'unreachable' IR instructions. 233 | // (which on X86, happens to be the 'ud2' instruction) 234 | // On PS4, the "return address" of a 'noreturn' call must still be within 235 | // the calling function, and TrapUnreachable is an easy way to get that. 236 | // The check here for 64-bit windows is a bit icky, but as we're unlikely 237 | // to ever want to mix 32 and 64-bit windows code in a single module 238 | // this should be fine. 239 | if ((TT.isOSWindows() && TT.getArch() == Triple::x86_64) || TT.isPS4() || 240 | TT.isOSBinFormatMachO()) { 241 | this->Options.TrapUnreachable = true; 242 | this->Options.NoTrapAfterNoreturn = TT.isOSBinFormatMachO(); 243 | } 244 | 245 | // Outlining is available for x86-64. 246 | if (TT.getArch() == Triple::x86_64) 247 | setMachineOutliner(true); 248 | 249 | initAsmInfo(); 250 | } 251 | 252 | X86TargetMachine::~X86TargetMachine() = default; 253 | 254 | const X86Subtarget * 255 | X86TargetMachine::getSubtargetImpl(const Function &F) const { 256 | Attribute CPUAttr = F.getFnAttribute("target-cpu"); 257 | Attribute FSAttr = F.getFnAttribute("target-features"); 258 | 259 | StringRef CPU = !CPUAttr.hasAttribute(Attribute::None) 260 | ? CPUAttr.getValueAsString() 261 | : (StringRef)TargetCPU; 262 | StringRef FS = !FSAttr.hasAttribute(Attribute::None) 263 | ? FSAttr.getValueAsString() 264 | : (StringRef)TargetFS; 265 | 266 | SmallString<512> Key; 267 | Key.reserve(CPU.size() + FS.size()); 268 | Key += CPU; 269 | Key += FS; 270 | 271 | // FIXME: This is related to the code below to reset the target options, 272 | // we need to know whether or not the soft float flag is set on the 273 | // function before we can generate a subtarget. We also need to use 274 | // it as a key for the subtarget since that can be the only difference 275 | // between two functions. 276 | bool SoftFloat = 277 | F.getFnAttribute("use-soft-float").getValueAsString() == "true"; 278 | // If the soft float attribute is set on the function turn on the soft float 279 | // subtarget feature. 280 | if (SoftFloat) 281 | Key += FS.empty() ? "+soft-float" : ",+soft-float"; 282 | 283 | // Keep track of the key width after all features are added so we can extract 284 | // the feature string out later. 285 | unsigned CPUFSWidth = Key.size(); 286 | 287 | // Extract prefer-vector-width attribute. 288 | unsigned PreferVectorWidthOverride = 0; 289 | if (F.hasFnAttribute("prefer-vector-width")) { 290 | StringRef Val = F.getFnAttribute("prefer-vector-width").getValueAsString(); 291 | unsigned Width; 292 | if (!Val.getAsInteger(0, Width)) { 293 | Key += ",prefer-vector-width="; 294 | Key += Val; 295 | PreferVectorWidthOverride = Width; 296 | } 297 | } 298 | 299 | // Extract required-vector-width attribute. 300 | unsigned RequiredVectorWidth = UINT32_MAX; 301 | if (F.hasFnAttribute("required-vector-width")) { 302 | StringRef Val = F.getFnAttribute("required-vector-width").getValueAsString(); 303 | unsigned Width; 304 | if (!Val.getAsInteger(0, Width)) { 305 | Key += ",required-vector-width="; 306 | Key += Val; 307 | RequiredVectorWidth = Width; 308 | } 309 | } 310 | 311 | // Extracted here so that we make sure there is backing for the StringRef. If 312 | // we assigned earlier, its possible the SmallString reallocated leaving a 313 | // dangling StringRef. 314 | FS = Key.slice(CPU.size(), CPUFSWidth); 315 | 316 | auto &I = SubtargetMap[Key]; 317 | if (!I) { 318 | // This needs to be done before we create a new subtarget since any 319 | // creation will depend on the TM and the code generation flags on the 320 | // function that reside in TargetOptions. 321 | resetTargetOptions(F); 322 | I = llvm::make_unique(TargetTriple, CPU, FS, *this, 323 | Options.StackAlignmentOverride, 324 | PreferVectorWidthOverride, 325 | RequiredVectorWidth); 326 | } 327 | return I.get(); 328 | } 329 | 330 | //===----------------------------------------------------------------------===// 331 | // Command line options for x86 332 | //===----------------------------------------------------------------------===// 333 | static cl::opt 334 | UseVZeroUpper("x86-use-vzeroupper", cl::Hidden, 335 | cl::desc("Minimize AVX to SSE transition penalty"), 336 | cl::init(true)); 337 | 338 | //===----------------------------------------------------------------------===// 339 | // X86 TTI query. 340 | //===----------------------------------------------------------------------===// 341 | 342 | TargetTransformInfo 343 | X86TargetMachine::getTargetTransformInfo(const Function &F) { 344 | return TargetTransformInfo(X86TTIImpl(this, F)); 345 | } 346 | 347 | //===----------------------------------------------------------------------===// 348 | // Pass Pipeline Configuration 349 | //===----------------------------------------------------------------------===// 350 | 351 | namespace { 352 | 353 | /// X86 Code Generator Pass Configuration Options. 354 | class X86PassConfig : public TargetPassConfig { 355 | public: 356 | X86PassConfig(X86TargetMachine &TM, PassManagerBase &PM) 357 | : TargetPassConfig(TM, PM) {} 358 | 359 | X86TargetMachine &getX86TargetMachine() const { 360 | return getTM(); 361 | } 362 | 363 | ScheduleDAGInstrs * 364 | createMachineScheduler(MachineSchedContext *C) const override { 365 | ScheduleDAGMILive *DAG = createGenericSchedLive(C); 366 | DAG->addMutation(createX86MacroFusionDAGMutation()); 367 | return DAG; 368 | } 369 | 370 | void addIRPasses() override; 371 | bool addInstSelector() override; 372 | bool addIRTranslator() override; 373 | bool addLegalizeMachineIR() override; 374 | bool addRegBankSelect() override; 375 | bool addGlobalInstructionSelect() override; 376 | bool addILPOpts() override; 377 | bool addPreISel() override; 378 | void addMachineSSAOptimization() override; 379 | void addPreRegAlloc() override; 380 | void addPostRegAlloc() override; 381 | void addPreEmitPass() override; 382 | void addPreEmitPass2() override; 383 | void addPreSched2() override; 384 | }; 385 | 386 | class X86ExecutionDomainFix : public ExecutionDomainFix { 387 | public: 388 | static char ID; 389 | X86ExecutionDomainFix() : ExecutionDomainFix(ID, X86::VR128XRegClass) {} 390 | StringRef getPassName() const override { 391 | return "X86 Execution Dependency Fix"; 392 | } 393 | }; 394 | char X86ExecutionDomainFix::ID; 395 | 396 | } // end anonymous namespace 397 | 398 | INITIALIZE_PASS_BEGIN(X86ExecutionDomainFix, "x86-execution-domain-fix", 399 | "X86 Execution Domain Fix", false, false) 400 | INITIALIZE_PASS_DEPENDENCY(ReachingDefAnalysis) 401 | INITIALIZE_PASS_END(X86ExecutionDomainFix, "x86-execution-domain-fix", 402 | "X86 Execution Domain Fix", false, false) 403 | 404 | TargetPassConfig *X86TargetMachine::createPassConfig(PassManagerBase &PM) { 405 | return new X86PassConfig(*this, PM); 406 | } 407 | 408 | void X86PassConfig::addIRPasses() { 409 | addPass(createAtomicExpandPass()); 410 | 411 | TargetPassConfig::addIRPasses(); 412 | 413 | if (TM->getOptLevel() != CodeGenOpt::None) 414 | addPass(createInterleavedAccessPass()); 415 | 416 | // Add passes that handle indirect branch removal and insertion of a retpoline 417 | // thunk. These will be a no-op unless a function subtarget has the retpoline 418 | // feature enabled. 419 | addPass(createIndirectBrExpandPass()); 420 | } 421 | 422 | bool X86PassConfig::addInstSelector() { 423 | // Install an instruction selector. 424 | addPass(createX86ISelDag(getX86TargetMachine(), getOptLevel())); 425 | 426 | // For ELF, cleanup any local-dynamic TLS accesses. 427 | if (TM->getTargetTriple().isOSBinFormatELF() && 428 | getOptLevel() != CodeGenOpt::None) 429 | addPass(createCleanupLocalDynamicTLSPass()); 430 | 431 | addPass(createX86GlobalBaseRegPass()); 432 | return false; 433 | } 434 | 435 | bool X86PassConfig::addIRTranslator() { 436 | addPass(new IRTranslator()); 437 | return false; 438 | } 439 | 440 | bool X86PassConfig::addLegalizeMachineIR() { 441 | addPass(new Legalizer()); 442 | return false; 443 | } 444 | 445 | bool X86PassConfig::addRegBankSelect() { 446 | addPass(new RegBankSelect()); 447 | return false; 448 | } 449 | 450 | bool X86PassConfig::addGlobalInstructionSelect() { 451 | addPass(new InstructionSelect()); 452 | return false; 453 | } 454 | 455 | bool X86PassConfig::addILPOpts() { 456 | addPass(&EarlyIfConverterID); 457 | if (EnableMachineCombinerPass) 458 | addPass(&MachineCombinerID); 459 | addPass(createX86CmovConverterPass()); 460 | return true; 461 | } 462 | 463 | bool X86PassConfig::addPreISel() { 464 | // Only add this pass for 32-bit x86 Windows. 465 | const Triple &TT = TM->getTargetTriple(); 466 | if (TT.isOSWindows() && TT.getArch() == Triple::x86) 467 | addPass(createX86WinEHStatePass()); 468 | return true; 469 | } 470 | 471 | void X86PassConfig::addPreRegAlloc() { 472 | if (getOptLevel() != CodeGenOpt::None) { 473 | addPass(&LiveRangeShrinkID); 474 | addPass(createX86FixupSetCC()); 475 | addPass(createX86OptimizeLEAs()); 476 | addPass(createX86CallFrameOptimization()); 477 | addPass(createX86AvoidStoreForwardingBlocks()); 478 | } 479 | 480 | if (EnableSpeculativeLoadHardening) 481 | addPass(createX86SpeculativeLoadHardeningPass()); 482 | 483 | addPass(createX86FlagsCopyLoweringPass()); 484 | addPass(createX86WinAllocaExpander()); 485 | } 486 | void X86PassConfig::addMachineSSAOptimization() { 487 | addPass(createX86DomainReassignmentPass()); 488 | TargetPassConfig::addMachineSSAOptimization(); 489 | } 490 | 491 | void X86PassConfig::addPostRegAlloc() { 492 | addPass(createX86FloatingPointStackifierPass()); 493 | } 494 | 495 | void X86PassConfig::addPreSched2() { addPass(createX86ExpandPseudoPass()); } 496 | 497 | void X86PassConfig::addPreEmitPass() { 498 | if (getOptLevel() != CodeGenOpt::None) { 499 | addPass(new X86ExecutionDomainFix()); 500 | addPass(createBreakFalseDeps()); 501 | } 502 | 503 | addPass(createShadowCallStackPass()); 504 | addPass(createX86IndirectBranchTrackingPass()); 505 | 506 | if (UseVZeroUpper) 507 | addPass(createX86IssueVZeroUpperPass()); 508 | 509 | if (getOptLevel() != CodeGenOpt::None) { 510 | addPass(createX86FixupBWInsts()); 511 | addPass(createX86PadShortFunctions()); 512 | addPass(createX86FixupLEAs()); 513 | addPass(createX86EvexToVexInsts()); 514 | } 515 | } 516 | 517 | void X86PassConfig::addPreEmitPass2() { 518 | addPass(createX86RetpolineThunksPass()); 519 | if (EnableSpecFuzz) 520 | addPass(createX86SpecFuzzPass()); 521 | // Verify basic block incoming and outgoing cfa offset and register values and 522 | // correct CFA calculation rule where needed by inserting appropriate CFI 523 | // instructions. 524 | const Triple &TT = TM->getTargetTriple(); 525 | if (!TT.isOSDarwin() && !TT.isOSWindows()) 526 | addPass(createCFIInstrInserter()); 527 | } 528 | -------------------------------------------------------------------------------- /install/patches/honggfuzz/fuzz.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * honggfuzz - fuzzing routines 4 | * ----------------------------------------- 5 | * 6 | * Authors: Robert Swiecki 7 | * Felix Gröbert 8 | * 9 | * Copyright 2010-2018 by Google Inc. All Rights Reserved. 10 | * 11 | * Licensed under the Apache License, Version 2.0 (the "License"); you may 12 | * not use this file except in compliance with the License. You may obtain 13 | * a copy of the License at 14 | * 15 | * http://www.apache.org/licenses/LICENSE-2.0 16 | * 17 | * Unless required by applicable law or agreed to in writing, software 18 | * distributed under the License is distributed on an "AS IS" BASIS, 19 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 20 | * implied. See the License for the specific language governing 21 | * permissions and limitations under the License. 22 | * 23 | */ 24 | 25 | #include "fuzz.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "arch.h" 47 | #include "honggfuzz.h" 48 | #include "input.h" 49 | #include "libhfcommon/common.h" 50 | #include "libhfcommon/files.h" 51 | #include "libhfcommon/log.h" 52 | #include "libhfcommon/util.h" 53 | #include "mangle.h" 54 | #include "report.h" 55 | #include "sanitizers.h" 56 | #include "socketfuzzer.h" 57 | #include "subproc.h" 58 | 59 | static time_t termTimeStamp = 0; 60 | 61 | bool fuzz_isTerminating(void) { 62 | if (ATOMIC_GET(termTimeStamp) != 0) { 63 | return true; 64 | } 65 | return false; 66 | } 67 | 68 | void fuzz_setTerminating(void) { 69 | if (ATOMIC_GET(termTimeStamp) != 0) { 70 | return; 71 | } 72 | ATOMIC_SET(termTimeStamp, time(NULL)); 73 | } 74 | 75 | bool fuzz_shouldTerminate() { 76 | if (ATOMIC_GET(termTimeStamp) == 0) { 77 | return false; 78 | } 79 | if ((time(NULL) - ATOMIC_GET(termTimeStamp)) > 5) { 80 | return true; 81 | } 82 | return false; 83 | } 84 | 85 | static fuzzState_t fuzz_getState(honggfuzz_t* hfuzz) { 86 | return ATOMIC_GET(hfuzz->feedback.state); 87 | } 88 | 89 | static bool fuzz_writeCovFile(const char* dir, const uint8_t* data, size_t len) { 90 | char fname[PATH_MAX]; 91 | 92 | uint64_t crc64f = util_CRC64(data, len); 93 | uint64_t crc64r = util_CRC64Rev(data, len); 94 | snprintf(fname, sizeof(fname), "%s/%016" PRIx64 "%016" PRIx64 ".%08" PRIx32 ".honggfuzz.cov", 95 | dir, crc64f, crc64r, (uint32_t)len); 96 | 97 | if (files_exists(fname)) { 98 | LOG_D("File '%s' already exists in the output corpus directory '%s'", fname, dir); 99 | return true; 100 | } 101 | 102 | LOG_D("Adding file '%s' to the corpus directory '%s'", fname, dir); 103 | 104 | if (!files_writeBufToFile(fname, data, len, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC)) { 105 | LOG_W("Couldn't write buffer to file '%s'", fname); 106 | return false; 107 | } 108 | 109 | return true; 110 | } 111 | 112 | static void fuzz_addFileToFileQ(honggfuzz_t* hfuzz, const uint8_t* data, size_t len) { 113 | ATOMIC_SET(hfuzz->timing.lastCovUpdate, time(NULL)); 114 | 115 | struct dynfile_t* dynfile = (struct dynfile_t*)util_Malloc(sizeof(struct dynfile_t)); 116 | dynfile->size = len; 117 | dynfile->data = (uint8_t*)util_Malloc(len); 118 | memcpy(dynfile->data, data, len); 119 | 120 | MX_SCOPED_RWLOCK_WRITE(&hfuzz->io.dynfileq_mutex); 121 | TAILQ_INSERT_TAIL(&hfuzz->io.dynfileq, dynfile, pointers); 122 | hfuzz->io.dynfileqCnt++; 123 | 124 | if (hfuzz->socketFuzzer.enabled) { 125 | /* Don't add coverage data to files in socketFuzzer mode */ 126 | return; 127 | } 128 | 129 | if (!fuzz_writeCovFile(hfuzz->io.covDirAll, data, len)) { 130 | LOG_E("Couldn't save the coverage data to '%s'", hfuzz->io.covDirAll); 131 | } 132 | 133 | /* No need to add files to the new coverage dir, if this is just the dry-run phase */ 134 | if (fuzz_getState(hfuzz) == _HF_STATE_DYNAMIC_DRY_RUN || hfuzz->io.covDirNew == NULL) { 135 | return; 136 | } 137 | 138 | if (!fuzz_writeCovFile(hfuzz->io.covDirNew, data, len)) { 139 | LOG_E("Couldn't save the new coverage data to '%s'", hfuzz->io.covDirNew); 140 | } 141 | } 142 | 143 | static void fuzz_setDynamicMainState(run_t* run) { 144 | /* All threads need to indicate willingness to switch to the DYNAMIC_MAIN state. Count them! */ 145 | static uint32_t cnt = 0; 146 | ATOMIC_PRE_INC(cnt); 147 | 148 | static pthread_mutex_t state_mutex = PTHREAD_MUTEX_INITIALIZER; 149 | MX_SCOPED_LOCK(&state_mutex); 150 | 151 | if (fuzz_getState(run->global) == _HF_STATE_DYNAMIC_MAIN) { 152 | return; 153 | } 154 | 155 | LOG_I("Entering phase 2/3: Switching to Dynamic Main (Feedback Driven Mode)"); 156 | ATOMIC_SET(run->global->feedback.state, _HF_STATE_DYNAMIC_SWITCH_TO_MAIN); 157 | 158 | for (;;) { 159 | /* Check if all threads have already reported in for changing state */ 160 | if (ATOMIC_GET(cnt) == run->global->threads.threadsMax) { 161 | break; 162 | } 163 | if (fuzz_isTerminating()) { 164 | return; 165 | } 166 | util_sleepForMSec(10); /* Check every 10ms */ 167 | } 168 | 169 | LOG_I("Entering phase 3/3: Dynamic Main (Feedback Driven Mode)"); 170 | snprintf(run->origFileName, sizeof(run->origFileName), "[DYNAMIC]"); 171 | ATOMIC_SET(run->global->feedback.state, _HF_STATE_DYNAMIC_MAIN); 172 | 173 | /* 174 | * If the initial fuzzing yielded no useful coverage, just add a single 1-byte file to the 175 | * dynamic corpus, so the dynamic phase doesn't fail because of lack of useful inputs 176 | */ 177 | if (run->global->io.dynfileqCnt == 0) { 178 | const char* single_byte = run->global->cfg.only_printable ? " " : "\0"; 179 | fuzz_addFileToFileQ(run->global, (const uint8_t*)single_byte, 1U); 180 | } 181 | } 182 | 183 | static void fuzz_perfFeedback(run_t* run) { 184 | if (run->global->feedback.skipFeedbackOnTimeout && run->tmOutSignaled) { 185 | return; 186 | } 187 | 188 | LOG_D("New file size: %zu, Perf feedback new/cur (instr,branch): %" PRIu64 "/%" PRIu64 189 | "/%" PRIu64 "/%" PRIu64 ", BBcnt new/total: %" PRIu64 "/%" PRIu64, 190 | run->dynamicFileSz, run->linux.hwCnts.cpuInstrCnt, run->global->linux.hwCnts.cpuInstrCnt, 191 | run->linux.hwCnts.cpuBranchCnt, run->global->linux.hwCnts.cpuBranchCnt, 192 | run->linux.hwCnts.newBBCnt, run->global->linux.hwCnts.bbCnt); 193 | 194 | MX_SCOPED_LOCK(&run->global->feedback.feedback_mutex); 195 | defer { 196 | wmb(); 197 | }; 198 | 199 | uint64_t softCntPc = 0; 200 | uint64_t softCntEdge = 0; 201 | uint64_t softCntCmp = 0; 202 | if (run->global->feedback.bbFd != -1) { 203 | softCntPc = ATOMIC_GET(run->global->feedback.feedbackMap->pidFeedbackPc[run->fuzzNo]); 204 | ATOMIC_CLEAR(run->global->feedback.feedbackMap->pidFeedbackPc[run->fuzzNo]); 205 | softCntEdge = ATOMIC_GET(run->global->feedback.feedbackMap->pidFeedbackEdge[run->fuzzNo]); 206 | ATOMIC_CLEAR(run->global->feedback.feedbackMap->pidFeedbackEdge[run->fuzzNo]); 207 | softCntCmp = ATOMIC_GET(run->global->feedback.feedbackMap->pidFeedbackCmp[run->fuzzNo]); 208 | ATOMIC_CLEAR(run->global->feedback.feedbackMap->pidFeedbackCmp[run->fuzzNo]); 209 | } 210 | 211 | int64_t diff0 = run->global->linux.hwCnts.cpuInstrCnt - run->linux.hwCnts.cpuInstrCnt; 212 | int64_t diff1 = run->global->linux.hwCnts.cpuBranchCnt - run->linux.hwCnts.cpuBranchCnt; 213 | 214 | /* Any increase in coverage (edge, pc, cmp, hw) counters forces adding input to the corpus */ 215 | if (run->linux.hwCnts.newBBCnt > 0 || softCntPc > 0 || softCntEdge > 0 || softCntCmp > 0 || 216 | diff0 < 0 || diff1 < 0) { 217 | if (diff0 < 0) { 218 | run->global->linux.hwCnts.cpuInstrCnt = run->linux.hwCnts.cpuInstrCnt; 219 | } 220 | if (diff1 < 0) { 221 | run->global->linux.hwCnts.cpuBranchCnt = run->linux.hwCnts.cpuBranchCnt; 222 | } 223 | run->global->linux.hwCnts.bbCnt += run->linux.hwCnts.newBBCnt; 224 | run->global->linux.hwCnts.softCntPc += softCntPc; 225 | run->global->linux.hwCnts.softCntEdge += softCntEdge; 226 | run->global->linux.hwCnts.softCntCmp += softCntCmp; 227 | 228 | LOG_I("Size:%zu (i,b,hw,edge,ip,cmp): %" PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64 229 | "/%" PRIu64 "/%" PRIu64 ", Tot:%" PRIu64 "/%" PRIu64 "/%" PRIu64 "/%" PRIu64 230 | "/%" PRIu64 "/%" PRIu64, 231 | run->dynamicFileSz, run->linux.hwCnts.cpuInstrCnt, run->linux.hwCnts.cpuBranchCnt, 232 | run->linux.hwCnts.newBBCnt, softCntEdge, softCntPc, softCntCmp, 233 | run->global->linux.hwCnts.cpuInstrCnt, run->global->linux.hwCnts.cpuBranchCnt, 234 | run->global->linux.hwCnts.bbCnt, run->global->linux.hwCnts.softCntEdge, 235 | run->global->linux.hwCnts.softCntPc, run->global->linux.hwCnts.softCntCmp); 236 | 237 | fuzz_addFileToFileQ(run->global, run->dynamicFile, run->dynamicFileSz); 238 | 239 | if (run->global->socketFuzzer.enabled) { 240 | LOG_D("SocketFuzzer: fuzz: new BB (perf)"); 241 | fuzz_notifySocketFuzzerNewCov(run->global); 242 | } 243 | } 244 | } 245 | 246 | /* Return value indicates whether report file should be updated with the current verified crash */ 247 | static bool fuzz_runVerifier(run_t* run) { 248 | if (!run->crashFileName[0] || !run->backtrace) { 249 | return false; 250 | } 251 | 252 | uint64_t backtrace = run->backtrace; 253 | 254 | char origCrashPath[PATH_MAX]; 255 | snprintf(origCrashPath, sizeof(origCrashPath), "%s", run->crashFileName); 256 | /* Workspace is inherited, just append a extra suffix */ 257 | char verFile[PATH_MAX]; 258 | snprintf(verFile, sizeof(verFile), "%s.verified", origCrashPath); 259 | 260 | if (files_exists(verFile)) { 261 | LOG_D("Crash file to verify '%s' is already verified as '%s'", origCrashPath, verFile); 262 | return false; 263 | } 264 | 265 | for (int i = 0; i < _HF_VERIFIER_ITER; i++) { 266 | LOG_I("Launching verifier for HASH: %" PRIx64 " (iteration: %d out of %d)", run->backtrace, 267 | i + 1, _HF_VERIFIER_ITER); 268 | run->timeStartedMillis = 0; 269 | run->backtrace = 0; 270 | run->access = 0; 271 | run->exception = 0; 272 | run->mainWorker = false; 273 | 274 | if (!subproc_Run(run)) { 275 | LOG_F("subproc_Run()"); 276 | } 277 | 278 | /* If stack hash doesn't match skip name tag and exit */ 279 | if (run->backtrace != backtrace) { 280 | LOG_E("Verifier stack mismatch: (original) %" PRIx64 " != (new) %" PRIx64, backtrace, 281 | run->backtrace); 282 | run->backtrace = backtrace; 283 | return true; 284 | } 285 | 286 | LOG_I("Verifier for HASH: %" PRIx64 " (iteration: %d, left: %d). MATCH!", run->backtrace, 287 | i + 1, _HF_VERIFIER_ITER - i - 1); 288 | } 289 | 290 | /* Copy file with new suffix & remove original copy */ 291 | int fd = TEMP_FAILURE_RETRY(open(verFile, O_CREAT | O_EXCL | O_WRONLY, 0600)); 292 | if (fd == -1 && errno == EEXIST) { 293 | LOG_I("It seems that '%s' already exists, skipping", verFile); 294 | return false; 295 | } 296 | if (fd == -1) { 297 | PLOG_E("Couldn't create '%s'", verFile); 298 | return true; 299 | } 300 | defer { 301 | close(fd); 302 | }; 303 | if (!files_writeToFd(fd, run->dynamicFile, run->dynamicFileSz)) { 304 | LOG_E("Couldn't save verified file as '%s'", verFile); 305 | unlink(verFile); 306 | return true; 307 | } 308 | 309 | LOG_I("Verified crash for HASH: %" PRIx64 " and saved it as '%s'", backtrace, verFile); 310 | ATOMIC_PRE_INC(run->global->cnts.verifiedCrashesCnt); 311 | 312 | return true; 313 | } 314 | 315 | static bool fuzz_fetchInput(run_t* run) { 316 | { 317 | fuzzState_t st = fuzz_getState(run->global); 318 | if (st == _HF_STATE_DYNAMIC_DRY_RUN || st == _HF_STATE_DYNAMIC_SWITCH_TO_MAIN) { 319 | run->mutationsPerRun = 0U; 320 | if (input_prepareStaticFile(run, /* rewind= */ false, true)) { 321 | return true; 322 | } 323 | fuzz_setDynamicMainState(run); 324 | run->mutationsPerRun = run->global->mutate.mutationsPerRun; 325 | } 326 | } 327 | 328 | if (fuzz_getState(run->global) == _HF_STATE_DYNAMIC_MAIN) { 329 | if (run->global->exe.externalCommand) { 330 | if (!input_prepareExternalFile(run)) { 331 | LOG_E("input_prepareFileExternally() failed"); 332 | return false; 333 | } 334 | } else if (run->global->exe.feedbackMutateCommand) { 335 | if (!input_prepareDynamicInput(run, false)) { 336 | LOG_E("input_prepareFileDynamically() failed"); 337 | return false; 338 | } 339 | } else if (!input_prepareDynamicInput(run, true)) { 340 | LOG_E("input_prepareFileDynamically() failed"); 341 | return false; 342 | } 343 | } 344 | 345 | if (fuzz_getState(run->global) == _HF_STATE_STATIC) { 346 | if (run->global->exe.externalCommand) { 347 | if (!input_prepareExternalFile(run)) { 348 | LOG_E("input_prepareFileExternally() failed"); 349 | return false; 350 | } 351 | } else if (run->global->exe.feedbackMutateCommand) { 352 | if (!input_prepareStaticFile(run, true, false)) { 353 | LOG_E("input_prepareFileDynamically() failed"); 354 | return false; 355 | } 356 | } else if (!input_prepareStaticFile(run, true /* rewind */, true)) { 357 | LOG_E("input_prepareFile() failed"); 358 | return false; 359 | } 360 | } 361 | 362 | if (run->global->exe.postExternalCommand && !input_postProcessFile(run)) { 363 | LOG_E("input_postProcessFile() failed"); 364 | return false; 365 | } 366 | 367 | if (run->global->exe.feedbackMutateCommand && !input_feedbackMutateFile(run)) { 368 | LOG_E("input_feedbackMutateFile() failed"); 369 | return false; 370 | } 371 | 372 | return true; 373 | } 374 | 375 | static void fuzz_fuzzLoop(run_t* run) { 376 | run->timeStartedMillis = 0; 377 | run->crashFileName[0] = '\0'; 378 | run->pc = 0; 379 | run->backtrace = 0; 380 | run->access = 0; 381 | run->exception = 0; 382 | run->report[0] = '\0'; 383 | run->mainWorker = true; 384 | run->mutationsPerRun = run->global->mutate.mutationsPerRun; 385 | run->dynamicFileSz = 0; 386 | run->dynamicFileCopyFd = -1; 387 | run->tmOutSignaled = false; 388 | 389 | run->linux.hwCnts.cpuInstrCnt = 0; 390 | run->linux.hwCnts.cpuBranchCnt = 0; 391 | run->linux.hwCnts.bbCnt = 0; 392 | run->linux.hwCnts.newBBCnt = 0; 393 | 394 | if (!fuzz_fetchInput(run)) { 395 | LOG_F("Cound't prepare input for fuzzing"); 396 | } 397 | if (!subproc_Run(run)) { 398 | LOG_F("Couldn't run fuzzed command"); 399 | } 400 | 401 | if (run->global->feedback.dynFileMethod != _HF_DYNFILE_NONE) { 402 | fuzz_perfFeedback(run); 403 | } 404 | if (run->global->cfg.useVerifier && !fuzz_runVerifier(run)) { 405 | return; 406 | } 407 | report_Report(run); 408 | } 409 | 410 | static void fuzz_fuzzLoopSocket(run_t* run) { 411 | run->timeStartedMillis = 0; 412 | run->crashFileName[0] = '\0'; 413 | run->pc = 0; 414 | run->backtrace = 0; 415 | run->access = 0; 416 | run->exception = 0; 417 | run->report[0] = '\0'; 418 | run->mainWorker = true; 419 | run->mutationsPerRun = run->global->mutate.mutationsPerRun; 420 | run->dynamicFileSz = 0; 421 | run->dynamicFileCopyFd = -1; 422 | run->tmOutSignaled = false; 423 | 424 | run->linux.hwCnts.cpuInstrCnt = 0; 425 | run->linux.hwCnts.cpuBranchCnt = 0; 426 | run->linux.hwCnts.bbCnt = 0; 427 | run->linux.hwCnts.newBBCnt = 0; 428 | 429 | LOG_I("------------------------------------------------------"); 430 | 431 | /* First iteration: Start target 432 | Other iterations: re-start target, if necessary 433 | subproc_Run() will decide by itself if a restart is necessary, via 434 | subproc_New() 435 | */ 436 | LOG_D("------[ 1: subproc_run"); 437 | if (!subproc_Run(run)) { 438 | LOG_W("Couldn't run server"); 439 | } 440 | 441 | /* Tell the external fuzzer to send data to target 442 | The fuzzer will notify us when finished; block until then. 443 | */ 444 | LOG_D("------[ 2: fetch input"); 445 | if (!fuzz_waitForExternalInput(run)) { 446 | /* Fuzzer could not connect to target, and told us to 447 | restart it. Do it on the next iteration. 448 | or: it crashed by fuzzing. Restart it too. 449 | */ 450 | LOG_D("------[ 2.1: Target down, will restart it"); 451 | run->pid = 0; // make subproc_Run() restart it on next iteration 452 | return; 453 | } 454 | 455 | LOG_D("------[ 3: feedback"); 456 | if (run->global->feedback.dynFileMethod != _HF_DYNFILE_NONE) { 457 | fuzz_perfFeedback(run); 458 | } 459 | if (run->global->cfg.useVerifier && !fuzz_runVerifier(run)) { 460 | return; 461 | } 462 | 463 | report_Report(run); 464 | } 465 | 466 | /// A testing function that prints the number of elements in every bucket 467 | /// 468 | /// TODO: this function does not fit well into the scope of this file. 469 | /// Move it somewhere else 470 | void hash_map_usage(feedback_t *feedback) { 471 | map_entry_t *coverage_map = feedback->cmpMapPc; 472 | LOG_I("Coverage map: item distribution"); 473 | int free = 0; 474 | int max = 0; 475 | for (unsigned i = 0; i < COVERAGE_MAP_HASHMAP_SIZE; i++) { 476 | map_entry_t *entry = &(coverage_map[i]); 477 | if (entry->count == 0) { 478 | free++; 479 | continue; 480 | } 481 | 482 | LOG_I("Starting Bucket %d", i); 483 | map_entry_t *coverage_map_conflicts = &coverage_map[COVERAGE_MAP_HASHMAP_SIZE]; 484 | int depth = 1; 485 | while (1) { 486 | LOG_I("Enter depth %d, next %d", depth, entry->next); 487 | if (entry->next == 0) { 488 | break; 489 | } 490 | entry = &coverage_map_conflicts[entry->next]; 491 | depth++; 492 | } 493 | if (depth > max) max = depth; 494 | //LOG_I("Bucket %d: %d", i, depth); 495 | } 496 | LOG_I("Free buckets: %d%%", (free * 100 / COVERAGE_MAP_HASHMAP_SIZE)); 497 | LOG_I("Max items per bucket: %d", max); 498 | LOG_I("Num conflicts: %d; max allowed: %d", feedback->cmpMapPcTop, COVERAGE_MAP_CONFLICTS_SIZE); 499 | } 500 | 501 | static void* fuzz_threadNew(void* arg) { 502 | honggfuzz_t* hfuzz = (honggfuzz_t*)arg; 503 | unsigned int fuzzNo = ATOMIC_POST_INC(hfuzz->threads.threadsActiveCnt); 504 | LOG_I("Launched new fuzzing thread, no. #%" PRId32, fuzzNo); 505 | 506 | run_t run = { 507 | .global = hfuzz, 508 | .pid = 0, 509 | .dynfileqCurrent = NULL, 510 | .dynamicFile = NULL, 511 | .dynamicFileFd = -1, 512 | .fuzzNo = fuzzNo, 513 | .persistentSock = -1, 514 | .tmOutSignaled = false, 515 | .origFileName = "[DYNAMIC]", 516 | }; 517 | 518 | /* Do not try to handle input files with socketfuzzer */ 519 | if (!hfuzz->socketFuzzer.enabled) { 520 | if (!(run.dynamicFile = files_mapSharedMem(hfuzz->mutate.maxFileSz, &run.dynamicFileFd, 521 | "hfuzz-input", run.global->io.workDir))) { 522 | LOG_F("Couldn't create an input file of size: %zu", hfuzz->mutate.maxFileSz); 523 | } 524 | } 525 | defer { 526 | if (run.dynamicFileFd != -1) { 527 | close(run.dynamicFileFd); 528 | } 529 | }; 530 | 531 | if (!arch_archThreadInit(&run)) { 532 | LOG_F("Could not initialize the thread"); 533 | } 534 | 535 | for (;;) { 536 | /* Check if dry run mode with verifier enabled */ 537 | if (run.global->mutate.mutationsPerRun == 0U && run.global->cfg.useVerifier && 538 | !hfuzz->socketFuzzer.enabled) { 539 | if (ATOMIC_POST_INC(run.global->cnts.mutationsCnt) >= run.global->io.fileCnt) { 540 | break; 541 | } 542 | } 543 | /* Check for max iterations limit if set */ 544 | else if ((ATOMIC_POST_INC(run.global->cnts.mutationsCnt) >= 545 | run.global->mutate.mutationsMax) && 546 | run.global->mutate.mutationsMax) { 547 | break; 548 | } 549 | 550 | if (hfuzz->socketFuzzer.enabled) { 551 | fuzz_fuzzLoopSocket(&run); 552 | } else { 553 | input_setSize(&run, run.global->mutate.maxFileSz); 554 | fuzz_fuzzLoop(&run); 555 | } 556 | 557 | if (fuzz_isTerminating()) { 558 | break; 559 | } 560 | 561 | if (run.global->cfg.exitUponCrash && ATOMIC_GET(run.global->cnts.crashesCnt) > 0) { 562 | LOG_I("Seen a crash. Terminating all fuzzing threads"); 563 | fuzz_setTerminating(); 564 | break; 565 | } 566 | } 567 | 568 | if (run.pid) { 569 | kill(run.pid, SIGKILL); 570 | } 571 | 572 | /* Report SpecFuzz coverage */ 573 | if (fuzzNo == 0) { 574 | LOG_I("Coverage:"); 575 | map_entry_t *coverage_map = run.global->feedback.feedbackMap->cmpMapPc; 576 | for (int i = 0; i < (int) COVERAGE_MAP_HASHMAP_SIZE ; i++) { 577 | map_entry_t entry = coverage_map[i]; 578 | if (entry.count == 0) 579 | continue; 580 | uint64_t address = (entry.tag << COVERAGE_INDEX_WIDTH) + i; 581 | LOG_I("[SF], 0x%lx: %d", address, entry.count); 582 | } 583 | map_entry_t *coverage_map_conflicts = &coverage_map[COVERAGE_MAP_HASHMAP_SIZE]; 584 | for (int i = 0; i < (int) COVERAGE_MAP_CONFLICTS_SIZE ; i++) { 585 | map_entry_t entry = coverage_map_conflicts[i]; 586 | if (entry.count == 0) 587 | continue; 588 | uint64_t address = (entry.tag << COVERAGE_INDEX_WIDTH) + i; 589 | LOG_I("[SF], 0x%lx: %d", address, entry.count); 590 | } 591 | //hash_map_usage(run.global->feedback.feedbackMap); 592 | } 593 | LOG_I("Terminating thread no. #%" PRId32 ", left: %zu", fuzzNo, 594 | hfuzz->threads.threadsMax - ATOMIC_GET(run.global->threads.threadsFinished)); 595 | ATOMIC_POST_INC(run.global->threads.threadsFinished); 596 | return NULL; 597 | } 598 | 599 | void fuzz_threadsStart(honggfuzz_t* hfuzz) { 600 | if (!arch_archInit(hfuzz)) { 601 | LOG_F("Couldn't prepare arch for fuzzing"); 602 | } 603 | if (!sanitizers_Init(hfuzz)) { 604 | LOG_F("Couldn't prepare sanitizer options"); 605 | } 606 | 607 | if (hfuzz->socketFuzzer.enabled) { 608 | /* Don't do dry run with socketFuzzer */ 609 | LOG_I("Entering phase - Feedback Driven Mode (SocketFuzzer)"); 610 | hfuzz->feedback.state = _HF_STATE_DYNAMIC_MAIN; 611 | } else if (hfuzz->feedback.dynFileMethod != _HF_DYNFILE_NONE) { 612 | LOG_I("Entering phase 1/3: Dry Run"); 613 | hfuzz->feedback.state = _HF_STATE_DYNAMIC_DRY_RUN; 614 | } else { 615 | LOG_I("Entering phase: Static"); 616 | hfuzz->feedback.state = _HF_STATE_STATIC; 617 | } 618 | 619 | for (size_t i = 0; i < hfuzz->threads.threadsMax; i++) { 620 | if (!subproc_runThread( 621 | hfuzz, &hfuzz->threads.threads[i], fuzz_threadNew, /* joinable= */ true)) { 622 | PLOG_F("Couldn't run a thread #%zu", i); 623 | } 624 | } 625 | } 626 | --------------------------------------------------------------------------------