├── .gitignore ├── .gitmodules ├── README.md ├── env.sh ├── example ├── Makefile ├── buggy.c └── uaf.c ├── install.sh ├── run.py └── runtime ├── Makefile ├── cmp.c └── wrap.c /.gitignore: -------------------------------------------------------------------------------- 1 | llvm-default/* 2 | llvm-floatzone/* 3 | *.so 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "xed"] 2 | path = xed 3 | url = https://github.com/intelxed/xed.git 4 | [submodule "floatzone-llvm-project"] 5 | path = floatzone-llvm-project 6 | url = https://github.com/vusec/floatzone-llvm-project.git 7 | [submodule "mbuild"] 8 | path = mbuild 9 | url = https://github.com/intelxed/mbuild.git 10 | [submodule "instrumentation-infra"] 11 | path = instrumentation-infra 12 | url = https://github.com/vusec/instrumentation-infra.git 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FloatZone 2 | 3 | 4 | **FloatZone**: a compiler-based sanitizer to detect spatial and temporal memory errors in C/C++ programs 5 | using lightweight checks that leverage the Floating Point Unit (FPU). 6 | 7 | **Paper:** [https://www.vusec.net/projects/floatzone/](https://www.vusec.net/projects/floatzone/) 8 | 9 | ## Dependencies 10 | 11 | (Tested on system running Ubuntu 22.04, glibc 2.35, and a stock v5.15 Linux kernel) 12 | 13 | ``` 14 | sudo apt install ninja-build cmake gcc-9 autoconf2.69 bison build-essential flex texinfo libtool zlib1g-dev 15 | pip3 install psutil terminaltables 16 | ``` 17 | 18 | ## How to install 19 | 20 | 21 | ``` 22 | git clone https://github.com/vusec/floatzone.git --recurse-submodules 23 | ``` 24 | 25 | Edit `env.sh` and update `FLOATZONE_TOP` with the full path where you cloned this repository. 26 | 27 | (OPTIONAL) To run SPEC benchmarks, update also the variable `FLOATZONE_SPEC06` with the full path of your SPEC installation. 28 | 29 | Then, load the environment in your current shell: 30 | ``` 31 | source env.sh 32 | ``` 33 | 34 | **IMPORTANT**: always ensure to load `env.sh` in your terminal before doing any of the following steps 35 | 36 | Finally, let's install everything. This will take a while since LLVM is quite a big project: 37 | 38 | ``` 39 | ./install.sh 40 | ``` 41 | 42 | ## How to test FloatZone is working 43 | 44 | Compile the example `buggy.c` and `uaf.c` 45 | 46 | ``` 47 | cd examples 48 | make clean 49 | make 50 | make uaf 51 | ``` 52 | 53 | This is the expected output: 54 | 55 | ``` 56 | ./buggy_floatzone_run_base 15 57 | A 58 | ``` 59 | 60 | ``` 61 | ./buggy_floatzone_run_base 16 62 | 63 | !!!! [FLOATZONE] Fault addr = 0x7fffffffdc10 !!!! 64 | 0x7fffffffdbd0: e0 11 40 00 65 | 0x7fffffffdbd4: 00 00 00 00 66 | 0x7fffffffdbd8: 00 dc ff ff 67 | 0x7fffffffdbdc: ff 7f 00 00 68 | 0x7fffffffdbe0: 40 d0 ff f7 69 | 0x7fffffffdbe4: ff 7f 00 00 70 | 0x7fffffffdbe8: 2e 12 40 00 71 | 0x7fffffffdbec: 00 00 00 00 72 | 0x7fffffffdbf0: 89 8b 8b 8b 73 | 0x7fffffffdbf4: 8b 8b 8b 8b 74 | 0x7fffffffdbf8: 8b 8b 8b 8b 75 | 0x7fffffffdbfc: 8b 8b 8b 8b 76 | 0x7fffffffdc00: 41 41 41 41 77 | 0x7fffffffdc04: 41 41 41 41 78 | 0x7fffffffdc08: 41 41 41 41 79 | 0x7fffffffdc0c: 41 41 41 41 80 | 0x7fffffffdc10: 89 8b 8b 8b <----- 81 | 0x7fffffffdc14: 8b 8b 8b 8b 82 | 0x7fffffffdc18: 8b 8b 8b 8b 83 | 0x7fffffffdc1c: 8b 8b 8b 8b 84 | 0x7fffffffdc20: 00 00 00 00 85 | 0x7fffffffdc24: 00 00 00 00 86 | 0x7fffffffdc28: 00 00 00 00 87 | 0x7fffffffdc2c: 00 00 00 00 88 | 0x7fffffffdc30: a0 3d 40 00 89 | 0x7fffffffdc34: 00 00 00 00 90 | 0x7fffffffdc38: 90 7d 74 f1 91 | 0x7fffffffdc3c: ff 7f 00 00 92 | 0x7fffffffdc40: 00 00 00 00 93 | 0x7fffffffdc44: 00 00 00 00 94 | 0x7fffffffdc48: e0 11 40 00 95 | 0x7fffffffdc4c: 00 00 00 00 96 | 97 | Fault RIP = 0x40123d 98 | Backtrace: 99 | - [0] ./buggy_floatzone_run_base() [0x40123d] 100 | - [1] /lib/x86_64-linux-gnu/libc.so.6(+0x29d90) [0x7ffff1747d90] 101 | - [2] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x7ffff1747e40] 102 | - [3] /home/sec23_ae/floatzone/runtime/libwrap.so(__libc_start_main+0x1fa) [0x7ffff19502fa] 103 | - [4] ./buggy_floatzone_run_base() [0x401095] 104 | ``` 105 | 106 | ## Benchmarks 107 | 108 | ### CPU SPEC 109 | 110 | To run SPEC06 benchmarks simply run the following command: 111 | 112 | ``` 113 | python3 run.py run spec2006 default_O2 asan_O2 floatzone_O2 --build --parallel=proc --parallelmax=1 114 | ``` 115 | 116 | This will run baseline, ASan and FloatZone all together. 117 | 118 | To compute the respective time and memory overhead do: (substitute `run.2023-06-20.15-37-32/` with your result folder) 119 | 120 | ``` 121 | python3 run.py report spec2006 results/run.2023-06-20.15-37-32/ --aggregate geomean --field runtime:median maxrss:median 122 | ``` 123 | 124 | This is an expected output: 125 | 126 | ``` 127 | + spec2006 aggregated data ----------------------------------------------+ 128 | | asan_O2 default_O2 floatzone_O2 | 129 | | runtime maxrss runtime maxrss runtime maxrss | 130 | |benchmark median median median median median median | 131 | +------------------------------------------------------------------------+ 132 | |400.perlbench 427 5517864 107 1235732 154 2893056 | 133 | |401.bzip2 301 3581624 196 3448396 254 3550160 | 134 | |403.gcc 237 13467288 83.9 4259380 163 8043360 | 135 | |429.mcf 145 1935800 110 1718588 118 1718428 | 136 | |433.milc 156 982764 130 697832 144 1020312 | 137 | |444.namd 188 61280 121 49808 142 49892 | 138 | |445.gobmk 285 1368400 182 152456 217 1062460 | 139 | |447.dealII 214 1764156 99.8 816224 132 1664564 | 140 | |450.soplex 120 1271488 76.5 564236 93.5 1231012 | 141 | |453.povray 101 236780 44.5 7408 73.6 217624 | 142 | |456.hmmer 236 814480 104 34004 164 607576 | 143 | |458.sjeng 342 184764 196 180744 226 181428 | 144 | |462.libquantum 135 366912 118 100732 123 334072 | 145 | |464.h264ref 368 726084 156 117508 354 659368 | 146 | |470.lbm 96.0 476048 78.5 421032 79.9 421040 | 147 | |471.omnetpp 230 776404 121 175944 190 647448 | 148 | |473.astar 224 1489504 157 473900 184 1118144 | 149 | |482.sphinx3 282 413280 174 45752 229 446512 | 150 | |483.xalancbmk 159 1472808 61.9 430504 129 831000 | 151 | +------------------------------------------------------------------------+ 152 | |geomean 205 939084 114 278538 155 782220 | 153 | +------------------------------------------------------------------------+ 154 | ``` 155 | 156 | We can see that the ASan time overhead is `205/114=79%` while FloatZone is `155/114=36%` 157 | 158 | ### Juliet 159 | 160 | 1. Edit `runtime/wrap.c` and set the `CATCH_SEGFAULT` macro to 1 to enable segmentation faults to also be caught (as ASan does). 161 | 2. Enable **FloatzoneExt** by editing `env.sh` such that `FLOATZONE_MODE="floatzone double_sided just_size"`. 162 | 3. Make sure `env.sh` is loaded via `source env.sh` 163 | 4. Check `echo $FLOATZONE_MODE` is equal to `floatzone double_sided just_size`. 164 | 5. Run `./install.sh` to update the shared library. 165 | 6. Run the following commands: 166 | 167 | ``` 168 | python3 run.py run juliet floatzone_O0 --build --cwe 121 169 | python3 run.py run juliet floatzone_O0 --build --cwe 122 170 | python3 run.py run juliet floatzone_O0 --build --cwe 124 171 | python3 run.py run juliet floatzone_O0 --build --cwe 126 172 | python3 run.py run juliet floatzone_O0 --build --cwe 127 173 | python3 run.py run juliet floatzone_O0 --build --cwe 415 174 | python3 run.py run juliet floatzone_O0 --build --cwe 416 175 | ``` 176 | 177 | Note 1: Some Juliet test cases are random (their test case contains the word 'rand') and you may need to re-run multiple times for it to be caught. 178 | 179 | Note 2: Juliet needs to compile with O0, so that's why we use `floatzone_O0` 180 | 181 | 182 | ## Troubleshooting 183 | 184 | * Ensure `source env.sh` was executed in your terminal (with correct paths) 185 | * Ensure evyerhting is up-to-date via `./install.sh` 186 | * For FloatZone binaries, `run_base` must be present in the binary file name. 187 | * Edit `wrap.c` depending on your needs (e.g. `SURVIVE_EXCEPTIONS=1`) 188 | -------------------------------------------------------------------------------- /env.sh: -------------------------------------------------------------------------------- 1 | #Must call this with `source env.sh` 2 | 3 | #FLOATZONE_MODE is used at compile time to configure the detection 4 | #capabilities: 5 | # - floatzone : enable FloatZone 6 | # - double_sided : include underflow redzone 7 | # - just_size : enable FloatZoneExt 8 | 9 | #--- FloatZone --- 10 | export FLOATZONE_MODE="floatzone double_sided" 11 | #--- FloatZoneExt --- 12 | #export FLOATZONE_MODE="floatzone double_sided just_size" 13 | 14 | #CHANGME depending on where you cloned the floatzone repo! 15 | export FLOATZONE_TOP=/home/sec23_ae/floatzone 16 | 17 | #CHANGME depending on where you installed SPEC 18 | export FLOATZONE_SPEC06=/home/sec23_ae/spec06 19 | 20 | export FLOATZONE_LLVM=$FLOATZONE_TOP/floatzone-llvm-project/llvm/ 21 | 22 | export FLOATZONE_LLVM_BUILD=$FLOATZONE_TOP/llvm-floatzone/ 23 | export FLOATZONE_C=$FLOATZONE_LLVM_BUILD/bin/clang 24 | export FLOATZONE_CXX=$FLOATZONE_LLVM_BUILD/bin/clang++ 25 | 26 | export DEFAULT_LLVM_BUILD=$FLOATZONE_TOP/llvm-default/ 27 | export DEFAULT_C=$DEFAULT_LLVM_BUILD/bin/clang 28 | export DEFAULT_CXX=$DEFAULT_LLVM_BUILD/bin/clang++ 29 | 30 | export FLOATZONE_XED=$FLOATZONE_TOP/xed/ 31 | export FLOATZONE_XED_MBUILD=$FLOATZONE_TOP/mbuild/ 32 | export FLOATZONE_XED_LIB=$FLOATZONE_XED/obj/libxed.a 33 | export FLOATZONE_XED_LIB_SO=$FLOATZONE_XED/obj/libxed.so 34 | export FLOATZONE_XED_INC=$FLOATZONE_XED/include/public/xed/ 35 | export FLOATZONE_XED_INC_OBJ=$FLOATZONE_XED/obj/ 36 | 37 | export WRAP_DIR=$FLOATZONE_TOP/runtime/ 38 | export FLOATZONE_LIBWRAP_SO=$WRAP_DIR/libwrap.so 39 | 40 | 41 | export FLOATZONE_INFRA=$FLOATZONE_TOP/instrumentation-infra/ 42 | 43 | #Suggested for better benchmarking 44 | #echo "performance" | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor 45 | #echo 0 | sudo tee /proc/sys/kernel/randomize_va_space 46 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -O2 -g -Wl,-z,now 2 | 3 | 4 | all: buggy buggy_asan buggy_floatzone 5 | 6 | buggy: 7 | ${DEFAULT_C} buggy.c -o buggy ${CFLAGS} 8 | 9 | buggy_asan: 10 | ${DEFAULT_C} buggy.c -o buggy_asan ${CFLAGS} -fsanitize=address 11 | 12 | buggy_floatzone: 13 | ${FLOATZONE_C} buggy.c -o buggy_floatzone_run_base ${CFLAGS} 14 | 15 | uaf: 16 | ${DEFAULT_C} uaf.c -o uaf ${CFLAGS} 17 | ${DEFAULT_C} uaf.c -o uaf_asan ${CFLAGS} -fsanitize=address 18 | ${FLOATZONE_C} uaf.c -o uaf_floatzone_run_base ${CFLAGS} 19 | 20 | clean: 21 | rm -f buggy buggy_asan buggy_floatzone_run_base uaf uaf_asan uaf_floatzone_run_base 22 | -------------------------------------------------------------------------------- /example/buggy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void fill_buffer(char *buf){ 6 | memset(buf, 0x41, 16); 7 | } 8 | 9 | char buggy(unsigned int idx) { 10 | char buf[16]; 11 | fill_buffer(buf); 12 | return buf[idx]; 13 | } 14 | 15 | int main(int argc, char **argv) { 16 | printf("%c\n", buggy(atoi(argv[1]))); 17 | } 18 | -------------------------------------------------------------------------------- /example/uaf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void fill_buffer(char *buf){ 6 | memset(buf, 0x41, 16); 7 | } 8 | 9 | char buggy(unsigned int idx) { 10 | char* buf = malloc(16); 11 | fill_buffer(buf); 12 | free(buf); 13 | return buf[idx]; 14 | } 15 | 16 | int main(int argc, char **argv) { 17 | printf("%c\n", buggy(atoi(argv[1]))); 18 | } 19 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | BAK_DIR=$(pwd) 3 | BAK_MODE=$FLOATZONE_MODE 4 | set -e 5 | unset FLOATZONE_MODE 6 | 7 | #Check we loaded env.sh 8 | if [ -z $FLOATZONE_C ] 9 | then 10 | echo $FLOATZONE_C 11 | echo "Env variables not found!" 12 | exit 1 13 | fi 14 | 15 | #Checking if LLVM default is present 16 | if [[ ! -f $DEFAULT_C ]] 17 | then 18 | mkdir -p $DEFAULT_LLVM_BUILD 19 | cd $DEFAULT_LLVM_BUILD 20 | cmake -DLLVM_ENABLE_PROJECTS="clang;compiler-rt;openmp" -DCMAKE_CXX_FLAGS=-DDEFAULTCLANG -DCMAKE_BUILD_TYPE=Release -GNinja -DLLVM_PARALLEL_LINK_JOBS=1 -DLLVM_TARGETS_TO_BUILD="X86" -DCLANG_ENABLE_STATIC_ANALYZER=OFF -DCLANG_ENABLE_ARCMT=OFF $FLOATZONE_LLVM 21 | ninja 22 | 23 | cp $DEFAULT_LLVM_BUILD/projects/openmp/runtime/src/omp.h $DEFAULT_LLVM_BUILD/lib/clang/14.0.6/include 24 | fi 25 | 26 | #Checking Floatzone LLVM is present and compiled 27 | if [[ ! -f $FLOATZONE_C ]] 28 | then 29 | #Doing the cmake of LLVM 30 | mkdir -p $FLOATZONE_LLVM_BUILD 31 | cd $FLOATZONE_LLVM_BUILD 32 | cmake -DLLVM_ENABLE_PROJECTS="clang;compiler-rt;openmp" -DCMAKE_BUILD_TYPE=Release -GNinja -DLLVM_PARALLEL_LINK_JOBS=1 -DLLVM_TARGETS_TO_BUILD="X86" -DCLANG_ENABLE_STATIC_ANALYZER=OFF -DCLANG_ENABLE_ARCMT=OFF $FLOATZONE_LLVM 33 | ninja 34 | 35 | cp $FLOATZONE_LLVM_BUILD/projects/openmp/runtime/src/omp.h $FLOATZONE_LLVM_BUILD/lib/clang/14.0.6/include 36 | fi 37 | 38 | #Always compile LLVM 39 | cd $FLOATZONE_LLVM_BUILD 40 | ninja 41 | 42 | # If after compilation we still do not have clang, abort 43 | if [[ ! -f $FLOATZONE_C ]] 44 | then 45 | echo "Missing clang, ABORT" 46 | exit -1 47 | fi 48 | 49 | # Check XED 50 | if [[ ! -f $FLOATZONE_XED_LIB_SO ]] 51 | then 52 | echo "Missing libxed.so, compiling it" 53 | cd $FLOATZONE_XED 54 | ./mfile.py --shared #--extra-flags=-fPIC 55 | 56 | if [[ ! -f $FLOATZONE_XED_LIB_SO ]] 57 | then 58 | echo "Missing libxed.so, ABORT" 59 | exit -1 60 | fi 61 | fi 62 | 63 | #Always compile wrap.so 64 | cd $WRAP_DIR 65 | make 66 | if [[ ! -f $FLOATZONE_LIBWRAP_SO ]] 67 | then 68 | echo "Missing libwrap.so, ABORT" 69 | exit -1 70 | fi 71 | 72 | #Check if SPEC2006 is installed 73 | #if [[ ! -d $FLOATZONE_SPEC06 ]] 74 | #then 75 | # echo "Missing spec 2006 installation" 76 | # mkdir -p /tmp/spec06 77 | # sudo mount -o loop $FLOATZONE_SPEC06_ISO /tmp/spec06 78 | # cd /tmp/spec06 79 | # ./install.sh -f -d $FLOATZONE_SPEC06 80 | # sudo umount /tmp/spec06 81 | #fi 82 | # 83 | ##Check if SPEC2017 is installed 84 | #if [[ ! -d $FLOATZONE_SPEC17 ]] 85 | #then 86 | # echo "Missing spec 2017 installation" 87 | # mkdir -p /tmp/spec17 88 | # sudo mount -o loop $FLOATZONE_SPEC17_ISO /tmp/spec17 89 | # cd /tmp/spec17 90 | # ./install.sh -f -d $FLOATZONE_SPEC17 91 | # sudo umount /tmp/spec17 92 | #fi 93 | # 94 | cd $BAK_DIR 95 | export FLOATZONE_MODE=$BAK_MODE 96 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # PYTHON_ARGCOMPLETE_OK 3 | 4 | #import stuff 5 | import sys 6 | import os.path 7 | sys.path.insert(0, os.getenv("FLOATZONE_INFRA")) 8 | print(os.getenv("FLOATZONE_INFRA")) 9 | from infra import Setup, Instance 10 | from infra.targets import SPEC2006 11 | from infra.targets import SPEC2017 12 | from infra.targets import Juliet 13 | script_dir = os.path.dirname(os.path.realpath(__file__)) 14 | setup = Setup(__file__) 15 | 16 | NUM_OPENMP_THREADS = 16 # also used for pinning cores 17 | 18 | default_clang = os.getenv("DEFAULT_C") 19 | floatzone_clang = os.getenv("FLOATZONE_C") 20 | asanmm_14_clang = os.getenv("ASANMM_14_C") 21 | 22 | class ClangC(Instance): 23 | def __init__(self, name, cc, opt_level): 24 | self.name = name + "_" + str(opt_level) 25 | self.cc = cc 26 | self.cflags = ["-" + opt_level, "-Wno-int-conversion"] 27 | 28 | def configure(self, ctx): 29 | super().configure(ctx) 30 | ctx.cc = self.cc 31 | ctx.cxx = self.cc + '++' 32 | ctx.cflags += self.cflags 33 | ctx.cxxflags += self.cflags 34 | 35 | #Avoid lazy binding, this is to avoid dl_runtime_resolve that push 36 | #on the stack the xmm register and can lead to false positives 37 | ctx.ldflags += ['-Wl,-z,now'] 38 | 39 | #openmp for spec17 40 | ctx.cflags += ['-DSPEC_OPENMP', '-fopenmp', '-Wno-deprecated-non-prototype'] 41 | ctx.ldflags += ['-fopenmp'] 42 | ctx.openmp_cores = NUM_OPENMP_THREADS 43 | 44 | class ClangCASan(Instance): 45 | def __init__(self, name, cc, opt_level): 46 | self.name = name + "_" + str(opt_level) 47 | self.cc = cc 48 | self.cflags = ["-" + opt_level, "-Wno-int-conversion"] 49 | 50 | def configure(self, ctx): 51 | super().configure(ctx) 52 | ctx.cc = self.cc 53 | ctx.cxx = self.cc + '++' 54 | ctx.cflags += self.cflags 55 | ctx.cxxflags += self.cflags 56 | ctx.cflags += ['-fsanitize=address', '-fno-sanitize-address-use-after-scope', '-fsanitize-address-use-after-return=never'] 57 | ctx.cxxflags += ['-fsanitize=address', '-fno-sanitize-address-use-after-scope', '-fsanitize-address-use-after-return=never'] 58 | ctx.ldflags += ['-fsanitize=address', '-fno-sanitize-address-use-after-scope', '-fsanitize-address-use-after-return=never'] 59 | 60 | #openmp for spec17 61 | ctx.cflags += ['-DSPEC_OPENMP', '-fopenmp', '-Wno-deprecated-non-prototype'] 62 | ctx.ldflags += ['-fopenmp'] 63 | ctx.openmp_cores = NUM_OPENMP_THREADS 64 | 65 | class DefaultClang(ClangC): 66 | def __init__(self, name, opt_level): 67 | super().__init__(name, default_clang, opt_level) 68 | 69 | class DefaultClangASan(ClangCASan): 70 | def __init__(self, name, opt_level): 71 | super().__init__(name, default_clang, opt_level) 72 | def prepare_run(self, ctx): 73 | ctx.runenv.ASAN_OPTIONS = 'detect_leaks=0:detect_stack_use_after_return=0:detect_stack_use_after_scope=0:alloc_dealloc_mismatch=0:detect_odr_violation=0' 74 | 75 | class FloatZoneClang(ClangC): 76 | def __init__(self, name, opt_level): 77 | super().__init__(name, floatzone_clang, opt_level) 78 | 79 | setup.add_instance(DefaultClang("default", "O2")) 80 | setup.add_instance(DefaultClang("default", "O0")) 81 | setup.add_instance(DefaultClangASan("asan", "O0")) 82 | setup.add_instance(DefaultClangASan("asan", "O2")) 83 | setup.add_instance(FloatZoneClang("floatzone", "O2")) 84 | setup.add_instance(FloatZoneClang("floatzone", "O0")) 85 | 86 | setup.add_target(SPEC2006( 87 | source = os.getenv("FLOATZONE_SPEC06"), 88 | source_type = 'installed', 89 | patches = ['dealII-stddef', 'asan', 'omnetpp-invalid-ptrcheck', 'libcxx'] 90 | )) 91 | 92 | #setup.add_target(SPEC2017( 93 | # source = os.getenv("FLOATZONE_SPEC17"), 94 | # source_type = 'installed', 95 | # patches = ['asan'], 96 | # force_cpu = -(NUM_OPENMP_THREADS-1) # -15 means use cores 0-15 for openMP if the binary supports it, otherwise pin to core 0 97 | #)) 98 | 99 | setup.add_target(Juliet(1)) 100 | 101 | if __name__ == '__main__': 102 | setup.main() 103 | -------------------------------------------------------------------------------- /runtime/Makefile: -------------------------------------------------------------------------------- 1 | all: libwrap.so libcmp.so 2 | 3 | libwrap.so: wrap.c 4 | ${DEFAULT_C} -fPIC -shared -g -O2 -o libwrap.so wrap.c -lm -ldl -I${FLOATZONE_XED_INC} -I${FLOATZONE_XED_INC_OBJ} -D LIBXED_SO='"${FLOATZONE_XED_LIB_SO}"' -Wl,-z,now 5 | 6 | libcmp.so: cmp.c 7 | ${DEFAULT_C} -fPIC -shared -g -O2 -o libcmp.so cmp.c -lm -ldl 8 | 9 | clean: 10 | rm -f *.so 11 | -------------------------------------------------------------------------------- /runtime/cmp.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE // for non-POSIX RTLD_NEXT 2 | #include 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 | #include 17 | #include 18 | 19 | #define TARGET "run_base" // use "run_base" for SPEC 20 | #define JULIET "CWE" // use "CWE" for Juliet 21 | 22 | #define REDZONE_SIZE 16 // bytes 23 | #define REDZONE_JUMP (REDZONE_SIZE/sizeof(float)) 24 | 25 | #define FAULT_ERROR_CODE 1 26 | 27 | #define FLOAT_MODE 1 28 | #define CMP_1_LOOP 0 29 | #define CMP_4_LOOP 0 30 | #define CMP_8_LOOP 0 31 | 32 | void * g_null = NULL; 33 | static uint8_t process = 0; 34 | 35 | //0x0b8b8b8a 36 | #define FLOAT_MAGIC_ADD ((float)(5.375081e-32)) 37 | 38 | static inline __attribute__((always_inline)) void fpadd_magic(void *mem) { 39 | asm volatile ( 40 | "vaddss %0, %1, %%xmm15" 41 | : 42 | :"p"(mem), "v"(FLOAT_MAGIC_ADD) 43 | :"xmm15"); 44 | } 45 | 46 | static inline __attribute__((always_inline)) void check_poison(void* src, size_t size) 47 | { 48 | size_t src_b = (size_t)src; 49 | 50 | //Always check leftmost byte (first iteration) and 51 | //then check every REDZONE_SIZE 52 | //TODO verify properly that we need REDZONE_SIZE/2 steps 53 | for(size_t ptr=src_b; ptr 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 | #include 46 | #include "xed-interface.h" 47 | 48 | #define TARGET "run_base" // use "run_base" for SPEC 49 | #define JULIET "CWE" // use "CWE" for Juliet 50 | 51 | #define REDZONE_SIZE 16 // bytes 52 | #define REDZONE_JUMP (REDZONE_SIZE/sizeof(float)) 53 | 54 | #define FAULT_ERROR_CODE 1 55 | 56 | #define FLOAT_MAGIC_POISON_PRE (0x8b8b8b89U) 57 | #define FLOAT_MAGIC_POISON_PRE_BYTE (0x89U) 58 | #define FLOAT_MAGIC_POISON (0x8b8b8b8bU) 59 | #define FLOAT_MAGIC_POISON_BYTE (0x8bU) 60 | //0x0b8b8b8a 61 | #define FLOAT_MAGIC_ADD ((float)(5.375081e-32)) 62 | 63 | // MODE: count exceptions handled 64 | #define COUNT_EXCEPTIONS 0 65 | // MODE: enable float underflow exceptions 66 | #define ENABLE_EXCEPTIONS 1 67 | // MODE: allow surviving exceptions (recover) 68 | #define SURVIVE_EXCEPTIONS 0 69 | // MODE: heap quarantine 70 | #define ENABLE_QUARANTINE 1 71 | // MODE: catch segmentation faults (Juliet) 72 | #define CATCH_SEGFAULT 0 73 | // MODE: AFL++ requires abort() for bugs 74 | #define FUZZ_MODE 0 75 | #define QUARANTINE_SIZE_BYTES 268435456 // 256 MB 76 | // quarantine max bytes / min. size of alloc == upper bound 77 | #define MIN_ALLOC_SIZE 40 78 | 79 | static uint8_t process = 0; 80 | 81 | struct redzone { 82 | char vals[16]; 83 | } redzone_s = {{ 0x89, 0x8b, 0x8b, 0x8b, 84 | 0x8b, 0x8b, 0x8b, 0x8b, 85 | 0x8b, 0x8b, 0x8b, 0x8b, 86 | 0x8b, 0x8b, 0x8b, 0x8b}}; 87 | 88 | 89 | #if COUNT_EXCEPTIONS == 1 90 | static uint32_t except_cnt_vaddss_skip = 0; // FP from vaddss but no redzone 91 | static uint32_t except_cnt_vaddss_rz = 0; // FP from vaddss and looks like redzone 92 | static uint32_t except_cnt_underflow = 0; // generic underflow 93 | extern const char *__progname; 94 | #endif 95 | 96 | // stack redzones (exceptions/longjmps) 97 | uintptr_t g_stored_sp = 0; 98 | 99 | // glibc symbols 100 | void* __libc_malloc(size_t size); 101 | void* __libc_calloc(size_t nmemb, size_t size); 102 | void* __libc_realloc(void* ptr, size_t size); 103 | void* __libc_free(void* ptr); 104 | 105 | 106 | // quarantine 107 | #if ENABLE_QUARANTINE == 1 108 | typedef struct Ring Ring; 109 | struct Ring { 110 | void* ptr; 111 | size_t size; 112 | }; 113 | 114 | #define MAX_RING_ELEMS (QUARANTINE_SIZE_BYTES/MIN_ALLOC_SIZE) 115 | Ring ring[MAX_RING_ELEMS]; 116 | // 5000 elements -> 256 MB allocated memory -> start clearing 117 | size_t front = 0; 118 | size_t rear = 0; 119 | uint64_t quarantine_size = 0; // in bytes 120 | pthread_mutex_t ring_lock; 121 | 122 | void append_to_list(void *ptr, size_t size) 123 | { 124 | // enqueue 125 | pthread_mutex_lock(&ring_lock); 126 | ring[rear].ptr = ptr; 127 | ring[rear].size = size; 128 | rear = rear + 1; 129 | if(rear == MAX_RING_ELEMS) rear = 0; 130 | // apply the poison (the first REDZONE_SIZE bytes (underflow) can be skipped) 131 | // the last 15 bytes are also guaranteed to be 0x8b 132 | // update quarantine size 133 | quarantine_size += size; 134 | pthread_mutex_unlock(&ring_lock); 135 | 136 | memset(((uint8_t*)ptr)+REDZONE_SIZE, FLOAT_MAGIC_POISON_BYTE, size-REDZONE_SIZE-(REDZONE_SIZE-1)); 137 | } 138 | 139 | void pop_last_from_list() 140 | { 141 | void *ptr_to_clean; 142 | size_t size_to_clean; 143 | 144 | pthread_mutex_lock(&ring_lock); 145 | // dequeue 146 | if(front != rear){ 147 | ptr_to_clean = ring[front].ptr; 148 | size_to_clean = ring[front].size; 149 | quarantine_size -= ring[front].size; 150 | 151 | front = (front + 1); 152 | if(front == MAX_RING_ELEMS) front = 0; 153 | 154 | pthread_mutex_unlock(&ring_lock); 155 | 156 | memset(ptr_to_clean, 0, size_to_clean); 157 | __libc_free(ptr_to_clean); 158 | } 159 | else{ 160 | // empty: set to zero 161 | quarantine_size = 0; 162 | pthread_mutex_unlock(&ring_lock); 163 | } 164 | } 165 | 166 | void add_to_quarantine(void* ptr, size_t size) 167 | { 168 | append_to_list(ptr, size); 169 | 170 | //TODO: lock to read quarantine_size? 171 | while(quarantine_size > QUARANTINE_SIZE_BYTES){ 172 | pop_last_from_list(); 173 | } 174 | } 175 | #endif 176 | 177 | //Override signal handling function to avoid that our SIGFPE handler get replaced 178 | void handler(int sig, siginfo_t* si, void* vcontext); // declare 179 | typedef sighandler_t (*proto_signal)(int signum, sighandler_t handler); 180 | proto_signal __signal; 181 | typedef int (*proto_sigaction)(int signum, const struct sigaction *act, struct sigaction *oldact); 182 | proto_sigaction ___sigaction; 183 | typedef sighandler_t (*proto_sysv_signal)(int signum, sighandler_t handler); 184 | proto_sysv_signal ___sysv_signal; 185 | 186 | sighandler_t signal(int signum, sighandler_t hndlr) { 187 | if(process){ 188 | if(signum == SIGFPE){ 189 | // return without registering 190 | return 0; 191 | } 192 | } 193 | return __signal(signum, hndlr); 194 | } 195 | 196 | // 600.perlbench calls __sysv_signal with signum==SIGFPE (depending on glibc) 197 | sighandler_t __sysv_signal(int signum, sighandler_t hndlr) { 198 | if(process){ 199 | if(signum == SIGFPE){ 200 | // return without registering 201 | return 0; 202 | } 203 | } 204 | return ___sysv_signal(signum, hndlr); 205 | } 206 | 207 | int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) 208 | { 209 | if(process){ 210 | if(signum == SIGFPE){ 211 | if(act != NULL && act->sa_sigaction != &handler){ 212 | // return without registering 213 | return 0; 214 | } 215 | } 216 | } 217 | return ___sigaction(signum, act, oldact); 218 | } 219 | 220 | 221 | // longjmp override 222 | typedef void (*proto_longjmp)(jmp_buf env, int val); 223 | typedef void (*proto_siglongjmp)(sigjmp_buf env, int val); 224 | proto_longjmp __longjmp; 225 | proto_siglongjmp __siglongjmp; 226 | 227 | void __attribute__((noreturn)) longjmp(jmp_buf env, int val) 228 | { 229 | if(process){ 230 | // store sp in g_stored_sp before jmp 231 | asm volatile("movq %%rsp, %0\n" : "=r"(g_stored_sp)); 232 | } 233 | __longjmp(env, val); 234 | exit(-1); 235 | } 236 | 237 | void __attribute__((noreturn)) siglongjmp(sigjmp_buf env, int val) 238 | { 239 | if(process){ 240 | // store sp in g_stored_sp before jmp 241 | asm volatile("movq %%rsp, %0\n" : "=r"(g_stored_sp)); 242 | } 243 | __siglongjmp(env, val); 244 | exit(-1); 245 | } 246 | 247 | // exceptions override 248 | typedef void (*proto_cxa_throw)(void *, void *, void (*) (void *)); 249 | proto_cxa_throw __og_cxa_throw; 250 | 251 | void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *)) 252 | { 253 | if(process){ 254 | // store sp in g_stored_sp before throw exception 255 | asm volatile("movq %%rsp, %0\n" : "=r"(g_stored_sp)); 256 | } 257 | __og_cxa_throw(thrown_exception, pvtinfo, dest); 258 | } 259 | 260 | // current_sp = sp before call 261 | // we do sp-8 to make sure the return address of clear_stack_on_jump remains intact 262 | void __attribute__ ((noinline, disable_sanitizer_instrumentation)) clear_stack_on_jump(unsigned long current_sp) 263 | { 264 | if(g_stored_sp == 0) return; // dont clear if old sp was never set yet 265 | memset((void*)g_stored_sp, 0, current_sp-g_stored_sp-8); 266 | } 267 | 268 | static inline __attribute__((always_inline)) void fpadd_magic(void *mem) { 269 | asm volatile ( 270 | "vaddss %0, %1, %%xmm15" 271 | : 272 | :"p"(mem), "v"(FLOAT_MAGIC_ADD) 273 | :"xmm15"); 274 | } 275 | 276 | static inline __attribute__((always_inline)) void apply_poison(void* ptr, size_t size) 277 | { 278 | void* poison = (void*) (((uint8_t *)ptr) + size); 279 | *((struct redzone*)poison) = redzone_s; 280 | } 281 | 282 | // FloatZone double-sided redzones on heap 283 | static inline __attribute__((always_inline)) void apply_poison_underflow(void* ptr) 284 | { 285 | *((struct redzone*)ptr) = redzone_s; 286 | } 287 | 288 | static inline __attribute__((always_inline)) void apply_poison_overflow_delta(void* ptr, size_t offset, size_t delta) 289 | { 290 | void* poison = (void*) (((uint8_t *)ptr) + offset); 291 | *((struct redzone*)poison) = redzone_s; 292 | memset(poison+REDZONE_SIZE, 0x8b, delta); 293 | } 294 | 295 | static inline __attribute__((always_inline)) void remove_poison_scan(void* ptr) 296 | { 297 | // assume ptr is already shifted back to the original start of the obj 298 | size_t sz = malloc_usable_size(ptr); 299 | 300 | // clear underflow redzone 301 | memset(ptr, 0, REDZONE_SIZE); 302 | 303 | // find the start of the overflow redzone 304 | uint8_t* b = ((uint8_t*)ptr) + sz; 305 | size_t i; 306 | for(i = REDZONE_SIZE; i < sz; i++){ 307 | if(*(b-i) != 0x8b){ 308 | break; 309 | } 310 | } 311 | // here *b-i == 0x89. clear overflow redzone 312 | memset(b-i, 0, i); 313 | } 314 | 315 | // check_poison externally visible 316 | void __attribute__ ((noinline)) check_poison_visible(void* src, size_t size) 317 | { 318 | // these calls do not check the size as pre-condition 319 | if(size == 0) return; 320 | 321 | size_t src_b = (size_t)src; 322 | 323 | for(size_t ptr=src_b; ptr rax+rbx*4+1234 751 | Arguments: 752 | - op: input, pointer to start of faulting FP instruction 753 | - op_len: output, pointer to return the length of the opcode 754 | - uc: input, struct containing the regs saved during exception 755 | Return: 756 | - Pointer to fualting address 757 | - NULL in case of error, (op_len is set to 0) 758 | 759 | Note: When I wrote this code only God and I understood what it did, 760 | Now only God knows. 761 | */ 762 | void* get_fault_addr(uint8_t *op, int *op_len, ucontext_t *uc) 763 | { 764 | uint32_t rex_x, rex_r, rex_b, modrm, mod, reg, rm, scale, index, base, sib, pos; 765 | int32_t offset; 766 | uint8_t *ptr; 767 | 768 | //Verify VEX instruction 769 | if (op[0] != 0xc5 && op[0] != 0xc4) goto get_fault_addr_error; 770 | 771 | base = 0; 772 | index = 0; 773 | scale = 0; 774 | offset = 0; 775 | 776 | // vex 2 bytes 777 | if (op[0] == 0xc5) { 778 | if(op[2] != 0x58) goto get_fault_addr_error; 779 | rex_r = 1^((op[1]>>7)&1); 780 | rex_x = 0; 781 | rex_b = 0; 782 | pos = 3; //point to modrm 783 | } 784 | 785 | // rex 3 bytes 786 | if (op[0] == 0xc4) { 787 | if(op[3] != 0x58) goto get_fault_addr_error; 788 | rex_r = 1^((op[1]>>7)&1); 789 | rex_x = 1^((op[1]>>6)&1); 790 | rex_b = 1^((op[1]>>5)&1); 791 | pos = 4; //point to modrm 792 | } 793 | 794 | //mod/rm decode 795 | modrm = op[pos]; 796 | mod = (modrm>>6)&0x3; 797 | reg = (rex_r<<3) | ((modrm>>3)&0x7); 798 | rm = (rex_b<<3) | (modrm&0x7); 799 | base = rm; 800 | pos++; 801 | 802 | //Check for supported mod/rm 803 | if (lut_modrm[mod][rm][0] == -1U) goto get_fault_addr_error; 804 | 805 | //If SIB 806 | if(lut_modrm[mod][rm][1]) { 807 | sib = op[pos]; 808 | scale = scales[(sib>>6) & 0x3]; 809 | index = (rex_x<<3) | ((sib>>3)&0x7); 810 | base = (rex_b<<3) | ((sib>>0)&0x7); 811 | //cursed SIB encoding 812 | if(mod != 0){ 813 | if (index == RSP) index = RNONE; 814 | } else { 815 | if((index == RSP) && (base == RBP || base == R13)) goto get_fault_addr_error; 816 | if (index == RSP) index = RNONE; 817 | if (base == RBP || base == R13) { 818 | base = RNONE; 819 | } 820 | } 821 | pos++; 822 | } 823 | 824 | //Offset 825 | if(lut_modrm[mod][rm][2] == 1) { 826 | offset = (int8_t)op[pos]; 827 | pos++; 828 | } 829 | if(lut_modrm[mod][rm][2] == 4) { 830 | offset = (int32_t)(((op[pos+0]&0xff) << 0) | 831 | ((op[pos+1]&0xff) << 8) | 832 | ((op[pos+2]&0xff) << 16) | 833 | ((op[pos+3]&0xff) << 24)); 834 | pos += 4; 835 | } 836 | 837 | get_fault_addr_success: 838 | ptr = NULL; 839 | *op_len = pos; 840 | if (base != RNONE) ptr += uc->uc_mcontext.gregs[regs_map[base]]; 841 | if (index != RNONE) ptr += uc->uc_mcontext.gregs[regs_map[index]]*scale; 842 | ptr += offset; 843 | return (void *) ptr; 844 | 845 | get_fault_addr_error: 846 | *op_len = 0; 847 | return NULL; 848 | } 849 | 850 | void dump(ucontext_t* uc) { 851 | printf("--------------------\n"); 852 | for(int i=0; i<16; i++) { 853 | for(int j=0; j<4; j++) { 854 | printf("%08x ", uc->uc_mcontext.fpregs->_xmm[i].element[j]); 855 | } 856 | printf("\n"); 857 | } 858 | } 859 | 860 | //push rax 861 | //push rbx 862 | //push rcx 863 | //push rdx 864 | //push rdi 865 | //push rsi 866 | //push rbp 867 | //push r8 868 | //push r9 869 | //push r10 870 | //push r11 871 | //push r12 872 | //push r13 873 | //push r14 874 | //push r15 875 | //movabs rax,0x1111111111111111 876 | //movabs rbx,0x2222222222222222 877 | //movabs rcx,0x3333333333333333 878 | //movabs rdx,0x4444444444444444 879 | //movabs rdi,0x5555555555555555 880 | //movabs rsi,0x6666666666666666 881 | //movabs rbp,0x7777777777777777 882 | //movabs r8,0x8888888888888888 883 | //movabs r9,0x9999999999999999 884 | //movabs r10,0xaaaaaaaaaaaaaaaa 885 | //movabs r11,0xbbbbbbbbbbbbbbbb 886 | //movabs r12,0xcccccccccccccccc 887 | //movabs r13,0xdddddddddddddddd 888 | //movabs r14,0xeeeeeeeeeeeeeeee 889 | //movabs r15,0xfefefefefefefefe 890 | const uint8_t prolog[] = { 891 | 0x50, 0x53, 0x51, 0x52, 0x57, 0x56, 0x55, 0x41, 0x50, 0x41, 0x51, 0x41, 892 | 0x52, 0x41, 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 893 | 0xb8, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x48, 0xbb, 0x22, 894 | 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x48, 0xb9, 0x33, 0x33, 0x33, 895 | 0x33, 0x33, 0x33, 0x33, 0x33, 0x48, 0xba, 0x44, 0x44, 0x44, 0x44, 0x44, 896 | 0x44, 0x44, 0x44, 0x48, 0xbf, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 897 | 0x55, 0x48, 0xbe, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x48, 898 | 0xbd, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x49, 0xb8, 0x88, 899 | 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x49, 0xb9, 0x99, 0x99, 0x99, 900 | 0x99, 0x99, 0x99, 0x99, 0x99, 0x49, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 901 | 0xaa, 0xaa, 0xaa, 0x49, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 902 | 0xbb, 0x49, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x49, 903 | 0xbd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x49, 0xbe, 0xee, 904 | 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0x49, 0xbf, 0xfe, 0xfe, 0xfe, 905 | 0xfe, 0xfe, 0xfe, 0xfe, 0xfe 906 | }; 907 | 908 | 909 | //pop r15 910 | //pop r14 911 | //pop r13 912 | //pop r12 913 | //pop r11 914 | //pop r10 915 | //pop r9 916 | //pop r8 917 | //pop rbp 918 | //pop rsi 919 | //pop rdi 920 | //pop rdx 921 | //pop rcx 922 | //pop rbx 923 | //pop rax 924 | //ret 925 | const uint8_t epilog[] = { 926 | 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x41, 0x5b, 0x41, 0x5a, 927 | 0x41, 0x59, 0x41, 0x58, 0x5d, 0x5e, 0x5f, 0x5a, 0x59, 0x5b, 0x58, 0xc3 928 | }; 929 | 930 | /* 931 | This is a terrible piece of code, but there are no other way around (I guess). 932 | This code disassemble the instruction present at `op` and returns its opcode 933 | length. This is needed since we need to skip the faulting SIGFPE instruction. 934 | To ensure we do not affect original execution, we re-execute the faulting 935 | instruction in an environment without FTZ enabled. This achieved with a 936 | terrible trick of doing some sort of JIT'ing. 937 | */ 938 | int get_ins_len_and_re_execute(uint8_t *op, ucontext_t *uc) { 939 | static uint8_t *rwx; 940 | static int first_time = 1; 941 | xed_state_t dstate; 942 | xed_decoded_inst_t xedd; 943 | const xed_inst_t* xi; 944 | int noperands; 945 | const xed_operand_t* operand; 946 | xed_operand_enum_t opname; 947 | xed_reg_enum_t reg; 948 | int op_len; 949 | void (*fptr)(void); 950 | 951 | static void (*xed_tables_init)(void); 952 | static void (*xed_decoded_inst_zero_set_mode)(xed_decoded_inst_t* p, const xed_state_t* dstate); 953 | static xed_error_enum_t (*xed_decode)(xed_decoded_inst_t* xedd, const xed_uint8_t* itext, const unsigned int bytes); 954 | static const xed_operand_t* (*xed_inst_operand)(const xed_inst_t *p, unsigned int i); 955 | static xed_reg_enum_t (*xed_decoded_inst_get_reg)(const xed_decoded_inst_t *p, xed_operand_enum_t reg_operand); 956 | static xed_uint_t (*xed_operand_written)(const xed_operand_t *p); 957 | void *handle; 958 | 959 | if(first_time) { 960 | handle = dlopen(LIBXED_SO, RTLD_LAZY); 961 | if(!handle) { 962 | printf("Can't open libxed.so\n"); 963 | exit(-1); 964 | } 965 | dlerror(); 966 | xed_tables_init = dlsym(handle, "xed_tables_init"); 967 | if(dlerror() != NULL) exit(-37); 968 | xed_decoded_inst_zero_set_mode = dlsym(handle, "xed_decoded_inst_zero_set_mode"); 969 | if(dlerror() != NULL) exit(-37); 970 | xed_decode = dlsym(handle, "xed_decode"); 971 | if(dlerror() != NULL) exit(-37); 972 | xed_inst_operand = dlsym(handle, "xed_inst_operand"); 973 | if(dlerror() != NULL) exit(-37); 974 | xed_decoded_inst_get_reg = dlsym(handle, "xed_decoded_inst_get_reg"); 975 | if(dlerror() != NULL) exit(-37); 976 | xed_operand_written = dlsym(handle, "xed_operand_written"); 977 | if(dlerror() != NULL) exit(-37); 978 | 979 | xed_tables_init(); 980 | first_time = 0; 981 | rwx = (uint8_t *) mmap(NULL, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 982 | } 983 | 984 | //Get instruction length 985 | dstate.mmode=XED_MACHINE_MODE_LONG_64; 986 | xed_decoded_inst_zero_set_mode(&xedd, &dstate); 987 | xed_decode(&xedd, op, XED_MAX_INSTRUCTION_BYTES); 988 | xi = xed_decoded_inst_inst(&xedd); 989 | op_len = xed_decoded_inst_get_length(&xedd); 990 | 991 | 992 | //Copy the assembly wrapper to re-execute the faulty instr 993 | fptr = (void(*)(void))rwx; 994 | memcpy(rwx, prolog, sizeof(prolog)); 995 | memcpy(rwx+sizeof(prolog), op, op_len); 996 | memcpy(rwx+sizeof(prolog)+op_len, epilog, sizeof(epilog)); 997 | 998 | //Patch the opcodes to restore the original registers 999 | memcpy(&rwx[0x17+ 0+2] , &uc->uc_mcontext.gregs[REG_RAX], 8); 1000 | memcpy(&rwx[0x17+10+2] , &uc->uc_mcontext.gregs[REG_RBX], 8); 1001 | memcpy(&rwx[0x17+20+2] , &uc->uc_mcontext.gregs[REG_RCX], 8); 1002 | memcpy(&rwx[0x17+30+2] , &uc->uc_mcontext.gregs[REG_RDX], 8); 1003 | memcpy(&rwx[0x17+40+2] , &uc->uc_mcontext.gregs[REG_RDI], 8); 1004 | memcpy(&rwx[0x17+50+2] , &uc->uc_mcontext.gregs[REG_RSI], 8); 1005 | memcpy(&rwx[0x17+60+2] , &uc->uc_mcontext.gregs[REG_RBP], 8); 1006 | memcpy(&rwx[0x17+70+2] , &uc->uc_mcontext.gregs[REG_R8 ], 8); 1007 | memcpy(&rwx[0x17+80+2] , &uc->uc_mcontext.gregs[REG_R9 ], 8); 1008 | memcpy(&rwx[0x17+90+2] , &uc->uc_mcontext.gregs[REG_R10], 8); 1009 | memcpy(&rwx[0x17+100+2], &uc->uc_mcontext.gregs[REG_R11], 8); 1010 | memcpy(&rwx[0x17+110+2], &uc->uc_mcontext.gregs[REG_R12], 8); 1011 | memcpy(&rwx[0x17+120+2], &uc->uc_mcontext.gregs[REG_R13], 8); 1012 | memcpy(&rwx[0x17+130+2], &uc->uc_mcontext.gregs[REG_R14], 8); 1013 | memcpy(&rwx[0x17+140+2], &uc->uc_mcontext.gregs[REG_R15], 8); 1014 | 1015 | asm volatile("lfence"); //Avoid MC.SMC 1016 | 1017 | //Disable FTZ, and re-execute the faulty instruction after restoring all XMM registers 1018 | _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF); 1019 | asm volatile("movdqu (%0), %%xmm0" ::"r"(&uc->uc_mcontext.fpregs->_xmm[0]):); 1020 | asm volatile("movdqu (%0), %%xmm1" ::"r"(&uc->uc_mcontext.fpregs->_xmm[1]):); 1021 | asm volatile("movdqu (%0), %%xmm2" ::"r"(&uc->uc_mcontext.fpregs->_xmm[2]):); 1022 | asm volatile("movdqu (%0), %%xmm3" ::"r"(&uc->uc_mcontext.fpregs->_xmm[3]):); 1023 | asm volatile("movdqu (%0), %%xmm4" ::"r"(&uc->uc_mcontext.fpregs->_xmm[4]):); 1024 | asm volatile("movdqu (%0), %%xmm5" ::"r"(&uc->uc_mcontext.fpregs->_xmm[5]):); 1025 | asm volatile("movdqu (%0), %%xmm6" ::"r"(&uc->uc_mcontext.fpregs->_xmm[6]):); 1026 | asm volatile("movdqu (%0), %%xmm7" ::"r"(&uc->uc_mcontext.fpregs->_xmm[7]):); 1027 | asm volatile("movdqu (%0), %%xmm8" ::"r"(&uc->uc_mcontext.fpregs->_xmm[8]):); 1028 | asm volatile("movdqu (%0), %%xmm9" ::"r"(&uc->uc_mcontext.fpregs->_xmm[9]):); 1029 | asm volatile("movdqu (%0), %%xmm10"::"r"(&uc->uc_mcontext.fpregs->_xmm[10]):); 1030 | asm volatile("movdqu (%0), %%xmm11"::"r"(&uc->uc_mcontext.fpregs->_xmm[11]):); 1031 | asm volatile("movdqu (%0), %%xmm12"::"r"(&uc->uc_mcontext.fpregs->_xmm[12]):); 1032 | asm volatile("movdqu (%0), %%xmm13"::"r"(&uc->uc_mcontext.fpregs->_xmm[13]):); 1033 | asm volatile("movdqu (%0), %%xmm14"::"r"(&uc->uc_mcontext.fpregs->_xmm[14]):); 1034 | asm volatile("movdqu (%0), %%xmm15"::"r"(&uc->uc_mcontext.fpregs->_xmm[15]):); 1035 | fptr(); 1036 | asm volatile("movdqu %%xmm0, (%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[0]):); 1037 | asm volatile("movdqu %%xmm1, (%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[1]):); 1038 | asm volatile("movdqu %%xmm2, (%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[2]):); 1039 | asm volatile("movdqu %%xmm3, (%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[3]):); 1040 | asm volatile("movdqu %%xmm4, (%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[4]):); 1041 | asm volatile("movdqu %%xmm5, (%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[5]):); 1042 | asm volatile("movdqu %%xmm6, (%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[6]):); 1043 | asm volatile("movdqu %%xmm7, (%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[7]):); 1044 | asm volatile("movdqu %%xmm8, (%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[8]):); 1045 | asm volatile("movdqu %%xmm9, (%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[9]):); 1046 | asm volatile("movdqu %%xmm10,(%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[10]):); 1047 | asm volatile("movdqu %%xmm11,(%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[11]):); 1048 | asm volatile("movdqu %%xmm12,(%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[12]):); 1049 | asm volatile("movdqu %%xmm13,(%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[13]):); 1050 | asm volatile("movdqu %%xmm14,(%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[14]):); 1051 | asm volatile("movdqu %%xmm15,(%0)" ::"r"(&uc->uc_mcontext.fpregs->_xmm[15]):); 1052 | _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); 1053 | 1054 | return op_len; 1055 | } 1056 | 1057 | void handler(int sig, siginfo_t* si, void* vcontext) 1058 | { 1059 | int op_len; 1060 | ucontext_t *uc = (ucontext_t *)vcontext; 1061 | void *fault_rip = (void *) si->si_addr; 1062 | void *fault_addr = get_fault_addr((uint8_t*)fault_rip, &op_len, uc); 1063 | uint8_t *fault_ptr = (uint8_t *) fault_addr; 1064 | 1065 | //fprintf(stderr, "Exception caught: fault_addr: %p\n", fault_addr); 1066 | //fflush(stderr); 1067 | 1068 | //If our decoder fails 1069 | if(fault_addr == NULL) { 1070 | //Damn we got a SIGFPE from a non vaddss. Let's disassemble and skip the fault 1071 | #if COUNT_EXCEPTIONS == 1 1072 | except_cnt_underflow++; 1073 | #endif 1074 | op_len = get_ins_len_and_re_execute(fault_rip, uc); 1075 | goto false_positive; 1076 | } 1077 | 1078 | //Probably useless 1079 | if( (*(uint32_t *)fault_ptr) != FLOAT_MAGIC_POISON && 1080 | (*(uint32_t *)fault_ptr) != FLOAT_MAGIC_POISON_PRE) goto false_positive; 1081 | 1082 | uint8_t *ptr = fault_ptr; 1083 | 1084 | // New Improved Addition: if the fault value is 0x8b8b8b89, we should scan right to confirm a redzone 1085 | // not left, since the 89 has to mark the start of a redzone (this way we avoid reading a prepended underflow zone) 1086 | if(*((uint32_t *)fault_ptr) == FLOAT_MAGIC_POISON_PRE){ // i = {0,1,2,3} == {89 8b 8b 8b} 1087 | int found = 0; 1088 | for(int i = 4; i < REDZONE_SIZE; i++){ 1089 | if(*(ptr+i) != FLOAT_MAGIC_POISON_BYTE){ 1090 | // the right of a 0x898b8b8b8b is not a redzone (no 8b) 1091 | #if COUNT_EXCEPTIONS == 1 1092 | except_cnt_vaddss_skip++; 1093 | #endif 1094 | goto false_positive; 1095 | } 1096 | } 1097 | } 1098 | else { 1099 | //Let's go left until we find something that is not 8b 1100 | //if it is 89 -> true positive, or false positive containing 89 8b 8b 8b 8b ... 1101 | //if it is not 89 false positive 1102 | //also make sure we have at least 15 8b on the right 1103 | 1104 | int found = 0; 1105 | while(*ptr == FLOAT_MAGIC_POISON_BYTE) { 1106 | ptr--; 1107 | found++; 1108 | } 1109 | 1110 | //Now ptr pointing to something that is not 8b 1111 | if(*ptr == FLOAT_MAGIC_POISON_PRE_BYTE) { 1112 | //Ok we need 15 8b on the right from current ptr 1113 | for(int i = 1; i < REDZONE_SIZE; i++) { 1114 | if (*(ptr+i) != FLOAT_MAGIC_POISON_BYTE) { 1115 | #if COUNT_EXCEPTIONS == 1 1116 | except_cnt_vaddss_skip++; 1117 | #endif 1118 | goto false_positive; 1119 | } 1120 | } 1121 | } else { 1122 | #if COUNT_EXCEPTIONS == 1 1123 | except_cnt_vaddss_skip++; 1124 | #endif 1125 | goto false_positive; 1126 | } 1127 | } 1128 | 1129 | // fault 1130 | #if COUNT_EXCEPTIONS == 1 1131 | except_cnt_vaddss_rz++; 1132 | #endif 1133 | 1134 | #if SURVIVE_EXCEPTIONS == 0 1135 | fprintf(stderr, "\n!!!! [FLOATZONE] Fault addr = %p !!!!\n", fault_addr); 1136 | 1137 | for(int i=-64; i<64; i+=4) { 1138 | fprintf(stderr, "%p: %02x %02x %02x %02x ", &fault_ptr[i], fault_ptr[i], fault_ptr[i+1], fault_ptr[i+2], fault_ptr[i+3]); 1139 | if((void *)&fault_ptr[i] == fault_addr) fprintf(stderr, " <-----"); 1140 | fprintf(stderr, "\n"); 1141 | } 1142 | fprintf(stderr, "\n"); 1143 | 1144 | void **buf = malloc(128*sizeof(void *)); 1145 | int ret = backtrace(buf, 128); 1146 | char **names = backtrace_symbols(buf, ret); 1147 | fprintf(stderr, "Fault RIP = %p\nBacktrace:\n", fault_rip); 1148 | for(int i=2; iuc_mcontext.gregs[REG_RIP] += op_len; 1161 | 1162 | //Remove the presence of spurious redzone from the stack. 1163 | //This was a nasty bug where the SIGFPE exception handler was leaving dangling redzone 1164 | //when returning from a false positive 1165 | for(int i=0; i<16; i++) { 1166 | if(memcmp(&uc->uc_mcontext.fpregs->_xmm[i], &redzone_s, REDZONE_SIZE) == 0) { 1167 | memset(&uc->uc_mcontext.fpregs->_xmm[i], 0, REDZONE_SIZE); 1168 | } 1169 | } 1170 | 1171 | return; 1172 | } 1173 | 1174 | #if CATCH_SEGFAULT == 1 1175 | static void segfault_handler(int sig, siginfo_t *si, void *vcontext){ 1176 | #if FUZZ_MODE == 1 1177 | abort(); 1178 | #else 1179 | exit(FAULT_ERROR_CODE); 1180 | #endif 1181 | } 1182 | #endif 1183 | 1184 | /// Disables the process so we don't do quarantine checking 1185 | /// on malloc'd memory from pre-init libc/libdl. 1186 | static void disable_process() { 1187 | process = 0; 1188 | } 1189 | 1190 | typedef int (*main_t)(int, char, char); 1191 | typedef int (*libc_start_main_t)(main_t main, int argc, char** ubp_av, 1192 | void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void* stack_end); 1193 | int __libc_start_main(main_t main, int argc, char** ubp_av, 1194 | void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void* stack_end) 1195 | { 1196 | libc_start_main_t og_libc_start_main = (libc_start_main_t)dlsym(RTLD_NEXT, "__libc_start_main"); 1197 | __signal = (proto_signal) dlsym(RTLD_NEXT, "signal"); 1198 | ___sigaction = (proto_sigaction) dlsym(RTLD_NEXT, "sigaction"); 1199 | ___sysv_signal = (proto_sysv_signal) dlsym(RTLD_NEXT, "__sysv_signal"); 1200 | 1201 | __longjmp = (proto_longjmp) dlsym(RTLD_NEXT, "longjmp"); 1202 | __siglongjmp = (proto_siglongjmp) dlsym(RTLD_NEXT, "siglongjmp"); 1203 | __og_cxa_throw = (proto_cxa_throw) dlsym(RTLD_NEXT, "__cxa_throw"); 1204 | __posix_memalign = (proto_posix_memalign) dlsym(RTLD_NEXT, "posix_memalign"); 1205 | 1206 | #if FUZZ_MODE == 1 1207 | // avoid shutdown free() calls in some glibc versions on uninstrumented memory 1208 | if (atexit(disable_process) != 0) { 1209 | fprintf(stderr, "Failed to set atexit\n"); 1210 | abort(); 1211 | } 1212 | #endif 1213 | 1214 | if(strstr(ubp_av[0], TARGET) || strstr(ubp_av[0], JULIET)){ 1215 | // register signal handler 1216 | struct sigaction action; 1217 | memset(&action, 0, sizeof(struct sigaction)); 1218 | action.sa_flags = SA_SIGINFO; 1219 | action.sa_sigaction = handler; 1220 | 1221 | #if ENABLE_EXCEPTIONS == 1 1222 | // enable Flush To Zero to allow Underflow 1223 | _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); 1224 | 1225 | ___sigaction(SIGFPE, &action, NULL); 1226 | 1227 | // enable FP underflow exceptions 1228 | feenableexcept(FE_UNDERFLOW); 1229 | #endif 1230 | 1231 | #if ENABLE_QUARANTINE == 1 1232 | pthread_mutex_init(&ring_lock, NULL); 1233 | #endif 1234 | 1235 | #if CATCH_SEGFAULT == 1 1236 | memset(&action, 0, sizeof(struct sigaction)); 1237 | sigemptyset(&action.sa_mask); 1238 | action.sa_flags = SA_NODEFER; 1239 | action.sa_sigaction = segfault_handler; 1240 | sigaction(SIGSEGV, &action, NULL); // Segmentation fault 1241 | #endif 1242 | 1243 | process = 1; 1244 | } 1245 | 1246 | return og_libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, stack_end); 1247 | } 1248 | 1249 | --------------------------------------------------------------------------------