diff --git a/Security Research and Development with LLVM - Andrew Reiter/.gitignore b/Security Research and Development with LLVM - Andrew Reiter/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/Security Research and Development with LLVM - Andrew Reiter/README.md b/Security Research and Development with LLVM - Andrew Reiter/README.md new file mode 100644 index 0000000..fbe528c --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/README.md @@ -0,0 +1,18 @@ + +This repo contains some materials related to a talk +on security r&d projects that in some way use LLVM +for doing their work. + + +- projects.md is a list of such projects +- code is a set of very basic, example code to help those interested in getting up to speed with some basics of LLVM. Don't hate. +- slides is the slide deck + +#### Again on the code +I must repeat myself: the provided code is only meant to be basic helpers for learning about LLVM +and is not meant to be some new awesome tool (sadly, no). There is a great deal of research in +dynamic and program analysis that is being done and the goal of this code is to make it so you +can start to more easily read some of the code from those projects ... and then make sense of it. +This is to avoid getting lost in code versus meaning. + + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/README.md b/Security Research and Development with LLVM - Andrew Reiter/code/README.md new file mode 100644 index 0000000..a0845ca --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/README.md @@ -0,0 +1,13 @@ +Very basic example codes. + +- bbskel: BasicBlock pass skeleton +- cgspskel: CallGraphSCC pass skeleton +- comminute: tool illustrating pass mgr, pass deps, and more +- fpskel: FunctionPass skeleton +- intflip: integer argument randomizer|bit-flipper +- mpskel: ModulePass skeleton +- npassert: NULL pointer check insertion +- rpskel: RegionPass skeleton +- visitorskel: Using a InstVisitor class + + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/Makefile b/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/Makefile new file mode 100644 index 0000000..3173d43 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/Makefile @@ -0,0 +1,52 @@ +LLVM_VER=3.9 +LLVM_HOME=/usr/bin +LLVM_CONFIG?=$(LLVM_HOME)/llvm-config-$(LLVM_VER) + +ifndef VERBOSE +QUIET:=@ +endif + +SRC_DIR?=$(PWD)/src + +CXX=$(LLVM_HOME)/clang++-$(LLVM_VER) +CC=$(LLVM_HOME)/clang-$(LLVM_VER) +OPT=$(LLVM_HOME)/opt-$(LLVM_VER) +DIS=$(LLVM_HOME)/llvm-dis-$(LLVM_VER) +LNK=$(LLVM_HOME)/llvm-link-$(LLVM_VER) + +LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags) +LDFLAGS+=-shared -Wl,-O1 + +CXXFLAGS+=-I$(shell $(LLVM_CONFIG) --includedir) +CXXFLAGS+=-std=c++11 -fPIC -fvisibility-inlines-hidden +CXXFLAGS+=-Wall -Wextra -g -Wno-unused-parameter -Wno-unused-variable + +CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) +CPPFLAGS+=-I$(SRC_DIR) + + +PASS=BBSkel.so +PASS_OBJECTS=BBSkel.o + +default: prep $(PASS) + +prep: + $(QUIET)mkdir -p built + +%.o : $(SRC_DIR)/%.cpp + @echo Compiling $*.cpp + $(QUIET)$(CXX) -o built/$*.o -c $(CPPFLAGS) $(CXXFLAGS) $< + +$(PASS) : $(PASS_OBJECTS) + @echo Linking $@ + $(QUIET)$(CXX) -o built/$@ $(LDFLAGS) $(CXXFLAGS) built/*.o + +clean: + $(QUIET)rm -rf built test/*.bc + + +tests: + $(CC) -emit-llvm -o test/foo.bc -c test/foo.c + +runtests: + $(OPT) -load built/BBSkel.so -mem2reg -bbskel < test/foo.bc diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/README.md b/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/README.md new file mode 100644 index 0000000..fe9c57a --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/README.md @@ -0,0 +1,20 @@ + +# BBSkel + +This is a basic block pass skeleton. Note, there are also +loop passes, region passes, etc. + + +# Build & Run + +First check the Makefile to set path to llvm-config and version. +3.8, 3.9 should be fine, so should 4.0 + +``` +$ make +$ opt-X.Y -load built/BBSkel.so -bbskel < file.bc +... +$ +``` + + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/src/BBSkel.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/src/BBSkel.cpp new file mode 100644 index 0000000..d28f4c0 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/src/BBSkel.cpp @@ -0,0 +1,61 @@ +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#include "BBSkel.h" + +void +BBSkel::getAnalysisUsage(AnalysisUsage &AU) const +{ + // No changes to CFG, so tell the pass manager + AU.setPreservesCFG(); +} + +bool +BBSkel::doFinalization(Function &F) +{ + errs() << "#BBs: " << bbcount << "\n"; + errs() << "#Is: " << icount << "\n"; + return false; +} + +bool +BBSkel::runOnBasicBlock(BasicBlock &B) +{ + bbcount++; + errs() << " Basic Block found:\n"; + for (auto &I : B) { // Iterate through instructions in the block + ++icount; + // Note in output if instruction is a call/invoke + if (isa(I) || isa(I)) { + errs() << " C "; + } else { + errs() << " "; + } + I.dump(); + errs() << " used by:\n"; + // Go through and dump the uses for each instruction. + for (auto ui = I.user_begin(); ui != I.user_end(); ++ui) { + errs() << " U: "; + ui->dump(); + } + errs() << " ~~~~ \n"; + } + errs() << " --- end of basic block ---\n"; + + // return true if CFG has changed. + return false; +} + + + +/* + * Register this pass to be made usable. + * Needs the static ID initialized and the pass declaration given. + */ +char BBSkel::ID = 0; +static RegisterPass XX("bbskel", "BasicBlock Pass Skeleton"); + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/src/BBSkel.h b/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/src/BBSkel.h new file mode 100644 index 0000000..62aef48 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/src/BBSkel.h @@ -0,0 +1,35 @@ +#ifndef __BBSKEL_H +#define __BBSKEL_H + +struct BBSkel : public BasicBlockPass { + /* + * For all of your passes you will need this and to define it. + * It's address is used by pass system, so the value does not matter. + */ + static char ID; + + unsigned bbcount; + unsigned icount; + + BBSkel() : BasicBlockPass(ID) { + bbcount = 0; + icount = 0; + } + + // Called on each BasicBlock in given compilation unit + virtual bool runOnBasicBlock(BasicBlock &); + + /* + * Used to help order passes by pass manager. + * Declare any passes you need run prior here.. as well as + * any information such as preserving CFG or similar. + */ + virtual void getAnalysisUsage(AnalysisUsage &) const; + + /* + * Called after each exec of a runOnBasicBlock. + */ + virtual bool doFinalization(Function &); +}; + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/test/foo.c b/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/test/foo.c new file mode 100644 index 0000000..3979e2c --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/bbskel/test/foo.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include +#include + +void +leaks_passwd() +{ + char *p; + struct addrinfo hints, *result; + + p = getpass("enter passwd: "); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + (void)getaddrinfo(p, "http", &hints, &result); +} + +int +main(int argc, char **argv) +{ + leaks_passwd(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/Makefile b/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/Makefile new file mode 100644 index 0000000..5f2806b --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/Makefile @@ -0,0 +1,51 @@ +LLVM_VER=3.9 +LLVM_HOME=/usr/bin +LLVM_CONFIG?=$(LLVM_HOME)/llvm-config-$(LLVM_VER) + +ifndef VERBOSE +QUIET:=@ +endif + +SRC_DIR?=$(PWD)/src + +CXX=$(LLVM_HOME)/clang++-$(LLVM_VER) +CC=$(LLVM_HOME)/clang-$(LLVM_VER) +OPT=$(LLVM_HOME)/opt-$(LLVM_VER) +DIS=$(LLVM_HOME)/llvm-dis-$(LLVM_VER) +LNK=$(LLVM_HOME)/llvm-link-$(LLVM_VER) + +LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags) +LDFLAGS+=-shared -Wl,-O1 + +CXXFLAGS+=-I$(shell $(LLVM_CONFIG) --includedir) +CXXFLAGS+=-std=c++11 -fPIC -fvisibility-inlines-hidden +CXXFLAGS+=-Wall -Wextra -g -Wno-unused-parameter -Wno-unused-variable + +CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) +CPPFLAGS+=-I$(SRC_DIR) + +PASS=CGSSkel.so +PASS_OBJECTS=CGSSkel.o + +default: prep $(PASS) + +prep: + $(QUIET)mkdir -p built + +%.o : $(SRC_DIR)/%.cpp + @echo Compiling $*.cpp + $(QUIET)$(CXX) -o built/$*.o -c $(CPPFLAGS) $(CXXFLAGS) $< + +$(PASS) : $(PASS_OBJECTS) + @echo Linking $@ + $(QUIET)$(CXX) -o built/$@ $(LDFLAGS) $(CXXFLAGS) built/*.o + +clean: + $(QUIET)rm -rf built test/*.bc + + +tests: + $(CC) -emit-llvm -o test/foo.bc -c test/foo.c + +runtests: + $(OPT) -load built/CGSSkel.so -cgsskel < test/foo.bc diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/README.md b/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/README.md new file mode 100644 index 0000000..021e5b5 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/README.md @@ -0,0 +1,18 @@ + +# CallGraphSCCPass Skeleton + +Bottom up style to assist to use + augment for CG building + +# Build & Run + +First check the Makefile to set path to llvm-config and version. +3.8, 3.9 should be fine, so should 4.0 + +``` +$ make +$ opt-X.Y -load built/CGSSkel.so -cgsskel < file.bc +... +$ +``` + + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/src/CGSSkel.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/src/CGSSkel.cpp new file mode 100644 index 0000000..35e049c --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/src/CGSSkel.cpp @@ -0,0 +1,58 @@ +#include "llvm/IR/Module.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#include "CGSSkel.h" + +void +CGSSkel::getAnalysisUsage(AnalysisUsage &AU) const +{ + // No changes to CFG, so tell the pass manager + AU.setPreservesCFG(); +} + +bool +CGSSkel::doFinalization(CallGraph &G) +{ + return false; +} + +bool +CGSSkel::doInitialization(CallGraph &G) +{ + return false; +} + +bool +CGSSkel::runOnSCC(CallGraphSCC &GSCC) +{ + errs() << " Strongly connected component found:\n"; + + /* + * Singular SCC's can be used to detect recursion. See: + * http://llvm.org/docs/doxygen/html/FunctionAttrs_8.cpp_source.html + */ + if (GSCC.isSingular()) { + errs() << " SCC is singular\n"; + } + for (auto &G : GSCC) { + errs() << " Dump:\n"; + G->dump(); + } + errs() << " --- end of SCC ---\n"; + + // return true if Module has been changed. + return false; +} + +/* + * Register this pass to be made usable. + * Needs the static ID initialized and the pass declaration given. + */ +char CGSSkel::ID = 0; +static RegisterPass XX("cgsskel", "CallGraphSCC Pass Skeleton"); + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/src/CGSSkel.h b/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/src/CGSSkel.h new file mode 100644 index 0000000..1bc752e --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/src/CGSSkel.h @@ -0,0 +1,28 @@ +#ifndef __CGSSKEL_H +#define __CGSSKEL_H + +struct CGSSkel : public CallGraphSCCPass { + /* + * For all of your passes you will need this and to define it. + * It's address is used by pass system, so the value does not matter. + */ + static char ID; + + CGSSkel() : CallGraphSCCPass(ID) { + } + + // Return true if Module was modified, otherwise false. + virtual bool runOnSCC(CallGraphSCC &); + + /* + * Used to help order passes by pass manager. + * Declare any passes you need run prior here.. as well as + * any information such as preserving CFG or similar. + */ + virtual void getAnalysisUsage(AnalysisUsage &) const; + + virtual bool doInitialization(CallGraph &CG); + virtual bool doFinalization(CallGraph &); +}; + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/test/foo.c b/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/test/foo.c new file mode 100644 index 0000000..3979e2c --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/cgsskel/test/foo.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include +#include + +void +leaks_passwd() +{ + char *p; + struct addrinfo hints, *result; + + p = getpass("enter passwd: "); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + (void)getaddrinfo(p, "http", &hints, &result); +} + +int +main(int argc, char **argv) +{ + leaks_passwd(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/Makefile b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/Makefile new file mode 100644 index 0000000..cd74890 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/Makefile @@ -0,0 +1,235 @@ +LLBIN=/usr/lib/llvm-3.9/bin +LLVM_CONFIG=$(LLBIN)/llvm-config +#QUIET:=@ +QUIET:= + +BUILDJSONCPP:=# +ifdef WITHJSONCPP +BUILDJSONCPP:= +endif + +SRC_DIR?=$(PWD)/src +LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags) -Lthirdparty/jsoncpp-1.8.0/build/src/lib_json -ljsoncpp + +COMMON_FLAGS=-Wall -Wextra -g + + +CXXFLAGS+=$(COMMON_FLAGS) $(shell $(LLVM_CONFIG) --cxxflags) +CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) -std=c++11 -I$(SRC_DIR) -Ithirdparty/jsoncpp-1.8.0/include + +LOADABLE_MODULE_OPTIONS=-shared -Wl,-O1 + +LDIS=$(LLBIN)/llvm-dis +CPP=$(LLBIN)/clang++ +CC=$(LLBIN)/clang + +BOD=build/obj +PASSMGR=Comminute +OPM=build/bin/$(PASSMGR) +PASS=ComminuteShared.so +PASS_OBJECTS=Analysis/TargetCallSitesPass.o \ + Analysis/StoreCollector.o \ + Transform/FunctionExternalizer.o \ + Transform/ChoosePhiValue.o \ + Analysis/NaiveSensitiveDataLeak.o \ + Analysis/NaiveFileDescLeak.o \ + Analysis/PotentiallyDangerousScan.o \ + Analysis/PotentiallyDangerousScanUserMethod.o \ + Analysis/PotentiallyDangerousScanFunctionPass.o \ + Analysis/NaiveConstantArgCheck.o + +# XXX +# This is awful... Im just like "PUT IT ALL IN" +LIBS=$(shell $(LLVM_CONFIG) --libs) -lclang +LIBS+=-lpthread -ldl -lncurses -lz + +TDIR=build/tests + +default: prep $(PASS) passmgr + +prep: + @echo "Prep phase" + $(QUIET)mkdir -p build/obj + $(QUIET)mkdir -p build/obj/Analysis + $(QUIET)mkdir -p build/obj/Transform + $(QUIET)mkdir -p build/bin + $(QUIET)mkdir -p build/lib + +define builditdood +$(QUIET)$(CPP) -o $(BOD)/$(1)/$(@F) -c $(CPPFLAGS) $(CXXFLAGS) $< +endef + +Transform/%.o: $(SRC_DIR)/Transform/%.cpp + @echo "Compiling $*.cpp" + $(call builditdood,Transform) + +Analysis/%.o: $(SRC_DIR)/Analysis/%.cpp + @echo "Compiling $*.cpp" + $(call builditdood,Analysis) + +%.o : $(SRC_DIR)/%.cpp + @echo "Compiling $*.cpp" + $(call builditdood,.) + +passmgr: + @echo "Building passmanager clean up ldflags XXX" + $(QUIET)$(CPP) -o $(BOD)/Comminute.o -c $(CPPFLAGS) $(CXXFLAGS) src/Comminute.cpp + $(QUIET)$(CPP) -o $(OPM) $(CXXFLAGS) build/obj/Comminute.o ${addprefix $(BOD)/,$(PASS_OBJECTS)} $(LDFLAGS) $(LIBS) + + +$(PASS) : $(PASS_OBJECTS) + @echo "Linking $@" + $(QUIET)$(CPP) -o build/lib/$@ $(LOADABLE_MODULE_OPTIONS) $(CXXFLAGS) $(LDFLAGS) ${addprefix $(BOD)/,$^} + +test: testprep testnca testnsdl testpd testnfdl + +testprep: + $(QUIET)mkdir -p $(TDIR) + +testnca: + $(QUIET)$(CC) -o $(TDIR)/NCA001 tests/NCA001.c + $(QUIET)$(CC) -g -emit-llvm -o $(TDIR)/NCA001.bc -c tests/NCA001.c + $(QUIET)$(LDIS) $(TDIR)/NCA001.bc + $(QUIET)$(CC) -o $(TDIR)/NCA002 tests/NCA002.c + $(QUIET)$(CC) -g -emit-llvm -o $(TDIR)/NCA002.bc -c tests/NCA002.c + $(QUIET)$(LDIS) $(TDIR)/NCA002.bc + +testnsdl: + $(QUIET)$(CC) -o $(TDIR)/NSDL001 tests/NSDL001.c + $(QUIET)$(CC) -g -emit-llvm -o $(TDIR)/NSDL001.bc -c tests/NSDL001.c + $(QUIET)$(LDIS) $(TDIR)/NSDL001.bc + $(QUIET)$(CC) -o $(TDIR)/NSDL002 tests/NSDL002.c + $(QUIET)$(CC) -g -emit-llvm -o $(TDIR)/NSDL002.bc -c tests/NSDL002.c + $(QUIET)$(LDIS) $(TDIR)/NSDL002.bc + +testpd: + $(QUIET)$(CC) -o $(TDIR)/PD001 tests/PD001.c + $(QUIET)$(CC) -g -emit-llvm -o $(TDIR)/PD001.bc -c tests/PD001.c + $(QUIET)$(LDIS) $(TDIR)/PD001.bc + +testnfdl: + $(QUIET)$(CC) -o $(TDIR)/NFDL001 tests/NFDL001.c + $(QUIET)$(CC) -emit-llvm -o $(TDIR)/NFDL001.bc -c tests/NFDL001.c + $(QUIET)$(LDIS) $(TDIR)/NFDL001.bc + $(QUIET)$(CC) -o $(TDIR)/NFDL002 tests/NFDL002.c + $(QUIET)$(CC) -g -emit-llvm -o $(TDIR)/NFDL002.bc -c tests/NFDL002.c + $(QUIET)$(LDIS) $(TDIR)/NFDL002.bc + $(QUIET)$(CC) -o $(TDIR)/NFDL003 tests/NFDL003.c + $(QUIET)$(CC) -g -emit-llvm -o $(TDIR)/NFDL003.bc -c tests/NFDL003.c + $(QUIET)$(LDIS) $(TDIR)/NFDL003.bc + $(QUIET)$(CC) -o $(TDIR)/NFDL004 tests/NFDL004.c + $(QUIET)$(CC) -g -emit-llvm -o $(TDIR)/NFDL004.bc -c tests/NFDL004.c + $(QUIET)$(LDIS) $(TDIR)/NFDL004.bc + $(QUIET)$(CC) -o $(TDIR)/NFDL005 tests/NFDL005.c + $(QUIET)$(CC) -g -emit-llvm -o $(TDIR)/NFDL005.bc -c tests/NFDL005.c + $(QUIET)$(LDIS) $(TDIR)/NFDL005.bc + $(QUIET)$(CC) -o $(TDIR)/NFDL006 tests/NFDL006.c + $(QUIET)$(CC) -g -emit-llvm -o $(TDIR)/NFDL006.bc -c tests/NFDL006.c + $(QUIET)$(LDIS) $(TDIR)/NFDL006.bc + $(QUIET)$(CC) -o $(TDIR)/NFDL007 tests/NFDL007.c + $(QUIET)$(CC) -g -emit-llvm -o $(TDIR)/NFDL007.bc -c tests/NFDL007.c + $(QUIET)$(LDIS) $(TDIR)/NFDL007.bc + +help: + @echo "make jsoncpp" + @echo "make " + @echo "...See build/" + @echo "make clean or make cleanall which requires jsoncpp rebuild" + @echo "make test" + @echo "make runtests" + @echo "make runconstantarg" + @echo "make runsensitiveleak" + @echo "make runfdleak" + @echo "make rundangerfn" + + +runtests: runconstantarg runsensitiveleak runfdleak rundangerfn + +runconstantarg: + @echo "***" + @echo "*** Running: Naive constant arg on NCA001 ***" + @echo "***" + $(QUIET)$(OPM) -naive-constant-arg $(TDIR)/NCA001.bc $(TDIR)/NCA001_out.bc + @echo "***" + @echo "*** Running: Naive constant arg on NCA002 ***" + @echo "***" + $(QUIET)$(OPM) -naive-constant-arg $(TDIR)/NCA002.bc $(TDIR)/NCA002_out.bc + +runsensitiveleak: + @echo "***" + @echo "*** Running: Naive sensitive leak on NSDL001 ***" + @echo "***" + $(QUIET)$(OPM) -naive-sensitive-data-leak $(TDIR)/NSDL001.bc $(TDIR)/NSDL001_out.bc + $(QUIET)$(LDIS) $(TDIR)/NSDL001_out.bc + @echo "***" + @echo "*** Running: Naive sensitive leak on NSDL002 ***" + @echo "***" + $(QUIET)$(OPM) -naive-sensitive-data-leak $(TDIR)/NSDL002.bc $(TDIR)/NSDL002_out.bc + $(QUIET)$(LDIS) $(TDIR)/NSDL002_out.bc + +rundangerfn: + @echo "***" + @echo "*** Running: Potentially danger function on PD001 ***" + @echo "***" + $(QUIET)$(OPM) -dangerous-function $(TDIR)/PD001.bc $(TDIR)/PD001_out.bc + @echo "***" + @echo "*** Running: Potentially danger function via user method on PD001 ***" + @echo "***" + $(QUIET)$(OPM) -dangerous-function-user-method $(TDIR)/PD001.bc $(TDIR)/PD001_out-um.bc + @echo "***" + @echo "*** Running: Potentially danger function via function pass on PD001 ***" + @echo "***" + $(QUIET)$(OPM) -dangerous-function-fpass $(TDIR)/PD001.bc $(TDIR)/PD001_out-fp.bc + +runfdleak: + @echo "***" + @echo "*** Running: Naive file descriptor leak on NFDL001 ***" + @echo "***" + $(QUIET)$(OPM) -naive-fd-leak $(TDIR)/NFDL001.bc $(TDIR)/NFDL001_out.bc + @echo "***" + @echo "*** Running: Naive file descriptor leak on NFDL002 ***" + @echo "***" + $(QUIET)$(OPM) -naive-fd-leak $(TDIR)/NFDL002.bc $(TDIR)/NFDL002_out.bc + @echo "***" + @echo "*** Running: Naive file descriptor leak on NFDL003 ***" + @echo "***" + $(QUIET)$(OPM) -naive-fd-leak $(TDIR)/NFDL003.bc $(TDIR)/NFDL003_out.bc + @echo "***" + @echo "*** Running: Naive file descriptor leak on NFDL004 ***" + @echo "***" + $(QUIET)$(OPM) -naive-fd-leak $(TDIR)/NFDL004.bc $(TDIR)/NFDL004_out.bc + @echo "***" + @echo "*** Running: Naive file descriptor leak on NFDL005 ***" + @echo "***" + $(QUIET)$(OPM) -naive-fd-leak $(TDIR)/NFDL005.bc $(TDIR)/NFDL005_out.bc + @echo "***" + @echo "*** Running: Naive file descriptor leak on NFDL006 ***" + @echo "***" + $(QUIET)$(OPM) -naive-fd-leak $(TDIR)/NFDL006.bc $(TDIR)/NFDL006_out.bc + @echo "***" + @echo "*** Running: Naive file descriptor leak on NFDL007 ***" + @echo "***" + $(QUIET)$(OPM) -naive-fd-leak $(TDIR)/NFDL007.bc $(TDIR)/NFDL007_out.bc + + +# :^D +jsoncpp: + @echo "Building jsoncpp-1.8.0" + cd thirdparty && \ + tar zxvf jsoncpp-1.8.0.tar.gz && \ + cd jsoncpp-1.8.0 && \ + rm -rf build && \ + mkdir -p build && \ + cd build && \ + cmake .. && \ + make && \ + cd ../../ + +jsonclean: + $(QUIET)rm -rf thirdparty/jsoncpp-1.8.0 + +clean: + $(QUIET)rm -rf build tests/*.ll + +cleanall: clean jsonclean + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/README.md b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/README.md new file mode 100644 index 0000000..29ea449 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/README.md @@ -0,0 +1,31 @@ + +# Comminute + +The code here is intended to be some basics that help with learning +the LLVM API. The points dealt with here are: + +- Pass manager use +- Pass dependency +- Some basic IR instruction and value analysis +- Use/User API + +It is not meant to be a some great bug hunting tool. It is meant +to help get you to the point where you can start to think about +interprocedural and other analyses. Once you get the feel you +should start to look at other code, like SVF, to get into things. +You should look at building CFGs so you can evaluate globals +better. You should look at some extended interprocedural SSA or +perhaps using Andersen's Alias Analysis for analyzing pointers. +There is a lot to doing good static analysis and that's where the +meat of the research is! + +I repeat... Just a learning tool. + +### Multiple potentially dangerous examples + +The potent-danger examples are there to illustrate you can do the +thing a few different ways. Essentially, depending on your +design needs and end goals, you may want to implement one +methodology or another... + + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/constantarg.cfg b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/constantarg.cfg new file mode 100644 index 0000000..a98e331 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/constantarg.cfg @@ -0,0 +1,4 @@ +{ + "srandom" : 0, + "srand48" : 0 +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/fdsink.cfg b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/fdsink.cfg new file mode 100644 index 0000000..443f3ab --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/fdsink.cfg @@ -0,0 +1,3 @@ +{ + "close" : 0 +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/fdsource.cfg b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/fdsource.cfg new file mode 100644 index 0000000..f6f4790 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/fdsource.cfg @@ -0,0 +1,4 @@ +{ + "socket" : -1, + "open" : -1 +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/fexternalizer.txt b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/fexternalizer.txt new file mode 100644 index 0000000..5b3e4d2 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/fexternalizer.txt @@ -0,0 +1,3370 @@ +# functions to externalize... they are only there because +# compiled in or lifted from MC and stubs created (most likely) +FE001_foo +# openssl +a2d_ASN1_OBJECT +a2i_ASN1_ENUMERATED +a2i_ASN1_INTEGER +a2i_ASN1_STRING +a2i_GENERAL_NAME +a2i_ipadd +a2i_IPADDRESS +a2i_IPADDRESS_NC +AES_bi_ige_encrypt +AES_cbc_encrypt +AES_cfb128_encrypt +AES_cfb1_encrypt +AES_cfb8_encrypt +AES_ctr128_encrypt +AES_decrypt +AES_ecb_encrypt +AES_encrypt +AES_ige_encrypt +AES_ofb128_encrypt +AES_options +AES_set_decrypt_key +AES_set_encrypt_key +AES_unwrap_key +AES_wrap_key +ascii2ebcdic +asn1_add_error +ASN1_add_oid_module +ASN1_BIT_STRING_check +ASN1_BIT_STRING_get_bit +ASN1_BIT_STRING_name_print +ASN1_BIT_STRING_num_asc +ASN1_BIT_STRING_set +ASN1_BIT_STRING_set_asc +ASN1_BIT_STRING_set_bit +ASN1_bn_print +ASN1_check_infinite_end +ASN1_const_check_infinite_end +asn1_const_Finish +ASN1_d2i_bio +ASN1_d2i_fp +ASN1_digest +asn1_do_adb +asn1_do_lock +ASN1_dup +asn1_enc_free +asn1_enc_init +asn1_enc_restore +asn1_enc_save +ASN1_ENUMERATED_get +ASN1_ENUMERATED_set +ASN1_ENUMERATED_to_BN +asn1_ex_c2i +asn1_ex_i2c +asn1_Finish +ASN1_GENERALIZEDTIME_adj +ASN1_GENERALIZEDTIME_check +ASN1_GENERALIZEDTIME_print +ASN1_GENERALIZEDTIME_set +ASN1_GENERALIZEDTIME_set_string +ASN1_generate_nconf +ASN1_generate_v3 +asn1_get_choice_selector +asn1_get_field_ptr +ASN1_get_object +asn1_GetSequence +ASN1_i2d_bio +ASN1_i2d_fp +ASN1_INTEGER_cmp +ASN1_INTEGER_dup +ASN1_INTEGER_get +ASN1_INTEGER_set +ASN1_INTEGER_to_BN +ASN1_item_d2i +ASN1_item_d2i_bio +ASN1_item_d2i_fp +ASN1_item_digest +ASN1_item_dup +ASN1_item_ex_d2i +ASN1_item_ex_free +ASN1_item_ex_i2d +ASN1_item_ex_new +ASN1_item_free +ASN1_item_i2d +ASN1_item_i2d_bio +ASN1_item_i2d_fp +ASN1_item_ndef_i2d +ASN1_item_new +ASN1_item_pack +ASN1_item_print +ASN1_item_sign +ASN1_item_sign_ctx +ASN1_item_unpack +ASN1_item_verify +ASN1_mbstring_copy +ASN1_mbstring_ncopy +ASN1_OBJECT_create +ASN1_OBJECT_free +ASN1_OBJECT_new +ASN1_object_size +ASN1_OCTET_STRING_cmp +ASN1_OCTET_STRING_dup +ASN1_OCTET_STRING_set +ASN1_pack_string +ASN1_parse +ASN1_parse_dump +ASN1_PCTX_free +ASN1_PCTX_get_cert_flags +ASN1_PCTX_get_flags +ASN1_PCTX_get_nm_flags +ASN1_PCTX_get_oid_flags +ASN1_PCTX_get_str_flags +ASN1_PCTX_new +ASN1_PCTX_set_cert_flags +ASN1_PCTX_set_flags +ASN1_PCTX_set_nm_flags +ASN1_PCTX_set_oid_flags +ASN1_PCTX_set_str_flags +ASN1_primitive_free +ASN1_primitive_new +ASN1_PRINTABLE_type +ASN1_put_eoc +ASN1_put_object +asn1_set_choice_selector +ASN1_sign +ASN1_STRING_clear_free +ASN1_STRING_cmp +ASN1_STRING_copy +ASN1_STRING_data +ASN1_STRING_dup +ASN1_STRING_free +ASN1_STRING_get_default_mask +ASN1_STRING_length +ASN1_STRING_length_set +ASN1_STRING_new +ASN1_STRING_print +ASN1_STRING_print_ex +ASN1_STRING_print_ex_fp +ASN1_STRING_set +ASN1_STRING_set0 +ASN1_STRING_set_by_NID +ASN1_STRING_set_default_mask +ASN1_STRING_set_default_mask_asc +ASN1_STRING_TABLE_add +ASN1_STRING_TABLE_cleanup +ASN1_STRING_TABLE_get +ASN1_STRING_to_UTF8 +ASN1_STRING_type +ASN1_STRING_type_new +ASN1_tag2bit +ASN1_tag2str +ASN1_template_d2i +ASN1_template_free +ASN1_template_i2d +ASN1_template_new +ASN1_TIME_adj +ASN1_TIME_check +ASN1_TIME_diff +ASN1_TIME_print +ASN1_TIME_set +ASN1_TIME_set_string +ASN1_TIME_to_generalizedtime +ASN1_TYPE_cmp +ASN1_TYPE_get +ASN1_TYPE_get_int_octetstring +ASN1_TYPE_get_octetstring +ASN1_TYPE_set +ASN1_TYPE_set1 +ASN1_TYPE_set_int_octetstring +ASN1_TYPE_set_octetstring +ASN1_UNIVERSALSTRING_to_string +ASN1_unpack_string +ASN1_UTCTIME_adj +ASN1_UTCTIME_check +ASN1_UTCTIME_cmp_time_t +ASN1_UTCTIME_print +ASN1_UTCTIME_set +ASN1_UTCTIME_set_string +ASN1_verify +b2i_PrivateKey +b2i_PrivateKey_bio +b2i_PublicKey +b2i_PublicKey_bio +b2i_PVK_bio +BF_cbc_encrypt +BF_cfb64_encrypt +BF_decrypt +BF_ecb_encrypt +BF_encrypt +BF_ofb64_encrypt +BF_options +BF_set_key +BIO_accept +BIO_asn1_get_prefix +BIO_asn1_get_suffix +BIO_asn1_set_prefix +BIO_asn1_set_suffix +BIO_callback_ctrl +BIO_clear_flags +BIO_copy_next_retry +BIO_ctrl +BIO_ctrl_get_read_request +BIO_ctrl_get_write_guarantee +BIO_ctrl_pending +BIO_ctrl_reset_read_request +BIO_ctrl_wpending +BIO_debug_callback +BIO_dgram_is_sctp +BIO_dgram_non_fatal_error +BIO_dgram_sctp_msg_waiting +BIO_dgram_sctp_notification_cb +BIO_dgram_sctp_wait_for_dry +BIO_dump +BIO_dump_cb +BIO_dump_fp +BIO_dump_indent +BIO_dump_indent_cb +BIO_dump_indent_fp +BIO_dup_chain +BIO_f_asn1 +BIO_f_base64 +BIO_f_buffer +BIO_f_cipher +BIO_fd_non_fatal_error +BIO_fd_should_retry +BIO_find_type +BIO_f_linebuffer +BIO_f_md +BIO_f_nbio_test +BIO_f_null +BIO_free +BIO_free_all +BIO_f_reliable +BIO_f_ssl +BIO_f_zlib +BIO_get_accept_socket +BIO_get_callback +BIO_get_callback_arg +BIO_get_ex_data +BIO_get_ex_new_index +BIO_gethostbyname +BIO_get_host_ip +BIO_get_port +BIO_get_retry_BIO +BIO_get_retry_reason +BIO_gets +BIO_hex_string +BIO_indent +BIO_int_ctrl +BIO_method_name +BIO_method_type +BIO_new +BIO_new_accept +BIO_new_bio_pair +BIO_new_buffer_ssl_connect +BIO_new_CMS +BIO_new_connect +BIO_new_dgram +BIO_new_dgram_sctp +BIO_new_fd +BIO_new_file +BIO_new_fp +BIO_new_mem_buf +BIO_new_NDEF +BIO_new_PKCS7 +BIO_new_socket +BIO_new_ssl +BIO_new_ssl_connect +BIO_next +BIO_nread +BIO_nread0 +BIO_number_read +BIO_number_written +BIO_nwrite +BIO_nwrite0 +BIO_pop +BIO_ptr_ctrl +BIO_push +BIO_puts +BIO_read +BIO_read_filename +BIO_s_accept +BIO_s_bio +BIO_s_connect +BIO_s_datagram +BIO_s_datagram_sctp +BIO_set +BIO_set_callback +BIO_set_callback_arg +BIO_set_cipher +BIO_set_ex_data +BIO_set_flags +BIO_set_md +BIO_set_tcp_ndelay +BIO_s_fd +BIO_s_file +BIO_s_log +BIO_s_mem +BIO_s_null +BIO_sock_cleanup +BIO_sock_error +BIO_socket_ioctl +BIO_socket_nbio +BIO_sock_init +BIO_sock_non_fatal_error +BIO_sock_should_retry +BIO_ssl_copy_session_id +BIO_ssl_shutdown +BIO_s_socket +BIO_test_flags +BIO_vfree +BIO_write +BN_add +BN_add_word +bn_add_words +BN_asc2bn +BN_bin2bn +BN_BLINDING_convert +BN_BLINDING_convert_ex +BN_BLINDING_create_param +BN_BLINDING_free +BN_BLINDING_get_flags +BN_BLINDING_get_thread_id +BN_BLINDING_invert +BN_BLINDING_invert_ex +BN_BLINDING_new +BN_BLINDING_set_flags +BN_BLINDING_set_thread_id +BN_BLINDING_thread_id +BN_BLINDING_update +BN_bn2bin +BN_bn2dec +BN_bn2hex +BN_bn2mpi +BN_bntest_rand +BN_clear +BN_clear_bit +BN_clear_free +BN_cmp +BN_consttime_swap +BN_copy +BN_CTX_end +BN_CTX_free +BN_CTX_get +BN_CTX_init +BN_CTX_new +BN_CTX_start +BN_dec2bn +BN_div +BN_div_recp +BN_div_word +bn_div_words +BN_dup +bn_dup_expand +BN_exp +bn_expand2 +BN_free +BN_from_montgomery +BN_gcd +BN_GENCB_call +BN_generate_prime +BN_generate_prime_ex +BN_get0_nist_prime_192 +BN_get0_nist_prime_224 +BN_get0_nist_prime_256 +BN_get0_nist_prime_384 +BN_get0_nist_prime_521 +BN_get_params +BN_get_word +BN_GF2m_add +BN_GF2m_arr2poly +BN_GF2m_mod +BN_GF2m_mod_arr +BN_GF2m_mod_div +BN_GF2m_mod_div_arr +BN_GF2m_mod_exp +BN_GF2m_mod_exp_arr +BN_GF2m_mod_inv +BN_GF2m_mod_inv_arr +BN_GF2m_mod_mul +BN_GF2m_mod_mul_arr +BN_GF2m_mod_solve_quad +BN_GF2m_mod_solve_quad_arr +BN_GF2m_mod_sqr +BN_GF2m_mod_sqr_arr +BN_GF2m_mod_sqrt +BN_GF2m_mod_sqrt_arr +BN_GF2m_poly2arr +BN_hex2bn +BN_init +BN_is_bit_set +BN_is_prime +BN_is_prime_ex +BN_is_prime_fasttest +BN_is_prime_fasttest_ex +BN_kronecker +BN_lshift +BN_lshift1 +BN_mask_bits +BN_mod_add +BN_mod_add_quick +BN_mod_exp +BN_mod_exp2_mont +BN_mod_exp_mont +BN_mod_exp_mont_consttime +BN_mod_exp_mont_word +BN_mod_exp_recp +BN_mod_exp_simple +BN_mod_inverse +BN_mod_lshift +BN_mod_lshift1 +BN_mod_lshift1_quick +BN_mod_lshift_quick +BN_mod_mul +BN_mod_mul_montgomery +BN_mod_mul_reciprocal +BN_mod_sqr +BN_mod_sqrt +BN_mod_sub +BN_mod_sub_quick +BN_mod_word +BN_MONT_CTX_copy +BN_MONT_CTX_free +BN_MONT_CTX_init +BN_MONT_CTX_new +BN_MONT_CTX_set +BN_MONT_CTX_set_locked +BN_mpi2bn +BN_mul +bn_mul_add_words +BN_mul_word +bn_mul_words +BN_new +BN_nist_mod_192 +BN_nist_mod_224 +BN_nist_mod_256 +BN_nist_mod_384 +BN_nist_mod_521 +BN_nnmod +BN_num_bits +BN_num_bits_word +BN_options +BN_print +BN_print_fp +BN_pseudo_rand +BN_pseudo_rand_range +BN_rand +BN_rand_range +BN_reciprocal +BN_RECP_CTX_free +BN_RECP_CTX_init +BN_RECP_CTX_new +BN_RECP_CTX_set +BN_rshift +BN_rshift1 +BN_set_bit +BN_set_negative +BN_set_params +BN_set_word +BN_sqr +bn_sqr_words +BN_sub +BN_sub_word +bn_sub_words +BN_swap +BN_to_ASN1_ENUMERATED +BN_to_ASN1_INTEGER +BN_uadd +BN_ucmp +BN_usub +BN_value_one +BN_X931_derive_prime_ex +BN_X931_generate_prime_ex +BN_X931_generate_Xpq +BUF_memdup +BUF_MEM_free +BUF_MEM_grow +BUF_MEM_grow_clean +BUF_MEM_new +BUF_reverse +BUF_strdup +BUF_strlcat +BUF_strlcpy +BUF_strndup +BUF_strnlen +c2i_ASN1_BIT_STRING +c2i_ASN1_INTEGER +c2i_ASN1_OBJECT +Camellia_cbc_encrypt +Camellia_cfb128_encrypt +Camellia_cfb1_encrypt +Camellia_cfb8_encrypt +Camellia_ctr128_encrypt +Camellia_decrypt +Camellia_ecb_encrypt +Camellia_encrypt +Camellia_ofb128_encrypt +Camellia_set_key +CAST_cbc_encrypt +CAST_cfb64_encrypt +CAST_decrypt +CAST_ecb_encrypt +CAST_encrypt +CAST_ofb64_encrypt +CAST_set_key +check_defer +CMAC_CTX_cleanup +CMAC_CTX_copy +CMAC_CTX_free +CMAC_CTX_get0_cipher_ctx +CMAC_CTX_new +CMAC_Final +CMAC_Init +CMAC_resume +CMAC_Update +CMS_add0_cert +CMS_add0_CertificateChoices +CMS_add0_crl +CMS_add0_recipient_key +CMS_add0_recipient_password +CMS_add0_RevocationInfoChoice +CMS_add1_cert +CMS_add1_crl +CMS_add1_ReceiptRequest +CMS_add1_recipient_cert +CMS_add1_signer +CMS_add_smimecap +CMS_compress +CMS_data +CMS_data_create +CMS_dataFinal +CMS_dataInit +CMS_decrypt +CMS_decrypt_set1_key +CMS_decrypt_set1_password +CMS_decrypt_set1_pkey +CMS_digest_create +CMS_digest_verify +CMS_EncryptedData_decrypt +CMS_EncryptedData_encrypt +CMS_EncryptedData_set1_key +CMS_EnvelopedData_create +CMS_final +CMS_get0_content +CMS_get0_eContentType +CMS_get0_type +CMS_get1_ReceiptRequest +CMS_is_detached +CMS_ReceiptRequest_create0 +CMS_ReceiptRequest_get0_values +CMS_RecipientEncryptedKey_cert_cmp +CMS_RecipientEncryptedKey_get0_id +CMS_RecipientInfo_decrypt +CMS_RecipientInfo_encrypt +CMS_RecipientInfo_get0_pkey_ctx +CMS_RecipientInfo_kari_decrypt +CMS_RecipientInfo_kari_get0_alg +CMS_RecipientInfo_kari_get0_ctx +CMS_RecipientInfo_kari_get0_orig_id +CMS_RecipientInfo_kari_orig_id_cmp +CMS_RecipientInfo_kari_set0_pkey +CMS_RecipientInfo_kekri_get0_id +CMS_RecipientInfo_kekri_id_cmp +CMS_RecipientInfo_ktri_cert_cmp +CMS_RecipientInfo_ktri_get0_algs +CMS_RecipientInfo_ktri_get0_signer_id +CMS_RecipientInfo_set0_key +CMS_RecipientInfo_set0_password +CMS_RecipientInfo_set0_pkey +CMS_RecipientInfo_type +CMS_set1_eContentType +CMS_set1_signers_certs +CMS_set_detached +CMS_SharedInfo_encode +CMS_sign +CMS_signed_add1_attr +CMS_signed_add1_attr_by_NID +CMS_signed_add1_attr_by_OBJ +CMS_signed_add1_attr_by_txt +CMS_SignedData_init +CMS_signed_delete_attr +CMS_signed_get0_data_by_OBJ +CMS_signed_get_attr +CMS_signed_get_attr_by_NID +CMS_signed_get_attr_by_OBJ +CMS_signed_get_attr_count +CMS_SignerInfo_cert_cmp +CMS_SignerInfo_get0_algs +CMS_SignerInfo_get0_md_ctx +CMS_SignerInfo_get0_pkey_ctx +CMS_SignerInfo_get0_signature +CMS_SignerInfo_get0_signer_id +CMS_SignerInfo_set1_signer_cert +CMS_SignerInfo_sign +CMS_SignerInfo_verify +CMS_SignerInfo_verify_content +CMS_sign_receipt +CMS_stream +CMS_uncompress +CMS_unsigned_add1_attr +CMS_unsigned_add1_attr_by_NID +CMS_unsigned_add1_attr_by_OBJ +CMS_unsigned_add1_attr_by_txt +CMS_unsigned_delete_attr +CMS_unsigned_get0_data_by_OBJ +CMS_unsigned_get_attr +CMS_unsigned_get_attr_by_NID +CMS_unsigned_get_attr_by_OBJ +CMS_unsigned_get_attr_count +CMS_verify +CMS_verify_receipt +COMP_compress_block +COMP_CTX_free +COMP_CTX_new +COMP_expand_block +COMP_rle +COMP_zlib +COMP_zlib_cleanup +_CONF_add_string +_CONF_free_data +CONF_get1_default_config_file +_CONF_get_number +_CONF_get_section +_CONF_get_string +CONF_imodule_get_flags +CONF_imodule_get_module +CONF_imodule_get_name +CONF_imodule_get_usr_data +CONF_imodule_get_value +CONF_imodule_set_flags +CONF_imodule_set_usr_data +CONF_module_add +CONF_module_get_usr_data +CONF_module_set_usr_data +CONF_modules_finish +CONF_modules_free +CONF_modules_load +CONF_modules_load_file +CONF_modules_unload +_CONF_new_data +_CONF_new_section +CONF_parse_list +CONF_set_default_method +CONF_set_nconf +CRYPTO_128_unwrap +CRYPTO_128_wrap +CRYPTO_add_lock +CRYPTO_cbc128_decrypt +CRYPTO_cbc128_encrypt +CRYPTO_ccm128_aad +CRYPTO_ccm128_decrypt +CRYPTO_ccm128_decrypt_ccm64 +CRYPTO_ccm128_encrypt +CRYPTO_ccm128_encrypt_ccm64 +CRYPTO_ccm128_init +CRYPTO_ccm128_setiv +CRYPTO_ccm128_tag +CRYPTO_cfb128_1_encrypt +CRYPTO_cfb128_8_encrypt +CRYPTO_cfb128_encrypt +CRYPTO_cleanup_all_ex_data +CRYPTO_ctr128_encrypt +CRYPTO_ctr128_encrypt_ctr32 +CRYPTO_cts128_decrypt +CRYPTO_cts128_decrypt_block +CRYPTO_cts128_encrypt +CRYPTO_cts128_encrypt_block +CRYPTO_dbg_free +CRYPTO_dbg_get_options +CRYPTO_dbg_malloc +CRYPTO_dbg_realloc +CRYPTO_dbg_set_options +CRYPTO_destroy_dynlockid +CRYPTO_dup_ex_data +CRYPTO_ex_data_new_class +CRYPTO_free +CRYPTO_free_ex_data +CRYPTO_free_locked +CRYPTO_gcm128_aad +CRYPTO_gcm128_decrypt +CRYPTO_gcm128_decrypt_ctr32 +CRYPTO_gcm128_encrypt +CRYPTO_gcm128_encrypt_ctr32 +CRYPTO_gcm128_finish +CRYPTO_gcm128_init +CRYPTO_gcm128_new +CRYPTO_gcm128_release +CRYPTO_gcm128_setiv +CRYPTO_gcm128_tag +CRYPTO_get_add_lock_callback +CRYPTO_get_dynlock_create_callback +CRYPTO_get_dynlock_destroy_callback +CRYPTO_get_dynlock_lock_callback +CRYPTO_get_dynlock_value +CRYPTO_get_ex_data +CRYPTO_get_ex_data_implementation +CRYPTO_get_ex_new_index +CRYPTO_get_id_callback +CRYPTO_get_locked_mem_ex_functions +CRYPTO_get_locked_mem_functions +CRYPTO_get_locking_callback +CRYPTO_get_lock_name +CRYPTO_get_mem_debug_functions +CRYPTO_get_mem_debug_options +CRYPTO_get_mem_ex_functions +CRYPTO_get_mem_functions +CRYPTO_get_new_dynlockid +CRYPTO_get_new_lockid +CRYPTO_is_mem_check_on +CRYPTO_lock +CRYPTO_malloc +CRYPTO_malloc_locked +CRYPTO_memcmp +CRYPTO_mem_ctrl +CRYPTO_mem_leaks +CRYPTO_mem_leaks_cb +CRYPTO_mem_leaks_fp +CRYPTO_new_ex_data +CRYPTO_nistcts128_decrypt +CRYPTO_nistcts128_decrypt_block +CRYPTO_nistcts128_encrypt +CRYPTO_nistcts128_encrypt_block +CRYPTO_num_locks +CRYPTO_ofb128_encrypt +CRYPTO_pop_info +CRYPTO_push_info_ +CRYPTO_realloc +CRYPTO_realloc_clean +CRYPTO_remalloc +CRYPTO_remove_all_info +CRYPTO_set_add_lock_callback +CRYPTO_set_dynlock_create_callback +CRYPTO_set_dynlock_destroy_callback +CRYPTO_set_dynlock_lock_callback +CRYPTO_set_ex_data +CRYPTO_set_ex_data_implementation +CRYPTO_set_id_callback +CRYPTO_set_locked_mem_ex_functions +CRYPTO_set_locked_mem_functions +CRYPTO_set_locking_callback +CRYPTO_set_mem_debug_functions +CRYPTO_set_mem_debug_options +CRYPTO_set_mem_ex_functions +CRYPTO_set_mem_functions +CRYPTO_strdup +CRYPTO_thread_id +CRYPTO_THREADID_cmp +CRYPTO_THREADID_cpy +CRYPTO_THREADID_current +CRYPTO_THREADID_get_callback +CRYPTO_THREADID_hash +CRYPTO_THREADID_set_callback +CRYPTO_THREADID_set_numeric +CRYPTO_THREADID_set_pointer +CRYPTO_xts128_encrypt +d2i_ASN1_BOOLEAN +d2i_ASN1_bytes +d2i_ASN1_OBJECT +d2i_ASN1_type_bytes +d2i_ASN1_UINTEGER +d2i_AutoPrivateKey +d2i_CMS_bio +d2i_DHparams +d2i_DHxparams +d2i_DSAparams +d2i_DSAPrivateKey +d2i_DSAPrivateKey_bio +d2i_DSAPrivateKey_fp +d2i_DSA_PUBKEY +d2i_DSA_PUBKEY_bio +d2i_DSA_PUBKEY_fp +d2i_DSAPublicKey +d2i_DSA_SIG +d2i_ECDSA_SIG +d2i_ECParameters +d2i_ECPKParameters +d2i_ECPrivateKey +d2i_ECPrivateKey_bio +d2i_ECPrivateKey_fp +d2i_EC_PUBKEY +d2i_EC_PUBKEY_bio +d2i_EC_PUBKEY_fp +d2i_ESS_CERT_ID +d2i_ESS_ISSUER_SERIAL +d2i_ESS_SIGNING_CERT +d2i_Netscape_RSA +d2i_PKCS12_bio +d2i_PKCS12_fp +d2i_PKCS7_bio +d2i_PKCS7_fp +d2i_PKCS8_bio +d2i_PKCS8_fp +d2i_PKCS8PrivateKey_bio +d2i_PKCS8PrivateKey_fp +d2i_PKCS8_PRIV_KEY_INFO_bio +d2i_PKCS8_PRIV_KEY_INFO_fp +d2i_PrivateKey +d2i_PrivateKey_bio +d2i_PrivateKey_fp +d2i_PUBKEY +d2i_PUBKEY_bio +d2i_PUBKEY_fp +d2i_PublicKey +d2i_RSA_NET +d2i_RSAPrivateKey_bio +d2i_RSAPrivateKey_fp +d2i_RSA_PUBKEY +d2i_RSA_PUBKEY_bio +d2i_RSA_PUBKEY_fp +d2i_RSAPublicKey_bio +d2i_RSAPublicKey_fp +d2i_SSL_SESSION +d2i_TS_ACCURACY +d2i_TS_MSG_IMPRINT +d2i_TS_MSG_IMPRINT_bio +d2i_TS_MSG_IMPRINT_fp +d2i_TS_REQ +d2i_TS_REQ_bio +d2i_TS_REQ_fp +d2i_TS_RESP +d2i_TS_RESP_bio +d2i_TS_RESP_fp +d2i_TS_STATUS_INFO +d2i_TS_TST_INFO +d2i_TS_TST_INFO_bio +d2i_TS_TST_INFO_fp +d2i_X509_AUX +d2i_X509_bio +d2i_X509_CRL_bio +d2i_X509_CRL_fp +d2i_X509_fp +d2i_X509_PKEY +d2i_X509_REQ_bio +d2i_X509_REQ_fp +DES_cbc_cksum +DES_cbc_encrypt +DES_cfb64_encrypt +DES_cfb_encrypt +DES_check_key_parity +DES_crypt +DES_decrypt3 +DES_ecb3_encrypt +DES_ecb_encrypt +DES_ede3_cbc_encrypt +DES_ede3_cbcm_encrypt +DES_ede3_cfb64_encrypt +DES_ede3_cfb_encrypt +DES_ede3_ofb64_encrypt +DES_enc_read +DES_encrypt1 +DES_encrypt2 +DES_encrypt3 +DES_enc_write +DES_fcrypt +DES_is_weak_key +DES_key_sched +DES_ncbc_encrypt +DES_ofb64_encrypt +DES_ofb_encrypt +DES_options +DES_pcbc_encrypt +DES_quad_cksum +DES_random_key +DES_read_2passwords +DES_read_password +DES_set_key +DES_set_key_checked +DES_set_key_unchecked +DES_set_odd_parity +DES_string_to_2keys +DES_string_to_key +DES_xcbc_encrypt +DH_check +DH_check_pub_key +DH_compute_key +DH_compute_key_padded +DH_free +DH_generate_key +DH_generate_parameters +DH_generate_parameters_ex +DH_get_1024_160 +DH_get_2048_224 +DH_get_2048_256 +DH_get_default_method +DH_get_ex_data +DH_get_ex_new_index +DH_KDF_X9_42 +DH_new +DH_new_method +DH_OpenSSL +DHparams_dup +DHparams_print +DHparams_print_fp +DH_set_default_method +DH_set_ex_data +DH_set_method +DH_size +DH_up_ref +DIST_POINT_set_dpname +DSA_do_sign +DSA_do_verify +DSA_dup_DH +DSA_free +DSA_generate_key +DSA_generate_parameters +DSA_generate_parameters_ex +DSA_get_default_method +DSA_get_ex_data +DSA_get_ex_new_index +DSA_new +DSA_new_method +DSA_OpenSSL +DSAparams_dup +DSAparams_print +DSAparams_print_fp +DSA_print +DSA_print_fp +DSA_set_default_method +DSA_set_ex_data +DSA_set_method +DSA_SIG_free +DSA_sign +DSA_SIG_new +DSA_sign_setup +DSA_size +DSA_up_ref +DSA_verify +DSO_bind_func +DSO_bind_var +DSO_convert_filename +DSO_ctrl +DSO_flags +DSO_free +DSO_get_default_method +DSO_get_filename +DSO_get_loaded_filename +DSO_get_method +DSO_global_lookup +DSO_load +DSO_merge +DSO_METHOD_beos +DSO_METHOD_dl +DSO_METHOD_dlfcn +DSO_METHOD_null +DSO_METHOD_openssl +DSO_METHOD_vms +DSO_METHOD_win32 +DSO_new +DSO_new_method +DSO_pathbyaddr +DSO_set_default_method +DSO_set_filename +DSO_set_method +DSO_set_name_converter +DSO_up_ref +DTLS_client_method +DTLS_method +DTLS_server_method +DTLSv1_2_client_method +DTLSv1_2_method +DTLSv1_2_server_method +DTLSv1_client_method +DTLSv1_method +DTLSv1_server_method +ebcdic2ascii +EC_curve_nid2nist +EC_curve_nist2nid +ECDH_compute_key +ECDH_get_default_method +ECDH_get_ex_data +ECDH_get_ex_new_index +ECDH_KDF_X9_62 +ECDH_OpenSSL +ECDH_set_default_method +ECDH_set_ex_data +ECDH_set_method +ECDSA_do_sign +ECDSA_do_sign_ex +ECDSA_do_verify +ECDSA_get_default_method +ECDSA_get_ex_data +ECDSA_get_ex_new_index +ECDSA_METHOD_free +ECDSA_METHOD_get_app_data +ECDSA_METHOD_new +ECDSA_METHOD_set_app_data +ECDSA_METHOD_set_flags +ECDSA_METHOD_set_name +ECDSA_METHOD_set_sign +ECDSA_METHOD_set_sign_setup +ECDSA_METHOD_set_verify +ECDSA_OpenSSL +ECDSA_set_default_method +ECDSA_set_ex_data +ECDSA_set_method +ECDSA_SIG_free +ECDSA_sign +ECDSA_SIG_new +ECDSA_sign_ex +ECDSA_sign_setup +ECDSA_size +ECDSA_verify +EC_get_builtin_curves +EC_GF2m_simple_method +EC_GFp_mont_method +EC_GFp_nist_method +EC_GFp_nistp224_method +EC_GFp_nistp256_method +EC_GFp_nistp521_method +EC_GFp_simple_method +EC_GROUP_check +EC_GROUP_check_discriminant +EC_GROUP_clear_free +EC_GROUP_cmp +EC_GROUP_copy +EC_GROUP_dup +EC_GROUP_free +EC_GROUP_get0_generator +EC_GROUP_get0_seed +EC_GROUP_get_asn1_flag +EC_GROUP_get_basis_type +EC_GROUP_get_cofactor +EC_GROUP_get_curve_GF2m +EC_GROUP_get_curve_GFp +EC_GROUP_get_curve_name +EC_GROUP_get_degree +EC_GROUP_get_mont_data +EC_GROUP_get_order +EC_GROUP_get_pentanomial_basis +EC_GROUP_get_point_conversion_form +EC_GROUP_get_seed_len +EC_GROUP_get_trinomial_basis +EC_GROUP_have_precompute_mult +EC_GROUP_method_of +EC_GROUP_new +EC_GROUP_new_by_curve_name +EC_GROUP_new_curve_GF2m +EC_GROUP_new_curve_GFp +EC_GROUP_precompute_mult +EC_GROUP_set_asn1_flag +EC_GROUP_set_curve_GF2m +EC_GROUP_set_curve_GFp +EC_GROUP_set_curve_name +EC_GROUP_set_generator +EC_GROUP_set_point_conversion_form +EC_GROUP_set_seed +EC_KEY_check_key +EC_KEY_clear_flags +EC_KEY_copy +EC_KEY_dup +EC_KEY_free +EC_KEY_generate_key +EC_KEY_get0_group +EC_KEY_get0_private_key +EC_KEY_get0_public_key +EC_KEY_get_conv_form +EC_KEY_get_enc_flags +EC_KEY_get_flags +EC_KEY_get_key_method_data +EC_KEY_insert_key_method_data +EC_KEY_new +EC_KEY_new_by_curve_name +EC_KEY_precompute_mult +EC_KEY_print +EC_KEY_print_fp +EC_KEY_set_asn1_flag +EC_KEY_set_conv_form +EC_KEY_set_enc_flags +EC_KEY_set_flags +EC_KEY_set_group +EC_KEY_set_private_key +EC_KEY_set_public_key +EC_KEY_set_public_key_affine_coordinates +EC_KEY_up_ref +EC_METHOD_get_field_type +ECParameters_print +ECParameters_print_fp +ECPKParameters_print +ECPKParameters_print_fp +EC_POINT_add +EC_POINT_bn2point +EC_POINT_clear_free +EC_POINT_cmp +EC_POINT_copy +EC_POINT_dbl +EC_POINT_dup +EC_POINT_free +EC_POINT_get_affine_coordinates_GF2m +EC_POINT_get_affine_coordinates_GFp +EC_POINT_get_Jprojective_coordinates_GFp +EC_POINT_hex2point +EC_POINT_invert +EC_POINT_is_at_infinity +EC_POINT_is_on_curve +EC_POINT_make_affine +EC_POINT_method_of +EC_POINT_mul +EC_POINT_new +EC_POINT_oct2point +EC_POINT_point2bn +EC_POINT_point2hex +EC_POINT_point2oct +EC_POINT_set_affine_coordinates_GF2m +EC_POINT_set_affine_coordinates_GFp +EC_POINT_set_compressed_coordinates_GF2m +EC_POINT_set_compressed_coordinates_GFp +EC_POINT_set_Jprojective_coordinates_GFp +EC_POINT_set_to_infinity +EC_POINTs_make_affine +EC_POINTs_mul +ENGINE_add +ENGINE_add_conf_module +ENGINE_by_id +ENGINE_cleanup +ENGINE_cmd_is_executable +ENGINE_ctrl +ENGINE_ctrl_cmd +ENGINE_ctrl_cmd_string +ENGINE_finish +ENGINE_free +ENGINE_get_cipher +ENGINE_get_cipher_engine +ENGINE_get_ciphers +ENGINE_get_cmd_defns +ENGINE_get_ctrl_function +ENGINE_get_default_DH +ENGINE_get_default_DSA +ENGINE_get_default_ECDH +ENGINE_get_default_ECDSA +ENGINE_get_default_RAND +ENGINE_get_default_RSA +ENGINE_get_destroy_function +ENGINE_get_DH +ENGINE_get_digest +ENGINE_get_digest_engine +ENGINE_get_digests +ENGINE_get_DSA +ENGINE_get_ECDH +ENGINE_get_ECDSA +ENGINE_get_ex_data +ENGINE_get_ex_new_index +ENGINE_get_finish_function +ENGINE_get_first +ENGINE_get_flags +ENGINE_get_id +ENGINE_get_init_function +ENGINE_get_last +ENGINE_get_load_privkey_function +ENGINE_get_load_pubkey_function +ENGINE_get_name +ENGINE_get_next +ENGINE_get_pkey_asn1_meth +ENGINE_get_pkey_asn1_meth_engine +ENGINE_get_pkey_asn1_meths +ENGINE_get_pkey_asn1_meth_str +ENGINE_get_pkey_meth +ENGINE_get_pkey_meth_engine +ENGINE_get_pkey_meths +ENGINE_get_prev +ENGINE_get_RAND +ENGINE_get_RSA +ENGINE_get_ssl_client_cert_function +ENGINE_get_static_state +ENGINE_get_STORE +ENGINE_get_table_flags +ENGINE_init +ENGINE_load_4758cca +ENGINE_load_aep +ENGINE_load_atalla +ENGINE_load_builtin_engines +ENGINE_load_capi +ENGINE_load_chil +ENGINE_load_cryptodev +ENGINE_load_cswift +ENGINE_load_dynamic +ENGINE_load_gmp +ENGINE_load_gost +ENGINE_load_nuron +ENGINE_load_openssl +ENGINE_load_padlock +ENGINE_load_private_key +ENGINE_load_public_key +ENGINE_load_rdrand +ENGINE_load_ssl_client_cert +ENGINE_load_sureware +ENGINE_load_ubsec +ENGINE_new +ENGINE_pkey_asn1_find_str +ENGINE_register_all_ciphers +ENGINE_register_all_complete +ENGINE_register_all_DH +ENGINE_register_all_digests +ENGINE_register_all_DSA +ENGINE_register_all_ECDH +ENGINE_register_all_ECDSA +ENGINE_register_all_pkey_asn1_meths +ENGINE_register_all_pkey_meths +ENGINE_register_all_RAND +ENGINE_register_all_RSA +ENGINE_register_all_STORE +ENGINE_register_ciphers +ENGINE_register_complete +ENGINE_register_DH +ENGINE_register_digests +ENGINE_register_DSA +ENGINE_register_ECDH +ENGINE_register_ECDSA +ENGINE_register_pkey_asn1_meths +ENGINE_register_pkey_meths +ENGINE_register_RAND +ENGINE_register_RSA +ENGINE_register_STORE +ENGINE_remove +ENGINE_set_ciphers +ENGINE_set_cmd_defns +ENGINE_set_ctrl_function +ENGINE_set_default +ENGINE_set_default_ciphers +ENGINE_set_default_DH +ENGINE_set_default_digests +ENGINE_set_default_DSA +ENGINE_set_default_ECDH +ENGINE_set_default_ECDSA +ENGINE_set_default_pkey_asn1_meths +ENGINE_set_default_pkey_meths +ENGINE_set_default_RAND +ENGINE_set_default_RSA +ENGINE_set_default_string +ENGINE_set_destroy_function +ENGINE_set_DH +ENGINE_set_digests +ENGINE_set_DSA +ENGINE_set_ECDH +ENGINE_set_ECDSA +ENGINE_set_ex_data +ENGINE_set_finish_function +ENGINE_set_flags +ENGINE_set_id +ENGINE_set_init_function +ENGINE_set_load_privkey_function +ENGINE_set_load_pubkey_function +ENGINE_set_load_ssl_client_cert_function +ENGINE_set_name +ENGINE_set_pkey_asn1_meths +ENGINE_set_pkey_meths +ENGINE_set_RAND +ENGINE_set_RSA +ENGINE_set_STORE +ENGINE_set_table_flags +ENGINE_setup_bsd_cryptodev +ENGINE_unregister_ciphers +ENGINE_unregister_DH +ENGINE_unregister_digests +ENGINE_unregister_DSA +ENGINE_unregister_ECDH +ENGINE_unregister_ECDSA +ENGINE_unregister_pkey_asn1_meths +ENGINE_unregister_pkey_meths +ENGINE_unregister_RAND +ENGINE_unregister_RSA +ENGINE_unregister_STORE +ENGINE_up_ref +ERR_add_error_data +ERR_add_error_vdata +ERR_clear_error +ERR_error_string +ERR_error_string_n +ERR_free_strings +ERR_func_error_string +ERR_get_error +ERR_get_error_line +ERR_get_error_line_data +ERR_get_implementation +ERR_get_next_error_library +ERR_get_state +ERR_lib_error_string +ERR_load_ASN1_strings +ERR_load_BIO_strings +ERR_load_BN_strings +ERR_load_BUF_strings +ERR_load_CMS_strings +ERR_load_COMP_strings +ERR_load_CONF_strings +ERR_load_crypto_strings +ERR_load_CRYPTO_strings +ERR_load_DH_strings +ERR_load_DSA_strings +ERR_load_DSO_strings +ERR_load_ECDH_strings +ERR_load_ECDSA_strings +ERR_load_EC_strings +ERR_load_ENGINE_strings +ERR_load_ERR_strings +ERR_load_EVP_strings +ERR_load_OBJ_strings +ERR_load_OCSP_strings +ERR_load_PEM_strings +ERR_load_PKCS12_strings +ERR_load_PKCS7_strings +ERR_load_RAND_strings +ERR_load_RSA_strings +ERR_load_SSL_strings +ERR_load_strings +ERR_load_TS_strings +ERR_load_UI_strings +ERR_load_X509_strings +ERR_load_X509V3_strings +ERR_peek_error +ERR_peek_error_line +ERR_peek_error_line_data +ERR_peek_last_error +ERR_peek_last_error_line +ERR_peek_last_error_line_data +ERR_pop_to_mark +ERR_print_errors +ERR_print_errors_cb +ERR_print_errors_fp +ERR_put_error +ERR_reason_error_string +ERR_remove_state +ERR_remove_thread_state +ERR_set_error_data +ERR_set_implementation +ERR_set_mark +ERR_unload_strings +ESS_CERT_ID_dup +ESS_CERT_ID_free +ESS_CERT_ID_new +ESS_ISSUER_SERIAL_dup +ESS_ISSUER_SERIAL_free +ESS_ISSUER_SERIAL_new +ESS_SIGNING_CERT_dup +ESS_SIGNING_CERT_free +ESS_SIGNING_CERT_new +EVP_add_alg_module +EVP_add_cipher +EVP_add_digest +EVP_aes_128_cbc +EVP_aes_128_cbc_hmac_sha1 +EVP_aes_128_cbc_hmac_sha256 +EVP_aes_128_ccm +EVP_aes_128_cfb1 +EVP_aes_128_cfb128 +EVP_aes_128_cfb8 +EVP_aes_128_ctr +EVP_aes_128_ecb +EVP_aes_128_gcm +EVP_aes_128_ofb +EVP_aes_128_wrap +EVP_aes_128_xts +EVP_aes_192_cbc +EVP_aes_192_ccm +EVP_aes_192_cfb1 +EVP_aes_192_cfb128 +EVP_aes_192_cfb8 +EVP_aes_192_ctr +EVP_aes_192_ecb +EVP_aes_192_gcm +EVP_aes_192_ofb +EVP_aes_192_wrap +EVP_aes_256_cbc +EVP_aes_256_cbc_hmac_sha1 +EVP_aes_256_cbc_hmac_sha256 +EVP_aes_256_ccm +EVP_aes_256_cfb1 +EVP_aes_256_cfb128 +EVP_aes_256_cfb8 +EVP_aes_256_ctr +EVP_aes_256_ecb +EVP_aes_256_gcm +EVP_aes_256_ofb +EVP_aes_256_wrap +EVP_aes_256_xts +EVP_bf_cbc +EVP_bf_cfb64 +EVP_bf_ecb +EVP_bf_ofb +EVP_BytesToKey +EVP_camellia_128_cbc +EVP_camellia_128_cfb1 +EVP_camellia_128_cfb128 +EVP_camellia_128_cfb8 +EVP_camellia_128_ecb +EVP_camellia_128_ofb +EVP_camellia_192_cbc +EVP_camellia_192_cfb1 +EVP_camellia_192_cfb128 +EVP_camellia_192_cfb8 +EVP_camellia_192_ecb +EVP_camellia_192_ofb +EVP_camellia_256_cbc +EVP_camellia_256_cfb1 +EVP_camellia_256_cfb128 +EVP_camellia_256_cfb8 +EVP_camellia_256_ecb +EVP_camellia_256_ofb +EVP_cast5_cbc +EVP_cast5_cfb64 +EVP_cast5_ecb +EVP_cast5_ofb +EVP_Cipher +EVP_CIPHER_asn1_to_param +EVP_CIPHER_block_size +EVP_CIPHER_CTX_block_size +EVP_CIPHER_CTX_cipher +EVP_CIPHER_CTX_cleanup +EVP_CIPHER_CTX_clear_flags +EVP_CIPHER_CTX_copy +EVP_CIPHER_CTX_ctrl +EVP_CIPHER_CTX_flags +EVP_CIPHER_CTX_free +EVP_CIPHER_CTX_get_app_data +EVP_CIPHER_CTX_init +EVP_CIPHER_CTX_iv_length +EVP_CIPHER_CTX_key_length +EVP_CIPHER_CTX_new +EVP_CIPHER_CTX_nid +EVP_CIPHER_CTX_rand_key +EVP_CIPHER_CTX_set_app_data +EVP_CIPHER_CTX_set_flags +EVP_CIPHER_CTX_set_key_length +EVP_CIPHER_CTX_set_padding +EVP_CIPHER_CTX_test_flags +EVP_CIPHER_do_all +EVP_CIPHER_do_all_sorted +EVP_CipherFinal +EVP_CipherFinal_ex +EVP_CIPHER_flags +EVP_CIPHER_get_asn1_iv +EVP_CipherInit +EVP_CipherInit_ex +EVP_CIPHER_iv_length +EVP_CIPHER_key_length +EVP_CIPHER_nid +EVP_CIPHER_param_to_asn1 +EVP_CIPHER_set_asn1_iv +EVP_CIPHER_type +EVP_CipherUpdate +EVP_cleanup +EVP_DecodeBlock +EVP_DecodeFinal +EVP_DecodeInit +EVP_DecodeUpdate +EVP_DecryptFinal +EVP_DecryptFinal_ex +EVP_DecryptInit +EVP_DecryptInit_ex +EVP_DecryptUpdate +EVP_des_cbc +EVP_des_cfb1 +EVP_des_cfb64 +EVP_des_cfb8 +EVP_des_ecb +EVP_des_ede +EVP_des_ede3 +EVP_des_ede3_cbc +EVP_des_ede3_cfb1 +EVP_des_ede3_cfb64 +EVP_des_ede3_cfb8 +EVP_des_ede3_ecb +EVP_des_ede3_ofb +EVP_des_ede3_wrap +EVP_des_ede_cbc +EVP_des_ede_cfb64 +EVP_des_ede_ecb +EVP_des_ede_ofb +EVP_des_ofb +EVP_desx_cbc +EVP_Digest +EVP_DigestFinal +EVP_DigestFinal_ex +EVP_DigestInit +EVP_DigestInit_ex +EVP_DigestSignFinal +EVP_DigestSignInit +EVP_DigestUpdate +EVP_DigestVerifyFinal +EVP_DigestVerifyInit +EVP_dss +EVP_dss1 +EVP_ecdsa +EVP_enc_null +EVP_EncodeBlock +EVP_EncodeFinal +EVP_EncodeInit +EVP_EncodeUpdate +EVP_EncryptFinal +EVP_EncryptFinal_ex +EVP_EncryptInit +EVP_EncryptInit_ex +EVP_EncryptUpdate +EVP_get_cipherbyname +EVP_get_digestbyname +EVP_get_pw_prompt +EVP_idea_cbc +EVP_idea_cfb64 +EVP_idea_ecb +EVP_idea_ofb +EVP_md2 +EVP_md4 +EVP_md5 +EVP_MD_block_size +EVP_mdc2 +EVP_MD_CTX_cleanup +EVP_MD_CTX_clear_flags +EVP_MD_CTX_copy +EVP_MD_CTX_copy_ex +EVP_MD_CTX_create +EVP_MD_CTX_destroy +EVP_MD_CTX_init +EVP_MD_CTX_md +EVP_MD_CTX_set_flags +EVP_MD_CTX_test_flags +EVP_MD_do_all +EVP_MD_do_all_sorted +EVP_MD_flags +EVP_md_null +EVP_MD_pkey_type +EVP_MD_size +EVP_MD_type +EVP_OpenFinal +EVP_OpenInit +EVP_PBE_alg_add +EVP_PBE_alg_add_type +EVP_PBE_CipherInit +EVP_PBE_cleanup +EVP_PBE_find +EVP_PKCS82PKEY +EVP_PKEY2PKCS8 +EVP_PKEY2PKCS8_broken +EVP_PKEY_add1_attr +EVP_PKEY_add1_attr_by_NID +EVP_PKEY_add1_attr_by_OBJ +EVP_PKEY_add1_attr_by_txt +EVP_PKEY_asn1_add0 +EVP_PKEY_asn1_add_alias +EVP_PKEY_asn1_copy +EVP_PKEY_asn1_find +EVP_PKEY_asn1_find_str +EVP_PKEY_asn1_free +EVP_PKEY_asn1_get0 +EVP_PKEY_asn1_get0_info +EVP_PKEY_asn1_get_count +EVP_PKEY_asn1_new +EVP_PKEY_asn1_set_ctrl +EVP_PKEY_asn1_set_free +EVP_PKEY_asn1_set_item +EVP_PKEY_asn1_set_param +EVP_PKEY_asn1_set_private +EVP_PKEY_asn1_set_public +EVP_PKEY_assign +EVP_PKEY_base_id +EVP_PKEY_bits +EVP_PKEY_cmp +EVP_PKEY_cmp_parameters +EVP_PKEY_copy_parameters +EVP_PKEY_CTX_ctrl +EVP_PKEY_CTX_ctrl_str +EVP_PKEY_CTX_dup +EVP_PKEY_CTX_free +EVP_PKEY_CTX_get0_peerkey +EVP_PKEY_CTX_get0_pkey +EVP_PKEY_CTX_get_app_data +EVP_PKEY_CTX_get_cb +EVP_PKEY_CTX_get_data +EVP_PKEY_CTX_get_keygen_info +EVP_PKEY_CTX_get_operation +EVP_PKEY_CTX_new +EVP_PKEY_CTX_new_id +EVP_PKEY_CTX_set0_keygen_info +EVP_PKEY_CTX_set_app_data +EVP_PKEY_CTX_set_cb +EVP_PKEY_CTX_set_data +EVP_PKEY_decrypt +EVP_PKEY_decrypt_init +EVP_PKEY_decrypt_old +EVP_PKEY_delete_attr +EVP_PKEY_derive +EVP_PKEY_derive_init +EVP_PKEY_derive_set_peer +EVP_PKEY_encrypt +EVP_PKEY_encrypt_init +EVP_PKEY_encrypt_old +EVP_PKEY_free +EVP_PKEY_get0 +EVP_PKEY_get0_asn1 +EVP_PKEY_get1_DH +EVP_PKEY_get1_DSA +EVP_PKEY_get1_EC_KEY +EVP_PKEY_get1_RSA +EVP_PKEY_get_attr +EVP_PKEY_get_attr_by_NID +EVP_PKEY_get_attr_by_OBJ +EVP_PKEY_get_attr_count +EVP_PKEY_get_default_digest_nid +EVP_PKEY_id +EVP_PKEY_keygen +EVP_PKEY_keygen_init +EVP_PKEY_meth_add0 +EVP_PKEY_meth_copy +EVP_PKEY_meth_find +EVP_PKEY_meth_free +EVP_PKEY_meth_get0_info +EVP_PKEY_meth_new +EVP_PKEY_meth_set_cleanup +EVP_PKEY_meth_set_copy +EVP_PKEY_meth_set_ctrl +EVP_PKEY_meth_set_decrypt +EVP_PKEY_meth_set_derive +EVP_PKEY_meth_set_encrypt +EVP_PKEY_meth_set_init +EVP_PKEY_meth_set_keygen +EVP_PKEY_meth_set_paramgen +EVP_PKEY_meth_set_sign +EVP_PKEY_meth_set_signctx +EVP_PKEY_meth_set_verify +EVP_PKEY_meth_set_verifyctx +EVP_PKEY_meth_set_verify_recover +EVP_PKEY_missing_parameters +EVP_PKEY_new +EVP_PKEY_new_mac_key +EVP_PKEY_paramgen +EVP_PKEY_paramgen_init +EVP_PKEY_print_params +EVP_PKEY_print_private +EVP_PKEY_print_public +EVP_PKEY_save_parameters +EVP_PKEY_set1_DH +EVP_PKEY_set1_DSA +EVP_PKEY_set1_EC_KEY +EVP_PKEY_set1_RSA +EVP_PKEY_set_type +EVP_PKEY_set_type_str +EVP_PKEY_sign +EVP_PKEY_sign_init +EVP_PKEY_size +EVP_PKEY_type +EVP_PKEY_verify +EVP_PKEY_verify_init +EVP_PKEY_verify_recover +EVP_PKEY_verify_recover_init +EVP_rc2_40_cbc +EVP_rc2_64_cbc +EVP_rc2_cbc +EVP_rc2_cfb64 +EVP_rc2_ecb +EVP_rc2_ofb +EVP_rc4 +EVP_rc4_40 +EVP_rc4_hmac_md5 +EVP_rc5_32_12_16_cbc +EVP_rc5_32_12_16_cfb64 +EVP_rc5_32_12_16_ecb +EVP_rc5_32_12_16_ofb +EVP_read_pw_string +EVP_read_pw_string_min +EVP_ripemd160 +EVP_SealFinal +EVP_SealInit +EVP_seed_cbc +EVP_seed_cfb128 +EVP_seed_ecb +EVP_seed_ofb +EVP_set_pw_prompt +EVP_sha +EVP_sha1 +EVP_sha224 +EVP_sha256 +EVP_sha384 +EVP_sha512 +EVP_SignFinal +EVP_VerifyFinal +EVP_whirlpool +FIPS_mode +FIPS_mode_set +GENERAL_NAME_cmp +GENERAL_NAME_dup +GENERAL_NAME_get0_otherName +GENERAL_NAME_get0_value +GENERAL_NAME_print +GENERAL_NAME_set0_othername +GENERAL_NAME_set0_value +get_rfc2409_prime_1024 +get_rfc2409_prime_768 +get_rfc3526_prime_1536 +get_rfc3526_prime_2048 +get_rfc3526_prime_3072 +get_rfc3526_prime_4096 +get_rfc3526_prime_6144 +get_rfc3526_prime_8192 +hex_to_string +HMAC +HMAC_CTX_cleanup +HMAC_CTX_copy +HMAC_CTX_init +HMAC_CTX_set_flags +HMAC_Final +HMAC_Init +HMAC_Init_ex +HMAC_Update +i2a_ACCESS_DESCRIPTION +i2a_ASN1_ENUMERATED +i2a_ASN1_INTEGER +i2a_ASN1_OBJECT +i2a_ASN1_STRING +i2b_PrivateKey_bio +i2b_PublicKey_bio +i2b_PVK_bio +i2c_ASN1_BIT_STRING +i2c_ASN1_INTEGER +i2d_ASN1_bio_stream +i2d_ASN1_BOOLEAN +i2d_ASN1_bytes +i2d_ASN1_OBJECT +i2d_CMS_bio +i2d_CMS_bio_stream +i2d_DHparams +i2d_DHxparams +i2d_DSAparams +i2d_DSAPrivateKey +i2d_DSAPrivateKey_bio +i2d_DSAPrivateKey_fp +i2d_DSA_PUBKEY +i2d_DSA_PUBKEY_bio +i2d_DSA_PUBKEY_fp +i2d_DSAPublicKey +i2d_DSA_SIG +i2d_ECDSA_SIG +i2d_ECParameters +i2d_ECPKParameters +i2d_ECPrivateKey +i2d_ECPrivateKey_bio +i2d_ECPrivateKey_fp +i2d_EC_PUBKEY +i2d_EC_PUBKEY_bio +i2d_EC_PUBKEY_fp +i2d_ESS_CERT_ID +i2d_ESS_ISSUER_SERIAL +i2d_ESS_SIGNING_CERT +i2d_Netscape_RSA +i2d_PKCS12_bio +i2d_PKCS12_fp +i2d_PKCS7_bio +i2d_PKCS7_bio_stream +i2d_PKCS7_fp +i2d_PKCS8_bio +i2d_PKCS8_fp +i2d_PKCS8PrivateKey_bio +i2d_PKCS8PrivateKey_fp +i2d_PKCS8PrivateKeyInfo_bio +i2d_PKCS8PrivateKeyInfo_fp +i2d_PKCS8PrivateKey_nid_bio +i2d_PKCS8PrivateKey_nid_fp +i2d_PKCS8_PRIV_KEY_INFO_bio +i2d_PKCS8_PRIV_KEY_INFO_fp +i2d_PrivateKey +i2d_PrivateKey_bio +i2d_PrivateKey_fp +i2d_PUBKEY +i2d_PUBKEY_bio +i2d_PUBKEY_fp +i2d_PublicKey +i2d_re_X509_tbs +i2d_RSA_NET +i2d_RSAPrivateKey_bio +i2d_RSAPrivateKey_fp +i2d_RSA_PUBKEY +i2d_RSA_PUBKEY_bio +i2d_RSA_PUBKEY_fp +i2d_RSAPublicKey_bio +i2d_RSAPublicKey_fp +i2d_SSL_SESSION +i2d_TS_ACCURACY +i2d_TS_MSG_IMPRINT +i2d_TS_MSG_IMPRINT_bio +i2d_TS_MSG_IMPRINT_fp +i2d_TS_REQ +i2d_TS_REQ_bio +i2d_TS_REQ_fp +i2d_TS_RESP +i2d_TS_RESP_bio +i2d_TS_RESP_fp +i2d_TS_STATUS_INFO +i2d_TS_TST_INFO +i2d_TS_TST_INFO_bio +i2d_TS_TST_INFO_fp +i2d_X509_AUX +i2d_X509_bio +i2d_X509_CRL_bio +i2d_X509_CRL_fp +i2d_X509_fp +i2d_X509_PKEY +i2d_X509_REQ_bio +i2d_X509_REQ_fp +i2o_ECPublicKey +i2s_ASN1_ENUMERATED +i2s_ASN1_ENUMERATED_TABLE +i2s_ASN1_INTEGER +i2s_ASN1_OCTET_STRING +i2t_ASN1_OBJECT +kssl_build_principal_2 +kssl_cget_tkt +kssl_check_authent +kssl_ctx_free +kssl_ctx_get0_client_princ +kssl_ctx_new +kssl_ctx_setkey +kssl_ctx_setprinc +kssl_ctx_setstring +kssl_ctx_show +kssl_err_set +kssl_krb5_free_data_contents +kssl_sget_tkt +kssl_skip_confound +kssl_validate_times +lh_delete +lh_doall +lh_doall_arg +lh_free +lh_insert +lh_new +lh_node_stats +lh_node_stats_bio +lh_node_usage_stats +lh_node_usage_stats_bio +lh_num_items +lh_retrieve +lh_stats +lh_stats_bio +lh_strhash +MD4 +MD4_Final +MD4_Init +MD4_Transform +MD4_Update +MD5 +MD5_Final +MD5_Init +MD5_Transform +MD5_Update +name_cmp +NAME_CONSTRAINTS_check +NCONF_default +NCONF_dump_bio +NCONF_dump_fp +NCONF_free +NCONF_free_data +NCONF_get_number_e +NCONF_get_string +NCONF_load +NCONF_load_bio +NCONF_load_fp +NCONF_new +NCONF_WIN32 +NETSCAPE_SPKI_b64_decode +NETSCAPE_SPKI_b64_encode +NETSCAPE_SPKI_get_pubkey +NETSCAPE_SPKI_print +NETSCAPE_SPKI_set_pubkey +NETSCAPE_SPKI_sign +NETSCAPE_SPKI_verify +o2i_ECPublicKey +OBJ_add_object +OBJ_add_sigid +OBJ_bsearch_ +OBJ_bsearch_ex_ +OBJ_cleanup +OBJ_cmp +OBJ_create +OBJ_create_objects +OBJ_dup +OBJ_find_sigid_algs +OBJ_find_sigid_by_algs +OBJ_ln2nid +OBJ_NAME_add +OBJ_NAME_cleanup +OBJ_NAME_do_all +OBJ_NAME_do_all_sorted +OBJ_NAME_get +OBJ_NAME_init +OBJ_NAME_new_index +OBJ_NAME_remove +OBJ_new_nid +OBJ_nid2ln +OBJ_nid2obj +OBJ_nid2sn +OBJ_obj2nid +OBJ_obj2txt +OBJ_sigid_free +OBJ_sn2nid +OBJ_txt2nid +OBJ_txt2obj +OCSP_accept_responses_new +OCSP_archive_cutoff_new +OCSP_basic_add1_cert +OCSP_basic_add1_nonce +OCSP_basic_add1_status +OCSP_BASICRESP_add1_ext_i2d +OCSP_BASICRESP_add_ext +OCSP_BASICRESP_delete_ext +OCSP_BASICRESP_get1_ext_d2i +OCSP_BASICRESP_get_ext +OCSP_BASICRESP_get_ext_by_critical +OCSP_BASICRESP_get_ext_by_NID +OCSP_BASICRESP_get_ext_by_OBJ +OCSP_BASICRESP_get_ext_count +OCSP_basic_sign +OCSP_basic_verify +OCSP_CERTID_dup +OCSP_cert_id_new +OCSP_cert_status_str +OCSP_cert_to_id +OCSP_check_nonce +OCSP_check_validity +OCSP_copy_nonce +OCSP_crlID_new +OCSP_crl_reason_str +OCSP_id_cmp +OCSP_id_get0_info +OCSP_id_issuer_cmp +OCSP_ONEREQ_add1_ext_i2d +OCSP_ONEREQ_add_ext +OCSP_ONEREQ_delete_ext +OCSP_onereq_get0_id +OCSP_ONEREQ_get1_ext_d2i +OCSP_ONEREQ_get_ext +OCSP_ONEREQ_get_ext_by_critical +OCSP_ONEREQ_get_ext_by_NID +OCSP_ONEREQ_get_ext_by_OBJ +OCSP_ONEREQ_get_ext_count +OCSP_parse_url +OCSP_REQ_CTX_add1_header +OCSP_REQ_CTX_free +OCSP_REQ_CTX_get0_mem_bio +OCSP_REQ_CTX_http +OCSP_REQ_CTX_i2d +OCSP_REQ_CTX_nbio +OCSP_REQ_CTX_nbio_d2i +OCSP_REQ_CTX_new +OCSP_REQ_CTX_set1_req +OCSP_request_add0_id +OCSP_request_add1_cert +OCSP_REQUEST_add1_ext_i2d +OCSP_request_add1_nonce +OCSP_REQUEST_add_ext +OCSP_REQUEST_delete_ext +OCSP_REQUEST_get1_ext_d2i +OCSP_REQUEST_get_ext +OCSP_REQUEST_get_ext_by_critical +OCSP_REQUEST_get_ext_by_NID +OCSP_REQUEST_get_ext_by_OBJ +OCSP_REQUEST_get_ext_count +OCSP_request_is_signed +OCSP_request_onereq_count +OCSP_request_onereq_get0 +OCSP_REQUEST_print +OCSP_request_set1_name +OCSP_request_sign +OCSP_request_verify +OCSP_resp_count +OCSP_resp_find +OCSP_resp_find_status +OCSP_resp_get0 +OCSP_response_create +OCSP_response_get1_basic +OCSP_RESPONSE_print +OCSP_response_status +OCSP_response_status_str +OCSP_sendreq_bio +OCSP_sendreq_nbio +OCSP_sendreq_new +OCSP_set_max_response_length +OCSP_single_get0_status +OCSP_SINGLERESP_add1_ext_i2d +OCSP_SINGLERESP_add_ext +OCSP_SINGLERESP_delete_ext +OCSP_SINGLERESP_get1_ext_d2i +OCSP_SINGLERESP_get_ext +OCSP_SINGLERESP_get_ext_by_critical +OCSP_SINGLERESP_get_ext_by_NID +OCSP_SINGLERESP_get_ext_by_OBJ +OCSP_SINGLERESP_get_ext_count +OCSP_url_svcloc_new +OPENSSL_add_all_algorithms_conf +OPENSSL_add_all_algorithms_noconf +OpenSSL_add_all_ciphers +OpenSSL_add_all_digests +OPENSSL_asc2uni +OPENSSL_cleanse +OPENSSL_config +OpenSSLDie +OPENSSL_ia32cap_loc +OPENSSL_init +OPENSSL_isservice +OPENSSL_issetugid +OPENSSL_load_builtin_modules +OPENSSL_no_config +OPENSSL_uni2asc +_ossl_096_des_random_seed +_ossl_old_crypt +_ossl_old_des_cbc_cksum +_ossl_old_des_cbc_encrypt +_ossl_old_des_cfb64_encrypt +_ossl_old_des_cfb_encrypt +_ossl_old_des_crypt +_ossl_old_des_decrypt3 +_ossl_old_des_ecb3_encrypt +_ossl_old_des_ecb_encrypt +_ossl_old_des_ede3_cbc_encrypt +_ossl_old_des_ede3_cfb64_encrypt +_ossl_old_des_ede3_ofb64_encrypt +_ossl_old_des_enc_read +_ossl_old_des_encrypt +_ossl_old_des_encrypt2 +_ossl_old_des_encrypt3 +_ossl_old_des_enc_write +_ossl_old_des_fcrypt +_ossl_old_des_is_weak_key +_ossl_old_des_key_sched +_ossl_old_des_ncbc_encrypt +_ossl_old_des_ofb64_encrypt +_ossl_old_des_ofb_encrypt +_ossl_old_des_options +_ossl_old_des_pcbc_encrypt +_ossl_old_des_quad_cksum +_ossl_old_des_random_key +_ossl_old_des_random_seed +_ossl_old_des_read_2passwords +_ossl_old_des_read_password +_ossl_old_des_read_pw +_ossl_old_des_read_pw_string +_ossl_old_des_set_key +_ossl_old_des_set_odd_parity +_ossl_old_des_string_to_2keys +_ossl_old_des_string_to_key +_ossl_old_des_xcbc_encrypt +OTHERNAME_cmp +PEM_ASN1_read +PEM_ASN1_read_bio +PEM_ASN1_write +PEM_ASN1_write_bio +PEM_bytes_read_bio +PEM_def_callback +PEM_dek_info +PEM_do_header +PEM_get_EVP_CIPHER_INFO +PEM_proc_type +PEM_read +PEM_read_bio +PEM_read_bio_Parameters +PEM_SealFinal +PEM_SealInit +PEM_SealUpdate +PEM_SignFinal +PEM_SignInit +PEM_SignUpdate +PEM_write +PEM_write_bio +PEM_write_bio_ASN1_stream +PEM_write_bio_CMS_stream +PEM_write_bio_Parameters +PEM_write_bio_PKCS7_stream +PEM_write_bio_PKCS8PrivateKey +PEM_write_bio_PKCS8PrivateKey_nid +PEM_write_PKCS8PrivateKey +PEM_write_PKCS8PrivateKey_nid +PEM_X509_INFO_write_bio +pitem_free +pitem_new +PKCS12_add_CSPName_asc +PKCS12_add_friendlyname_asc +PKCS12_add_friendlyname_uni +PKCS12_add_localkeyid +PKCS12_certbag2x509 +PKCS12_certbag2x509crl +PKCS12_create +PKCS12_decrypt_skey +PKCS12_gen_mac +PKCS12_get_friendlyname +PKCS12_init +PKCS12_item_decrypt_d2i +PKCS12_item_i2d_encrypt +PKCS12_item_pack_safebag +PKCS12_key_gen_asc +PKCS12_key_gen_uni +PKCS12_MAKE_KEYBAG +PKCS12_MAKE_SHKEYBAG +PKCS12_newpass +PKCS12_pack_authsafes +PKCS12_pack_p7encdata +PKCS12_parse +PKCS12_PBE_add +PKCS12_pbe_crypt +PKCS12_PBE_keyivgen +PKCS12_set_mac +PKCS12_setup_mac +PKCS12_verify_mac +PKCS12_x5092certbag +PKCS12_x509crl2certbag +PKCS1_MGF1 +PKCS5_pbe2_set +PKCS5_pbe2_set_iv +PKCS5_PBE_add +PKCS5_PBE_keyivgen +PKCS5_pbe_set +PKCS5_pbe_set0_algor +PKCS5_PBKDF2_HMAC +PKCS5_PBKDF2_HMAC_SHA1 +PKCS5_pbkdf2_set +PKCS5_v2_PBE_keyivgen +PKCS7_add0_attrib_signing_time +PKCS7_add1_attrib_digest +PKCS7_add_attrib_content_type +PKCS7_add_attrib_smimecap +PKCS7_add_attribute +PKCS7_add_certificate +PKCS7_add_crl +PKCS7_add_recipient +PKCS7_add_recipient_info +PKCS7_add_signature +PKCS7_add_signed_attribute +PKCS7_add_signer +PKCS7_cert_from_signer_info +PKCS7_content_new +PKCS7_ctrl +PKCS7_dataDecode +PKCS7_dataFinal +PKCS7_dataInit +PKCS7_dataVerify +PKCS7_decrypt +PKCS7_dup +PKCS7_final +PKCS7_get_attribute +PKCS7_get_issuer_and_serial +PKCS7_get_signed_attribute +PKCS7_ISSUER_AND_SERIAL_digest +PKCS7_RECIP_INFO_get0_alg +PKCS7_RECIP_INFO_set +PKCS7_set0_type_other +PKCS7_set_attributes +PKCS7_set_cipher +PKCS7_set_content +PKCS7_set_digest +PKCS7_set_signed_attributes +PKCS7_set_type +PKCS7_sign +PKCS7_sign_add_signer +PKCS7_signatureVerify +PKCS7_SIGNER_INFO_get0_algs +PKCS7_SIGNER_INFO_set +PKCS7_SIGNER_INFO_sign +PKCS7_stream +PKCS7_to_TS_TST_INFO +PKCS7_verify +PKCS8_add_keyusage +PKCS8_decrypt +PKCS8_encrypt +PKCS8_pkey_get0 +PKCS8_pkey_set0 +PKCS8_set_broken +pqueue_find +pqueue_free +pqueue_insert +pqueue_iterator +pqueue_new +pqueue_next +pqueue_peek +pqueue_pop +pqueue_print +pqueue_size +private_AES_set_decrypt_key +private_AES_set_encrypt_key +private_BF_set_key +private_Camellia_set_key +private_CAST_set_key +private_DES_set_key_unchecked +private_MD4_Init +private_MD5_Init +private_RC2_set_key +private_RC4_set_key +private_RIPEMD160_Init +private_SEED_set_key +private_SHA1_Init +private_SHA224_Init +private_SHA256_Init +private_SHA384_Init +private_SHA512_Init +private_SHA_Init +private_WHIRLPOOL_Init +RAND_add +RAND_bytes +RAND_cleanup +RAND_egd +RAND_egd_bytes +RAND_event +RAND_file_name +RAND_get_rand_method +RAND_init_fips +RAND_load_file +RAND_poll +RAND_pseudo_bytes +RAND_query_egd_bytes +RAND_screen +RAND_seed +RAND_set_fips_drbg_type +RAND_set_rand_engine +RAND_set_rand_method +RAND_SSLeay +RAND_status +RAND_write_file +RC2_cbc_encrypt +RC2_cfb64_encrypt +RC2_decrypt +RC2_ecb_encrypt +RC2_encrypt +RC2_ofb64_encrypt +RC2_set_key +RC4 +RC4_options +RC4_set_key +RIPEMD160 +RIPEMD160_Final +RIPEMD160_Init +RIPEMD160_Transform +RIPEMD160_Update +RSA_blinding_off +RSA_blinding_on +RSA_check_key +RSA_flags +RSA_free +RSA_generate_key +RSA_generate_key_ex +RSA_get_default_method +RSA_get_ex_data +RSA_get_ex_new_index +RSA_get_method +RSA_memory_lock +RSA_new +RSA_new_method +RSA_null_method +RSA_padding_add_none +RSA_padding_add_PKCS1_OAEP +RSA_padding_add_PKCS1_OAEP_mgf1 +RSA_padding_add_PKCS1_PSS +RSA_padding_add_PKCS1_PSS_mgf1 +RSA_padding_add_PKCS1_type_1 +RSA_padding_add_PKCS1_type_2 +RSA_padding_add_SSLv23 +RSA_padding_add_X931 +RSA_padding_check_none +RSA_padding_check_PKCS1_OAEP +RSA_padding_check_PKCS1_OAEP_mgf1 +RSA_padding_check_PKCS1_type_1 +RSA_padding_check_PKCS1_type_2 +RSA_padding_check_SSLv23 +RSA_padding_check_X931 +RSA_PKCS1_SSLeay +RSA_print +RSA_print_fp +RSA_private_decrypt +RSA_private_encrypt +RSAPrivateKey_dup +RSA_public_decrypt +RSA_public_encrypt +RSAPublicKey_dup +RSA_set_default_method +RSA_set_ex_data +RSA_set_method +RSA_setup_blinding +RSA_sign +RSA_sign_ASN1_OCTET_STRING +RSA_size +RSA_up_ref +RSA_verify +RSA_verify_ASN1_OCTET_STRING +RSA_verify_PKCS1_PSS +RSA_verify_PKCS1_PSS_mgf1 +RSA_X931_hash_id +s2i_ASN1_INTEGER +s2i_ASN1_OCTET_STRING +SEED_cbc_encrypt +SEED_cfb128_encrypt +SEED_decrypt +SEED_ecb_encrypt +SEED_encrypt +SEED_ofb128_encrypt +SEED_set_key +SHA +SHA1 +SHA1_Final +SHA1_Init +SHA1_Transform +SHA1_Update +SHA224 +SHA224_Final +SHA224_Init +SHA224_Update +SHA256 +SHA256_Final +SHA256_Init +SHA256_Transform +SHA256_Update +SHA384 +SHA384_Final +SHA384_Init +SHA384_Update +SHA512 +SHA512_Final +SHA512_Init +SHA512_Transform +SHA512_Update +SHA_Final +SHA_Init +SHA_Transform +SHA_Update +sk_deep_copy +sk_delete +sk_delete_ptr +sk_dup +sk_find +sk_find_ex +sk_free +sk_insert +sk_is_sorted +sk_new +sk_new_null +sk_num +sk_pop +sk_pop_free +sk_push +sk_set +sk_set_cmp_func +sk_shift +sk_sort +sk_unshift +sk_value +sk_zero +SMIME_crlf_copy +SMIME_read_ASN1 +SMIME_read_CMS +SMIME_read_PKCS7 +SMIME_text +SMIME_write_ASN1 +SMIME_write_CMS +SMIME_write_PKCS7 +SRP_Calc_A +SRP_Calc_A_param +SRP_Calc_B +SRP_Calc_client_key +SRP_Calc_server_key +SRP_Calc_u +SRP_Calc_x +SRP_check_known_gN_param +SRP_create_verifier +SRP_create_verifier_BN +SRP_generate_client_master_secret +SRP_generate_server_master_secret +SRP_get_default_gN +SRP_user_pwd_free +SRP_VBASE_free +SRP_VBASE_get1_by_user +SRP_VBASE_get_by_user +SRP_VBASE_init +SRP_VBASE_new +SRP_Verify_A_mod_N +SRP_Verify_B_mod_N +SSL_accept +SSL_add_client_CA +SSL_alert_desc_string +SSL_alert_desc_string_long +SSL_alert_type_string +SSL_alert_type_string_long +SSL_cache_hit +SSL_callback_ctrl +SSL_certs_clear +SSL_check_chain +SSL_check_private_key +SSL_CIPHER_description +SSL_CIPHER_find +SSL_CIPHER_get_bits +SSL_CIPHER_get_id +SSL_CIPHER_get_name +SSL_CIPHER_get_version +SSL_CIPHER_standard_name +SSL_clear +SSL_COMP_add_compression_method +SSL_COMP_free_compression_methods +SSL_COMP_get_compression_methods +SSL_COMP_get_name +SSL_CONF_cmd +SSL_CONF_cmd_argv +SSL_CONF_cmd_value_type +SSL_CONF_CTX_clear_flags +SSL_CONF_CTX_finish +SSL_CONF_CTX_free +SSL_CONF_CTX_new +SSL_CONF_CTX_set1_prefix +SSL_CONF_CTX_set_flags +SSL_CONF_CTX_set_ssl +SSL_CONF_CTX_set_ssl_ctx +SSL_connect +SSL_copy_session_id +SSL_ctrl +SSL_CTX_add_client_CA +SSL_CTX_add_client_custom_ext +SSL_CTX_add_server_custom_ext +SSL_CTX_add_session +SSL_CTX_callback_ctrl +SSL_CTX_check_private_key +SSL_CTX_ctrl +SSL_CTX_flush_sessions +SSL_CTX_free +SSL_CTX_get0_certificate +SSL_CTX_get0_param +SSL_CTX_get0_privatekey +SSL_CTX_get_cert_store +SSL_CTX_get_client_cert_cb +SSL_CTX_get_ex_data +SSL_CTX_get_ex_new_index +SSL_CTX_get_info_callback +SSL_CTX_get_quiet_shutdown +SSL_CTX_get_ssl_method +SSL_CTX_get_timeout +SSL_CTX_get_verify_callback +SSL_CTX_get_verify_depth +SSL_CTX_get_verify_mode +SSL_CTX_load_verify_locations +SSL_CTX_new +SSL_CTX_remove_session +SSL_CTX_sess_get_get_cb +SSL_CTX_sess_get_new_cb +SSL_CTX_sess_get_remove_cb +SSL_CTX_sess_set_get_cb +SSL_CTX_sess_set_new_cb +SSL_CTX_sess_set_remove_cb +SSL_CTX_set1_param +SSL_CTX_set_alpn_protos +SSL_CTX_set_alpn_select_cb +SSL_CTX_set_cert_cb +SSL_CTX_set_cert_store +SSL_CTX_set_cert_verify_callback +SSL_CTX_set_cipher_list +SSL_CTX_set_client_CA_list +SSL_CTX_set_client_cert_cb +SSL_CTX_set_client_cert_engine +SSL_CTX_set_cookie_generate_cb +SSL_CTX_set_cookie_verify_cb +SSL_CTX_set_default_passwd_cb +SSL_CTX_set_default_passwd_cb_userdata +SSL_CTX_set_default_verify_paths +SSL_CTX_set_ex_data +SSL_CTX_set_generate_session_id +SSL_CTX_set_info_callback +SSL_CTX_set_msg_callback +SSL_CTX_set_next_protos_advertised_cb +SSL_CTX_set_next_proto_select_cb +SSL_CTX_set_psk_client_callback +SSL_CTX_set_psk_server_callback +SSL_CTX_set_purpose +SSL_CTX_set_quiet_shutdown +SSL_CTX_set_session_id_context +SSL_CTX_set_srp_cb_arg +SSL_CTX_set_srp_client_pwd_callback +SSL_CTX_set_srp_password +SSL_CTX_set_srp_strength +SSL_CTX_set_srp_username +SSL_CTX_set_srp_username_callback +SSL_CTX_set_srp_verify_param_callback +SSL_CTX_set_ssl_version +SSL_CTX_set_timeout +SSL_CTX_set_tlsext_use_srtp +SSL_CTX_set_tmp_dh_callback +SSL_CTX_set_tmp_ecdh_callback +SSL_CTX_set_tmp_rsa_callback +SSL_CTX_set_trust +SSL_CTX_set_verify +SSL_CTX_set_verify_depth +SSL_CTX_SRP_CTX_free +SSL_CTX_SRP_CTX_init +SSL_CTX_use_certificate +SSL_CTX_use_certificate_ASN1 +SSL_CTX_use_certificate_chain_file +SSL_CTX_use_certificate_file +SSL_CTX_use_PrivateKey +SSL_CTX_use_PrivateKey_ASN1 +SSL_CTX_use_PrivateKey_file +SSL_CTX_use_psk_identity_hint +SSL_CTX_use_RSAPrivateKey +SSL_CTX_use_RSAPrivateKey_ASN1 +SSL_CTX_use_RSAPrivateKey_file +SSL_CTX_use_serverinfo +SSL_CTX_use_serverinfo_file +SSL_do_handshake +SSL_dup +SSLeay +SSLeay_version +SSL_export_keying_material +SSL_extension_supported +SSL_free +SSL_get0_alpn_selected +SSL_get0_kssl_ctx +SSL_get0_next_proto_negotiated +SSL_get0_param +SSL_get1_session +SSL_get_certificate +SSL_get_cipher_list +SSL_get_current_cipher +SSL_get_current_compression +SSL_get_current_expansion +SSL_get_default_timeout +SSL_get_error +SSL_get_ex_data +SSL_get_ex_data_X509_STORE_CTX_idx +SSL_get_ex_new_index +SSL_get_fd +SSL_get_finished +SSL_get_info_callback +SSL_get_peer_certificate +SSL_get_peer_finished +SSL_get_privatekey +SSL_get_psk_identity +SSL_get_psk_identity_hint +SSL_get_quiet_shutdown +SSL_get_rbio +SSL_get_read_ahead +SSL_get_rfd +SSL_get_selected_srtp_profile +SSL_get_servername +SSL_get_servername_type +SSL_get_session +SSL_get_shared_ciphers +SSL_get_shared_sigalgs +SSL_get_shutdown +SSL_get_sigalgs +SSL_get_srp_g +SSL_get_srp_N +SSL_get_srp_userinfo +SSL_get_srp_username +SSL_get_SSL_CTX +SSL_get_ssl_method +SSL_get_verify_callback +SSL_get_verify_depth +SSL_get_verify_mode +SSL_get_verify_result +SSL_get_version +SSL_get_wbio +SSL_get_wfd +SSL_has_matching_session_id +SSL_is_server +SSL_library_init +SSL_load_error_strings +SSL_new +SSL_peek +SSL_pending +SSL_read +SSL_renegotiate +SSL_renegotiate_abbreviated +SSL_renegotiate_pending +SSL_rstate_string +SSL_rstate_string_long +SSL_select_next_proto +SSL_SESSION_free +SSL_SESSION_get0_peer +SSL_SESSION_get_compress_id +SSL_SESSION_get_ex_data +SSL_SESSION_get_ex_new_index +SSL_SESSION_get_id +SSL_SESSION_get_time +SSL_SESSION_get_timeout +SSL_SESSION_new +SSL_SESSION_print +SSL_SESSION_print_fp +SSL_SESSION_set1_id_context +SSL_SESSION_set_ex_data +SSL_SESSION_set_time +SSL_SESSION_set_timeout +SSL_set0_kssl_ctx +SSL_set1_param +SSL_set_accept_state +SSL_set_alpn_protos +SSL_set_bio +SSL_set_cert_cb +SSL_set_cipher_list +SSL_set_client_CA_list +SSL_set_connect_state +SSL_set_debug +SSL_set_ex_data +SSL_set_fd +SSL_set_generate_session_id +SSL_set_info_callback +SSL_set_msg_callback +SSL_set_psk_client_callback +SSL_set_psk_server_callback +SSL_set_purpose +SSL_set_quiet_shutdown +SSL_set_read_ahead +SSL_set_rfd +SSL_set_session +SSL_set_session_id_context +SSL_set_session_secret_cb +SSL_set_session_ticket_ext +SSL_set_session_ticket_ext_cb +SSL_set_shutdown +SSL_set_srp_server_param +SSL_set_srp_server_param_pw +SSL_set_SSL_CTX +SSL_set_ssl_method +SSL_set_state +SSL_set_tlsext_use_srtp +SSL_set_tmp_dh_callback +SSL_set_tmp_ecdh_callback +SSL_set_tmp_rsa_callback +SSL_set_trust +SSL_set_verify +SSL_set_verify_depth +SSL_set_verify_result +SSL_set_wfd +SSL_shutdown +SSL_SRP_CTX_free +SSL_SRP_CTX_init +SSL_srp_server_param_with_username +SSL_state +SSL_state_string +SSL_state_string_long +SSL_test_functions +SSL_trace +SSL_use_certificate +SSL_use_certificate_ASN1 +SSL_use_certificate_file +SSL_use_PrivateKey +SSL_use_PrivateKey_ASN1 +SSL_use_PrivateKey_file +SSL_use_psk_identity_hint +SSL_use_RSAPrivateKey +SSL_use_RSAPrivateKey_ASN1 +SSL_use_RSAPrivateKey_file +SSLv23_client_method +SSLv23_method +SSLv23_server_method +SSLv2_client_method +SSLv2_method +SSLv2_server_method +SSLv3_client_method +SSLv3_method +SSLv3_server_method +SSL_version +SSL_want +SSL_write +STACK_OF +string_to_hex +SXNET_add_id_asc +SXNET_add_id_INTEGER +SXNET_add_id_ulong +SXNET_get_id_asc +SXNET_get_id_INTEGER +SXNET_get_id_ulong +TLSv1_1_client_method +TLSv1_1_method +TLSv1_1_server_method +TLSv1_2_client_method +TLSv1_2_method +TLSv1_2_server_method +TLSv1_client_method +TLSv1_method +TLSv1_server_method +TS_ACCURACY_dup +TS_ACCURACY_free +TS_ACCURACY_get_micros +TS_ACCURACY_get_millis +TS_ACCURACY_get_seconds +TS_ACCURACY_new +TS_ACCURACY_set_micros +TS_ACCURACY_set_millis +TS_ACCURACY_set_seconds +TS_ASN1_INTEGER_print_bio +TS_CONF_get_tsa_section +TS_CONF_load_cert +TS_CONF_load_key +TS_CONF_set_accuracy +TS_CONF_set_certs +TS_CONF_set_clock_precision_digits +TS_CONF_set_crypto_device +TS_CONF_set_default_engine +TS_CONF_set_def_policy +TS_CONF_set_digests +TS_CONF_set_ess_cert_id_chain +TS_CONF_set_ordering +TS_CONF_set_policies +TS_CONF_set_serial +TS_CONF_set_signer_cert +TS_CONF_set_signer_key +TS_CONF_set_tsa_name +TS_ext_print_bio +TS_MSG_IMPRINT_dup +TS_MSG_IMPRINT_free +TS_MSG_IMPRINT_get_algo +TS_MSG_IMPRINT_get_msg +TS_MSG_IMPRINT_new +TS_MSG_IMPRINT_print_bio +TS_MSG_IMPRINT_set_algo +TS_MSG_IMPRINT_set_msg +TS_OBJ_print_bio +TS_REQ_add_ext +TS_REQ_delete_ext +TS_REQ_dup +TS_REQ_ext_free +TS_REQ_free +TS_REQ_get_cert_req +TS_REQ_get_ext +TS_REQ_get_ext_by_critical +TS_REQ_get_ext_by_NID +TS_REQ_get_ext_by_OBJ +TS_REQ_get_ext_count +TS_REQ_get_ext_d2i +TS_REQ_get_msg_imprint +TS_REQ_get_nonce +TS_REQ_get_policy_id +TS_REQ_get_version +TS_REQ_new +TS_REQ_print_bio +TS_REQ_set_cert_req +TS_REQ_set_msg_imprint +TS_REQ_set_nonce +TS_REQ_set_policy_id +TS_REQ_set_version +TS_REQ_to_TS_VERIFY_CTX +TS_RESP_create_response +TS_RESP_CTX_add_failure_info +TS_RESP_CTX_add_flags +TS_RESP_CTX_add_md +TS_RESP_CTX_add_policy +TS_RESP_CTX_free +TS_RESP_CTX_get_request +TS_RESP_CTX_get_tst_info +TS_RESP_CTX_new +TS_RESP_CTX_set_accuracy +TS_RESP_CTX_set_certs +TS_RESP_CTX_set_clock_precision_digits +TS_RESP_CTX_set_def_policy +TS_RESP_CTX_set_extension_cb +TS_RESP_CTX_set_serial_cb +TS_RESP_CTX_set_signer_cert +TS_RESP_CTX_set_signer_key +TS_RESP_CTX_set_status_info +TS_RESP_CTX_set_status_info_cond +TS_RESP_CTX_set_time_cb +TS_RESP_dup +TS_RESP_free +TS_RESP_get_status_info +TS_RESP_get_token +TS_RESP_get_tst_info +TS_RESP_new +TS_RESP_print_bio +TS_RESP_set_status_info +TS_RESP_set_tst_info +TS_RESP_verify_response +TS_RESP_verify_signature +TS_RESP_verify_token +TS_STATUS_INFO_dup +TS_STATUS_INFO_free +TS_STATUS_INFO_new +TS_STATUS_INFO_print_bio +TS_TST_INFO_add_ext +TS_TST_INFO_delete_ext +TS_TST_INFO_dup +TS_TST_INFO_ext_free +TS_TST_INFO_free +TS_TST_INFO_get_accuracy +TS_TST_INFO_get_ext +TS_TST_INFO_get_ext_by_critical +TS_TST_INFO_get_ext_by_NID +TS_TST_INFO_get_ext_by_OBJ +TS_TST_INFO_get_ext_count +TS_TST_INFO_get_ext_d2i +TS_TST_INFO_get_msg_imprint +TS_TST_INFO_get_nonce +TS_TST_INFO_get_ordering +TS_TST_INFO_get_policy_id +TS_TST_INFO_get_serial +TS_TST_INFO_get_time +TS_TST_INFO_get_tsa +TS_TST_INFO_get_version +TS_TST_INFO_new +TS_TST_INFO_print_bio +TS_TST_INFO_set_accuracy +TS_TST_INFO_set_msg_imprint +TS_TST_INFO_set_nonce +TS_TST_INFO_set_ordering +TS_TST_INFO_set_policy_id +TS_TST_INFO_set_serial +TS_TST_INFO_set_time +TS_TST_INFO_set_tsa +TS_TST_INFO_set_version +TS_VERIFY_CTX_cleanup +TS_VERIFY_CTX_free +TS_VERIFY_CTX_init +TS_VERIFY_CTX_new +TS_X509_ALGOR_print_bio +TXT_DB_create_index +TXT_DB_free +TXT_DB_get_by_index +TXT_DB_insert +TXT_DB_read +TXT_DB_write +UI_add_error_string +UI_add_info_string +UI_add_input_boolean +UI_add_input_string +UI_add_user_data +UI_add_verify_string +UI_construct_prompt +UI_create_method +UI_ctrl +UI_destroy_method +UI_dup_error_string +UI_dup_info_string +UI_dup_input_boolean +UI_dup_input_string +UI_dup_verify_string +UI_free +UI_get0_action_string +UI_get0_output_string +UI_get0_result +UI_get0_result_string +UI_get0_test_string +UI_get0_user_data +UI_get_default_method +UI_get_ex_data +UI_get_ex_new_index +UI_get_input_flags +UI_get_method +UI_get_result_maxsize +UI_get_result_minsize +UI_get_string_type +UI_method_get_closer +UI_method_get_flusher +UI_method_get_opener +UI_method_get_prompt_constructor +UI_method_get_reader +UI_method_get_writer +UI_method_set_closer +UI_method_set_flusher +UI_method_set_opener +UI_method_set_prompt_constructor +UI_method_set_reader +UI_method_set_writer +UI_new +UI_new_method +UI_OpenSSL +UI_process +UI_set_default_method +UI_set_ex_data +UI_set_method +UI_set_result +UI_UTIL_read_pw +UI_UTIL_read_pw_string +UTF8_getc +UTF8_putc +v2i_ASN1_BIT_STRING +v2i_GENERAL_NAME +v2i_GENERAL_NAME_ex +v2i_GENERAL_NAMES +v3_addr_add_inherit +v3_addr_add_prefix +v3_addr_add_range +v3_addr_canonize +v3_addr_get_afi +v3_addr_get_range +v3_addr_inherits +v3_addr_is_canonical +v3_addr_subset +v3_addr_validate_path +v3_asid_add_id_or_range +v3_asid_add_inherit +v3_asid_canonize +v3_asid_inherits +v3_asid_is_canonical +v3_asid_subset +v3_asid_validate_path +WHIRLPOOL +WHIRLPOOL_BitUpdate +WHIRLPOOL_Final +WHIRLPOOL_Init +WHIRLPOOL_Update +X509_add1_ext_i2d +X509_add1_reject_object +X509_add1_trust_object +X509_add_ext +X509_ALGOR_cmp +X509_ALGOR_dup +X509_ALGOR_get0 +X509_ALGOR_set0 +X509_ALGOR_set_md +X509_alias_get0 +X509_alias_set1 +X509_ATTRIBUTE_count +X509_ATTRIBUTE_create +X509_ATTRIBUTE_create_by_NID +X509_ATTRIBUTE_create_by_OBJ +X509_ATTRIBUTE_create_by_txt +X509_ATTRIBUTE_dup +X509_ATTRIBUTE_get0_data +X509_ATTRIBUTE_get0_object +X509_ATTRIBUTE_get0_type +X509_ATTRIBUTE_set1_data +X509_ATTRIBUTE_set1_object +X509_CERT_AUX_print +X509_certificate_type +X509_chain_check_suiteb +X509_check_akid +X509_check_ca +X509_check_email +X509_check_host +X509_check_ip +X509_check_ip_asc +X509_check_issued +X509_check_private_key +X509_check_purpose +X509_check_trust +X509_cmp +X509_cmp_current_time +X509_cmp_time +X509_CRL_add0_revoked +X509_CRL_add1_ext_i2d +X509_CRL_add_ext +X509_CRL_check_suiteb +X509_CRL_cmp +X509_CRL_delete_ext +X509_CRL_diff +X509_CRL_digest +X509_CRL_dup +X509_CRL_get0_by_cert +X509_CRL_get0_by_serial +X509_CRL_get_ext +X509_CRL_get_ext_by_critical +X509_CRL_get_ext_by_NID +X509_CRL_get_ext_by_OBJ +X509_CRL_get_ext_count +X509_CRL_get_ext_d2i +X509_CRL_get_meth_data +X509_CRL_http_nbio +X509_CRL_match +X509_CRL_METHOD_free +X509_CRL_METHOD_new +X509_CRL_print +X509_CRL_print_fp +X509_CRL_set_default_method +X509_CRL_set_issuer_name +X509_CRL_set_lastUpdate +X509_CRL_set_meth_data +X509_CRL_set_nextUpdate +X509_CRL_set_version +X509_CRL_sign +X509_CRL_sign_ctx +X509_CRL_sort +X509_CRL_verify +X509_delete_ext +X509_digest +X509_dup +X509_EXTENSION_create_by_NID +X509_EXTENSION_create_by_OBJ +X509_EXTENSION_dup +X509_EXTENSION_get_critical +X509_EXTENSION_get_data +X509_EXTENSION_get_object +X509_EXTENSION_set_critical +X509_EXTENSION_set_data +X509_EXTENSION_set_object +X509_get0_pubkey_bitstr +X509_get0_signature +X509_get_default_cert_area +X509_get_default_cert_dir +X509_get_default_cert_dir_env +X509_get_default_cert_file +X509_get_default_cert_file_env +X509_get_default_private_dir +X509_get_ex_data +X509_get_ex_new_index +X509_get_ext +X509_get_ext_by_critical +X509_get_ext_by_NID +X509_get_ext_by_OBJ +X509_get_ext_count +X509_get_ext_d2i +X509_get_issuer_name +X509_get_pubkey +X509_get_pubkey_parameters +X509_get_serialNumber +X509_get_signature_nid +X509_get_subject_name +X509_gmtime_adj +X509_http_nbio +X509_INFO_free +X509_INFO_new +X509_issuer_and_serial_cmp +X509_issuer_and_serial_hash +X509_issuer_name_cmp +X509_issuer_name_hash +X509_issuer_name_hash_old +X509_keyid_get0 +X509_keyid_set1 +X509_load_cert_crl_file +X509_load_cert_file +X509_load_crl_file +X509_LOOKUP_by_alias +X509_LOOKUP_by_fingerprint +X509_LOOKUP_by_issuer_serial +X509_LOOKUP_by_subject +X509_LOOKUP_ctrl +X509_LOOKUP_file +X509_LOOKUP_free +X509_LOOKUP_hash_dir +X509_LOOKUP_init +X509_LOOKUP_new +X509_LOOKUP_shutdown +X509_NAME_add_entry +X509_NAME_add_entry_by_NID +X509_NAME_add_entry_by_OBJ +X509_NAME_add_entry_by_txt +X509_NAME_cmp +X509_NAME_delete_entry +X509_NAME_digest +X509_NAME_dup +X509_NAME_entry_count +X509_NAME_ENTRY_create_by_NID +X509_NAME_ENTRY_create_by_OBJ +X509_NAME_ENTRY_create_by_txt +X509_NAME_ENTRY_dup +X509_NAME_ENTRY_get_data +X509_NAME_ENTRY_get_object +X509_NAME_ENTRY_set_data +X509_NAME_ENTRY_set_object +X509_NAME_get_entry +X509_NAME_get_index_by_NID +X509_NAME_get_index_by_OBJ +X509_NAME_get_text_by_NID +X509_NAME_get_text_by_OBJ +X509_NAME_hash +X509_NAME_hash_old +X509_NAME_oneline +X509_NAME_print +X509_NAME_print_ex +X509_NAME_print_ex_fp +X509_NAME_set +X509_OBJECT_free_contents +X509_OBJECT_up_ref_count +X509_ocspid_print +X509_PKEY_free +X509_PKEY_new +X509_policy_check +X509_policy_level_get0_node +X509_policy_level_node_count +X509_policy_node_get0_parent +X509_policy_node_get0_policy +X509_POLICY_NODE_print +X509_policy_tree_free +X509_policy_tree_get0_level +X509_policy_tree_level_count +X509_print +X509_print_ex +X509_print_ex_fp +X509_print_fp +X509_pubkey_digest +X509_PUBKEY_get +X509_PUBKEY_get0_param +X509_PUBKEY_set +X509_PUBKEY_set0_param +X509_PURPOSE_add +X509_PURPOSE_cleanup +X509_PURPOSE_get0 +X509_PURPOSE_get0_name +X509_PURPOSE_get0_sname +X509_PURPOSE_get_by_id +X509_PURPOSE_get_by_sname +X509_PURPOSE_get_count +X509_PURPOSE_get_id +X509_PURPOSE_get_trust +X509_PURPOSE_set +X509_reject_clear +X509_REQ_add1_attr +X509_REQ_add1_attr_by_NID +X509_REQ_add1_attr_by_OBJ +X509_REQ_add1_attr_by_txt +X509_REQ_add_extensions +X509_REQ_add_extensions_nid +X509_REQ_check_private_key +X509_REQ_delete_attr +X509_REQ_digest +X509_REQ_dup +X509_REQ_extension_nid +X509_REQ_get_attr +X509_REQ_get_attr_by_NID +X509_REQ_get_attr_by_OBJ +X509_REQ_get_attr_count +X509_REQ_get_extension_nids +X509_REQ_get_pubkey +X509_REQ_print +X509_REQ_print_ex +X509_REQ_print_fp +X509_REQ_set_extension_nids +X509_REQ_set_pubkey +X509_REQ_set_subject_name +X509_REQ_set_version +X509_REQ_sign +X509_REQ_sign_ctx +X509_REQ_to_X509 +X509_REQ_verify +X509_REVOKED_add1_ext_i2d +X509_REVOKED_add_ext +X509_REVOKED_delete_ext +X509_REVOKED_dup +X509_REVOKED_get_ext +X509_REVOKED_get_ext_by_critical +X509_REVOKED_get_ext_by_NID +X509_REVOKED_get_ext_by_OBJ +X509_REVOKED_get_ext_count +X509_REVOKED_get_ext_d2i +X509_REVOKED_set_revocationDate +X509_REVOKED_set_serialNumber +X509_set_ex_data +X509_set_issuer_name +X509_set_notAfter +X509_set_notBefore +X509_set_pubkey +X509_set_serialNumber +X509_set_subject_name +X509_set_version +X509_sign +X509_signature_dump +X509_signature_print +X509_sign_ctx +X509_STORE_add_cert +X509_STORE_add_crl +X509_STORE_add_lookup +X509_STORE_CTX_cleanup +X509_STORE_CTX_free +X509_STORE_CTX_get0_current_crl +X509_STORE_CTX_get0_current_issuer +X509_STORE_CTX_get0_param +X509_STORE_CTX_get0_parent_ctx +X509_STORE_CTX_get0_policy_tree +X509_STORE_CTX_get0_store +X509_STORE_CTX_get1_issuer +X509_STORE_CTX_get_current_cert +X509_STORE_CTX_get_error +X509_STORE_CTX_get_error_depth +X509_STORE_CTX_get_ex_data +X509_STORE_CTX_get_ex_new_index +X509_STORE_CTX_get_explicit_policy +X509_STORE_CTX_init +X509_STORE_CTX_new +X509_STORE_CTX_purpose_inherit +X509_STORE_CTX_set0_crls +X509_STORE_CTX_set0_param +X509_STORE_CTX_set_cert +X509_STORE_CTX_set_chain +X509_STORE_CTX_set_default +X509_STORE_CTX_set_depth +X509_STORE_CTX_set_error +X509_STORE_CTX_set_ex_data +X509_STORE_CTX_set_flags +X509_STORE_CTX_set_purpose +X509_STORE_CTX_set_time +X509_STORE_CTX_set_trust +X509_STORE_CTX_set_verify_cb +X509_STORE_CTX_trusted_stack +X509_STORE_free +X509_STORE_get_by_subject +X509_STORE_load_locations +X509_STORE_new +X509_STORE_set1_param +X509_STORE_set_default_paths +X509_STORE_set_depth +X509_STORE_set_flags +X509_STORE_set_lookup_crls_cb +X509_STORE_set_purpose +X509_STORE_set_trust +X509_STORE_set_verify_cb +X509_subject_name_cmp +X509_subject_name_hash +X509_subject_name_hash_old +X509_supported_extension +X509_time_adj +X509_time_adj_ex +X509_to_X509_REQ +X509_TRUST_add +X509_TRUST_cleanup +X509_trust_clear +X509_TRUST_get0 +X509_TRUST_get0_name +X509_TRUST_get_by_id +X509_TRUST_get_count +X509_TRUST_get_flags +X509_TRUST_get_trust +X509_TRUST_set +X509_TRUST_set_default +X509V3_add_standard_extensions +X509V3_add_value +X509V3_add_value_bool +X509V3_add_value_bool_nf +X509V3_add_value_int +X509V3_add_value_uchar +X509V3_conf_free +X509V3_EXT_add +X509V3_EXT_add_alias +X509V3_EXT_add_list +X509V3_EXT_add_nconf +X509V3_EXT_add_nconf_sk +X509V3_EXT_cleanup +X509V3_EXT_CRL_add_nconf +X509V3_EXT_d2i +X509V3_extensions_print +X509V3_EXT_free +X509V3_EXT_get +X509V3_EXT_get_nid +X509V3_EXT_i2d +X509V3_EXT_nconf +X509V3_EXT_nconf_nid +X509V3_EXT_print +X509V3_EXT_print_fp +X509V3_EXT_REQ_add_nconf +X509V3_EXT_val_prn +X509V3_get_string +X509V3_get_value_bool +X509V3_get_value_int +X509V3_NAME_from_section +X509V3_section_free +X509V3_set_conf_lhash +X509V3_set_ctx +X509V3_set_nconf +X509V3_string_free +X509_verify +X509_verify_cert +X509_verify_cert_error_string +X509_VERIFY_PARAM_add0_policy +X509_VERIFY_PARAM_add0_table +X509_VERIFY_PARAM_add1_host +X509_VERIFY_PARAM_clear_flags +X509_VERIFY_PARAM_free +X509_VERIFY_PARAM_get0 +X509_VERIFY_PARAM_get0_name +X509_VERIFY_PARAM_get0_peername +X509_VERIFY_PARAM_get_count +X509_VERIFY_PARAM_get_depth +X509_VERIFY_PARAM_get_flags +X509_VERIFY_PARAM_inherit +X509_VERIFY_PARAM_lookup +X509_VERIFY_PARAM_new +X509_VERIFY_PARAM_set1 +X509_VERIFY_PARAM_set1_email +X509_VERIFY_PARAM_set1_host +X509_VERIFY_PARAM_set1_ip +X509_VERIFY_PARAM_set1_ip_asc +X509_VERIFY_PARAM_set1_name +X509_VERIFY_PARAM_set1_policies +X509_VERIFY_PARAM_set_depth +X509_VERIFY_PARAM_set_flags +X509_VERIFY_PARAM_set_hostflags +X509_VERIFY_PARAM_set_purpose +X509_VERIFY_PARAM_set_time +X509_VERIFY_PARAM_set_trust +X509_VERIFY_PARAM_table_cleanup +# pcre +pcre16_assign_jit_stack +pcre16_callout +pcre16_compile +pcre16_compile2 +pcre16_config +pcre16_copy_named_substring +pcre16_copy_substring +pcre16_dfa_exec +pcre16_exec +pcre16_free +pcre16_free_study +pcre16_free_substring +pcre16_free_substring_list +pcre16_fullinfo +pcre16_get_named_substring +pcre16_get_stringnumber +pcre16_get_stringtable_entries +pcre16_get_substring +pcre16_get_substring_list +pcre16_jit_exec +pcre16_jit_free_unused_memory +pcre16_jit_stack_alloc +pcre16_jit_stack_free +pcre16_maketables +pcre16_malloc +pcre16_pattern_to_host_byte_order +pcre16_refcount +pcre16_stack_free +pcre16_stack_guard +pcre16_stack_malloc +pcre16_study +pcre16_utf16_to_host_byte_order +pcre16_version +pcre32_assign_jit_stack +pcre32_callout +pcre32_compile +pcre32_compile2 +pcre32_config +pcre32_copy_named_substring +pcre32_copy_substring +pcre32_dfa_exec +pcre32_exec +pcre32_free +pcre32_free_study +pcre32_free_substring +pcre32_free_substring_list +pcre32_fullinfo +pcre32_get_named_substring +pcre32_get_stringnumber +pcre32_get_stringtable_entries +pcre32_get_substring +pcre32_get_substring_list +pcre32_jit_exec +pcre32_jit_free_unused_memory +pcre32_jit_stack_alloc +pcre32_jit_stack_free +pcre32_maketables +pcre32_malloc +pcre32_pattern_to_host_byte_order +pcre32_refcount +pcre32_stack_free +pcre32_stack_guard +pcre32_stack_malloc +pcre32_study +pcre32_utf32_to_host_byte_order +pcre32_version +pcre_assign_jit_stack +pcre_callout +pcre_compile +pcre_compile2 +pcre_config +pcre_copy_named_substring +pcre_copy_substring +PCRE_DECLARE_INTEGER_PARSER +pcre_dfa_exec +pcre_exec +pcre_free +pcre_free_study +pcre_free_substring +pcre_free_substring_list +pcre_fullinfo +pcre_get_named_substring +pcre_get_stringnumber +pcre_get_stringtable_entries +pcre_get_substring +pcre_get_substring_list +pcre_jit_exec +pcre_jit_free_unused_memory +pcre_jit_stack_alloc +pcre_jit_stack_free +PCRE_MAKE_PARSER +pcre_maketables +pcre_malloc +pcre_pattern_to_host_byte_order +pcreposix_regcomp +pcreposix_regerror +pcreposix_regexec +pcreposix_regfree +pcre_refcount +pcre_stack_free +pcre_stack_guard +pcre_stack_malloc +pcre_study +pcre_version diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/pdfunctions.cfg b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/pdfunctions.cfg new file mode 100644 index 0000000..02a2813 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/pdfunctions.cfg @@ -0,0 +1,3 @@ +{ + "functions" : [ "strcpy" ] +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/sensitivesink.cfg b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/sensitivesink.cfg new file mode 100644 index 0000000..288ebcd --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/sensitivesink.cfg @@ -0,0 +1,3 @@ +{ + "getaddrinfo" : 0 +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/sensitivesource.cfg b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/sensitivesource.cfg new file mode 100644 index 0000000..b3ec9f7 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/conf/sensitivesource.cfg @@ -0,0 +1,3 @@ +{ + "getpass" : -1 +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveConstantArgCheck.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveConstantArgCheck.cpp new file mode 100644 index 0000000..ebd0baf --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveConstantArgCheck.cpp @@ -0,0 +1,194 @@ +/* + * NaiveConstantArgCheck + * + * There are some functions that you do not want constant values + * as arguments... some such are seed functions to (P)RNGs. + * This attempts some basic detection of such cases, but is quite + * naive + * + * Note: + * Things would be better if this used the TargetCallSitesPass. + * Mostly wanted to show using instruction iteration in an + * example. There are many improvements to be made.. C'est la vie. + * + */ + +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/Pass.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Analysis/LazyCallGraph.h" + +#include +#include +#include + +#include +#include +#include + +using namespace llvm; + +#include "NaiveConstantArgCheck.h" + +void +NaiveConstantArgCheck::getAnalysisUsage(AnalysisUsage &AU) const +{ +} + +bool +NaiveConstantArgCheck::runOnModule(Module &M) +{ + errs() << "Running naive constant argument check pass\n"; + + Json::Value caDict; + std::ifstream cfgFileStream; + std::map> _existingToCheck; + + cfgFileStream.open(this->getConfigFilePath()); + cfgFileStream >> caDict; + cfgFileStream.close(); + + Json::Value::Members mems = caDict.getMemberNames(); + for (auto memberIt = mems.begin(); memberIt != mems.end(); ++memberIt) { + std::string fnName = *memberIt; + unsigned fnArgIdx = caDict[fnName].asUInt(); + + // Lookup Function by name in this module + Function *f = M.getFunction(fnName); + if (f == NULL) { + continue; + } + + // If arg count for target fn and this fn don't match, don't add it. + if (f->arg_size() == 0 || f->arg_size() <= fnArgIdx) { + continue; + } + _existingToCheck[fnName] = std::make_pair(f, fnArgIdx); + } + + /* + * Go through every function (cept some) + * Go through every call instruction + * Determine if the called function is a sink function + * Naively check if the argument in question is constant (to that function) + * If so, add to result set. + * See User in naive sensitive data leak for another way to do things. + * + */ + for (auto &f : M) { + Function *parentFunction = &f; + + /* + * Skip analyzing any functions we check the calling of. + */ + auto etcIt = _existingToCheck.begin(); + for ( ; etcIt != _existingToCheck.end(); ++etcIt) { + auto fi = etcIt->second; + Function *ignoreMe = fi.first; + if (ignoreMe == parentFunction) { + break; + } + } + if (etcIt != _existingToCheck.end()) { + continue; + } + + /* + * Iterate through the instructions that compose the function. + * + * Instead of going through instructions to find CallInst, etc, + * we could use an instruction visitor. For such an example, see the + * visitor code found in the intflip base above this directory. + * + * Further, as per two comments above and code in another file, could + * just utilize the User list associated with the Function. + */ + for (inst_iterator iIt = inst_begin(f); iIt != inst_end(f); ++iIt) { + /* + * Check if the current instruction is a call instruction. If not, + * skip to the next instruction. + * + * Some might use: + * if (CallInst *ci = dyn_cast(&fInst) { + * } else if (InvokeInst *ii ....) + * instead... + * + */ + Instruction *fInst = &*iIt; + if (!isa(fInst) && !isa(fInst)) { + continue; + } + DILocation *lineInfo = fInst->getDebugLoc().get(); + CallSite cs(fInst); + Function *calledFunction = cs.getCalledFunction(); + + auto fIt = _existingToCheck.begin(); + for (; fIt != _existingToCheck.end(); ++fIt) { + auto j = fIt->second; + Function *badFunc = j.first; + unsigned idx = j.second; + + if (badFunc == calledFunction) { + + // We just assume there needs to be enough arguments + // Improvement would check function signature or something. + unsigned nOps = cs.getNumArgOperands(); + if (nOps <= idx) { + continue; + } + + // Get argument by index. + Value *arg = cs.getArgOperand(idx); + + // and determine if this argument is constant + if (!isa(arg)) { + continue; + } + + /* + * Since the arg was constant and was to a fn of interest, + * then save off this info as a finding to display. + * + */ + NaiveConstantArgCheckResult n(parentFunction, + calledFunction, arg, idx, lineInfo); + n.printResult(); + } + } + } + } + return false; +} + +void +NaiveConstantArgCheckResult::printResult() +{ + bool hl = hasLocation(); + bool hn = caller->hasName(); + + if (hn && hl) { + unsigned line = loc->getLine(); + StringRef file = loc->getFilename(); + StringRef fdir = loc->getDirectory(); + std::cout << " !" << caller->getName().str() << " calls " + << callee->getName().str() << " where arg index: " + << argIndex << " is a constant\n"; + std::cout << " " << file.str() << ":" << line << "\n"; + } else if (hn && !hl) { + std::cout << " !" << caller->getName().str() << " calls " + << callee->getName().str() << " with argument " + << argIndex << " of constant value: \n "; + argument->dump(); + } +} + +char NaiveConstantArgCheck::ID = 0; +static RegisterPass XX("naive-con-arg-check", "Basic constant arg check"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveConstantArgCheck.h b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveConstantArgCheck.h new file mode 100644 index 0000000..aaee334 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveConstantArgCheck.h @@ -0,0 +1,46 @@ +#ifndef _NAIVECONSTANTARGCHECK_H +#define _NAIVECONSTANTARGCHECK_H + +class NaiveConstantArgCheckResult { + Function *caller; + Function *callee; + Value *argument; + unsigned argIndex; + DILocation *loc; + +public: + NaiveConstantArgCheckResult(Function *aCaller, + Function *aCallee, Value *arg, unsigned idx, DILocation *d) : + caller(aCaller), callee(aCallee), argument(arg), argIndex(idx), loc(d) {}; + + Function *getCaller() { return caller; } + Function *getCallee() { return callee; } + Value *getArgument() { return argument; } + unsigned getArgumentIndex() { return argIndex; } + bool hasLocation() { + if (loc == NULL) { + return false; + } + return true; + } + DILocation *getLocation() { return loc; } + void printResult(); +}; + +struct NaiveConstantArgCheck : public ModulePass { +private: + std::vector _results; + std::string configFilePath; + +public: + static char ID; + + NaiveConstantArgCheck() : ModulePass(ID) {} + + virtual bool runOnModule(Module &M); + virtual void getAnalysisUsage(AnalysisUsage &) const; + + void setConfigFilePath(std::string a) { configFilePath = a; } + std::string getConfigFilePath() { return configFilePath; } +}; +#endif // !_CONSTANTARGCHECK_H diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveFileDescLeak.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveFileDescLeak.cpp new file mode 100644 index 0000000..77a82e3 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveFileDescLeak.cpp @@ -0,0 +1,180 @@ +/* + * NaiveFileDescLeak + * + * Look for cases where + * + * %k = call srcfnthatreturnsfd + * ... + * + * and no call close %k in the same function + */ + +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/Pass.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/CallSite.h" +#include "llvm/Support/raw_ostream.h" + +#include + +using namespace llvm; + +#include "StoreCollector.h" +#include "TargetCallSitesPass.h" +#include "NaiveFileDescLeak.h" + +void +NaiveFileDescLeak::getAnalysisUsage(AnalysisUsage &AU) const +{ + AU.addRequired(); + AU.setPreservesCFG(); +} + +void +NaiveFileDescLeak::printLeak(TargetCallSite *s) +{ + Instruction *i = s->getInstruction(); + DILocation *loc = i->getDebugLoc().get(); + + errs() << " ! file descriptor leak:\n"; + if (loc) { + errs() << " " << s->getCaller()->getName() << " calls " + << s->getCalled()->getName() << " at " << loc->getFilename() + << ":" << loc->getLine() << " and never closes\n"; + } else { + // No debug info. + errs() << " " << s->getCaller()->getName() << " calls " + << s->getCalled()->getName() << " and never closes \n"; + i->getDebugLoc().dump(); + } +} + +void +NaiveFileDescLeak::printLikelyFP(TargetCallSite *s, std::string reason) +{ + Instruction *i = s->getInstruction(); + DILocation *loc = i->getDebugLoc().get(); + + errs() << " ! file descriptor FP likely:\n"; + if (loc) { + errs() << " " << s->getCaller()->getName() << " calls " + << s->getCalled()->getName() << " at " << loc->getFilename() + << ":" << loc->getLine() << " reason: " << reason << "\n"; + } else { + // No debug info. + errs() << " " << s->getCaller()->getName() << " calls " + << s->getCalled()->getName() << " reason: " << reason << "\n"; + i->getDebugLoc().dump(); + } +} + +bool +NaiveFileDescLeak::runOnModule(Module &M) +{ + errs() << "Running naive file descriptor leak pass\n"; + + /* + * Make use of the result of running the TargetCallSitesPass. + * It gives locations where file descriptors were created + * and locations of file descriptor destroyer calls (e.g. close(2)). + */ + TargetCallSitesPass &p = getAnalysis(); + if (p.src_empty()) { + return false; + } + + /* + * If there exist no close-like calls, then every source is + * leaking or we are missing some function that closes (e.g. + * it exists in a different compilation unit (Module) or we + * do not know some call from an API we externalized does a + * close). + */ + if (p.snk_empty()) { + errs() << " ! No close-like calls found.\n"; + for (auto tcs = p.src_begin(); tcs != p.src_end(); ++tcs) { + TargetCallSite *s = tcs->get(); + printLeak(s); + } + return false; + } + /* + * For every open()-like, if there is not even a use of the + * Value, then we know there is something up. + */ + for (auto srcIt = p.src_begin(); srcIt != p.src_end(); ) { + TargetCallSite *srcSite = &*srcIt->get(); + Value *possiblyLeaked = srcSite->getTarget(); + if (possiblyLeaked->user_empty()) { + printLeak(srcSite); + srcIt = p.src_erase(srcIt); + } else { + ++srcIt; + } + } + + for (auto snkIt = p.snk_begin(); snkIt != p.snk_end(); ++snkIt) { + TargetCallSite *snkSite = &*snkIt->get(); + Value *closingVar = snkSite->getTarget(); + if (isa(closingVar)) { + printLikelyFP(snkSite, "Value is an Argument to parent function (unsupported)"); + } else if (isa(closingVar)) { + printLikelyFP(snkSite, "Value is a GlobalVariable (unsupported)"); + } + } + + /* + * Now, for every close()-like, go through and see if we can easily + * find a source open(). If we can, we remove the value from being + * a possible leak. + * + * Note that this is naive. Note that if you use the PHINode axe that + * you may have FN. Etc etc etc :P + */ + for (auto snkIt = p.snk_begin(); snkIt != p.snk_end(); ) { + TargetCallSite *snkSite = &*snkIt->get(); + Value *closedValue = snkSite->getTarget(); + bool remd = false; + for (auto srcIt = p.src_begin(); srcIt != p.src_end(); ) { + TargetCallSite *srcSite = &*srcIt->get(); + Value *possiblyLeaked = srcSite->getTarget(); + if (closedValue == possiblyLeaked) { + snkIt = p.snk_erase(snkIt); + srcIt = p.src_erase(srcIt); + remd = true; + break; + } else { + ++srcIt; + } + } + if (remd == false) { + ++snkIt; + } + } + + /* + * If we did not remove some sources then either: + * (a) we failed to track things properly (very likely! :D) + * (b) we have some fd leak + * these are basic, weak assumptions. + */ + for (auto srcIt = p.src_begin(); srcIt != p.src_end(); ++srcIt) { + TargetCallSite *srcSite = &*srcIt->get(); + Value *v = srcSite->getTarget(); + if (isa(v)) { + printLikelyFP(srcSite, "Value is an Argument to parent function (unsupported)"); + } else if (isa(v)) { + printLikelyFP(srcSite, "Value is a GlobalVariable (unsupported)"); + } else { + printLeak(srcSite); + } + } + return false; +} + +char NaiveFileDescLeak::ID = 0; +static RegisterPass XX("naive-fd-leak", "Naive fd leak"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveFileDescLeak.h b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveFileDescLeak.h new file mode 100644 index 0000000..f412c6a --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveFileDescLeak.h @@ -0,0 +1,22 @@ +#ifndef __NAIVEFILEDESCLEAK_H +#define __NAIVEFILEDESCLEAK_H + +struct NaiveFileDescLeak : public ModulePass { +public: + static char ID; + + typedef std::pair FuncArg; + typedef std::map FuncArgMap; + + NaiveFileDescLeak() : ModulePass(ID) { } + virtual bool runOnModule(Module &); + virtual void getAnalysisUsage(AnalysisUsage &) const; + + void printLeak(TargetCallSite *s); + void printLikelyFP(TargetCallSite *s, std::string r); + +private: +}; + + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveSensitiveDataLeak.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveSensitiveDataLeak.cpp new file mode 100644 index 0000000..203cf8c --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveSensitiveDataLeak.cpp @@ -0,0 +1,104 @@ +/* + * NaiveSensitiveDataLeak + * + * It makes use of the TargetCallSitesPass as a way to get uses and + * target values of interest (sinks, sources, and the related data); + * it runs prior to this pass. + * + * There is no handling of special entry points or callbacks that are + * tainted a priori. + */ + +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/Pass.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/Support/raw_ostream.h" + +#include + +using namespace llvm; + +#include "TargetCallSitesPass.h" +#include "NaiveSensitiveDataLeak.h" + +void +NaiveSensitiveDataLeak::getAnalysisUsage(AnalysisUsage &AU) const +{ + AU.addRequired(); + AU.setPreservesCFG(); +} + +bool +NaiveSensitiveDataLeak::runOnModule(Module &M) +{ + errs() << "Running naive sensitive data leak pass\n"; + /* + * We can use the upstream analysis from the TargetCallSitesPass. + * Always nice use already available tools. + */ + TargetCallSitesPass &p = getAnalysis(); + + + if (p.src_empty()) { + return false; + } + if (p.snk_empty()) { + return false; + } + + // For each sink value available, we must attempt to trace it to a source + for (auto snkIt = p.snk_begin(); snkIt != p.snk_end(); ++snkIt) { + TargetCallSite *snkSite = &*snkIt->get(); + Value *leakData = snkSite->getTarget(); + auto srcIt = p.src_end(); + --srcIt; + bool brk_back = false; + for (; brk_back == false; --srcIt) { + if (srcIt == p.src_begin()) { + brk_back = true; + } + TargetCallSite *srcSite = &*srcIt->get(); + Value *originalSourceData = srcSite->getTarget(); + Value *sourceData = originalSourceData; + if (isa(leakData) || isa(leakData)) { + if (leakData == sourceData) { + printResult(srcSite, snkSite); + break; + } + } + } + } + return false; + +} + +void +NaiveSensitiveDataLeak::printResult(TargetCallSite *srcSite, + TargetCallSite *snkSite) +{ + Instruction *snkIn = snkSite->getInstruction(); + Instruction *srcIn = srcSite->getInstruction(); + + DILocation *snkLoc = snkIn->getDebugLoc().get(); + DILocation *srcLoc = srcIn->getDebugLoc().get(); + + errs() << " ! sensitive data leak \n"; + errs() << " " << snkSite->getCaller()->getName() + << " calls " << snkSite->getCalled()->getName() + << " where arg idx #" << snkSite->getArgIndex() + << " is tainted sensitive. file: " << snkLoc->getFilename() + << " line: " << snkLoc->getLine() << "\n"; + errs() << " source: " << srcSite->getCaller()->getName() + << " calls " << srcSite->getCalled()->getName() + << " at line: "<< srcLoc->getLine() << " of file: " + << srcLoc->getFilename() << "\n"; +} + +char NaiveSensitiveDataLeak::ID = 0; +static RegisterPass XX("naive-sensitive-leak", + "Naive sensitive data leak"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveSensitiveDataLeak.h b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveSensitiveDataLeak.h new file mode 100644 index 0000000..c1cc248 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveSensitiveDataLeak.h @@ -0,0 +1,19 @@ +#ifndef __NAIVESENSITIVEDATALEAK_H +#define __NAIVESENSITIVEDATALEAK_H + +struct NaiveSensitiveDataLeak : public ModulePass { + static char ID; + typedef std::pair FuncArg; + typedef std::map FuncArgMap; + + NaiveSensitiveDataLeak() : ModulePass(ID) { } + virtual bool runOnModule(Module &); + virtual void getAnalysisUsage(AnalysisUsage &) const; +private: + void parseAndCheckConfig(FuncArgMap *, bool); + void printResult(TargetCallSite *srcSite, TargetCallSite *snkSite); + +}; + + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveSensitiveDataLeak_ahead.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveSensitiveDataLeak_ahead.cpp new file mode 100644 index 0000000..fb23aaf --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/NaiveSensitiveDataLeak_ahead.cpp @@ -0,0 +1,155 @@ +/* + * XXX I accidentally committed this file.. so maybe ignore.. but + * leaving it because it might be useful to read for someone. + */ + +/* + * NaiveSensitiveDataLeak + * + * It makes use of the TargetCallSitesPass as a way to get uses and + * target values of interest (sinks, sources, and the related data); + * it runs prior to this pass. + * + * It is using the StoreCollector a poor means of tracking + * memory load/store use. That could be a pass but it isn't. There + * are much better ways for handling this... Andersen's AA or + * MemoryDependenceAnalysis. The former is a bit more memory intensive + * and agressive, while the latter is ``lazy''. + * + * There is no handling of special entry points or callbacks that are + * tainted a priori. + */ + +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/Pass.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/Support/raw_ostream.h" + +#include + +using namespace llvm; + +#include "TargetCallSitesPass.h" +#include "NaiveSensitiveDataLeak.h" +#include "StoreCollector.h" + +void +NaiveSensitiveDataLeak::getAnalysisUsage(AnalysisUsage &AU) const +{ + AU.addRequired(); + AU.preservesCFG(); +} + +bool +NaiveSensitiveDataLeak::runOnModule(Module &M) +{ + errs() << "Running naive sensitive data leak pass\n"; + TargetCallSitesPass &p = getAnalysis(); + + + if (p.src_empty()) { + return false; + } + if (p.snk_empty()) { + return false; + } + + StoreCollector *store = new StoreCollector(); + + // For each sink value available, we must attempt to trace it to a source + for (auto snkIt = p.snk_begin(); snkIt != p.snk_end(); ++snkIt) { + TargetCallSite *snkSite = &*snkIt->get(); + Value *leakData = snkSite->getTarget(); + +#if 0 + /* Lazily refresh the StoreInst holder */ + if (snkSite->getCaller() != store->getFunction()) { + store->collect(snkSite->getCaller()); + } +#endif + + for (auto srcIt = p.src_begin(); srcIt != p.src_end(); ++srcIt) { + TargetCallSite *srcSite = &*srcIt->get(); + Value *originalSourceData = srcSite->getTarget(); + Value *sourceData = originalSourceData; + + while (true) { + if (isa(leakData) || isa(leakData)) { + if (leakData == sourceData) { + printResult(srcSite, snkSite); + } + /* + * Does not handle propagators at this point :( + * so any call is either a source or dead end. + */ + break; + } + + if (isa(leakData)) { + break; + } + if (isa(leakData)) { + break; + } + + if (CastInst *ci = dyn_cast(leakData)) { + User *cu = cast(ci); + leakData = cu->getOperand(0); + continue; + } + if (LoadInst *li = dyn_cast(leakData)) { + Value *memLoc = li->getPointerOperand(); + leakData = store->find(memLoc); + assert(leakData != NULL && "memLoc not in storeCollect"); + continue; + } + if (GetElementPtrInst *gp = + dyn_cast(leakData)) { + leakData = gp->getPointerOperand(); + continue; + } + if (isa(leakData)) { + errs() << "Data leaked escaped function analysis, unknown result.\n"; + break; + } + errs() << "Unhandled:\n "; + leakData->dump(); + assert(0 == 1); + } + } + } + delete store; + return false; + +} + +void +NaiveSensitiveDataLeak::printResult(TargetCallSite *srcSite, + TargetCallSite *snkSite) +{ + Instruction *snkIn = snkSite->getInstruction(); + Instruction *srcIn = srcSite->getInstruction(); + + DILocation *snkLoc = snkIn->getDebugLoc().get(); + DILocation *srcLoc = srcIn->getDebugLoc().get(); + + errs() << " ! sensitive data leak \n"; + errs() << " " << snkSite->getCaller()->getName() + << " calls " << snkSite->getCalled()->getName() + << " where arg idx #" << snkSite->getArgIndex() + << " is tainted sensitive. file: " << snkLoc->getFilename() + << " line: " << snkLoc->getLine() << "\n"; + errs() << " source: " << srcSite->getCaller()->getName() + << " calls " << srcSite->getCalled()->getName() + << " at line: "<< srcLoc->getLine() << " of file: " + << srcLoc->getFilename() << "\n"; +} + +char NaiveSensitiveDataLeak::ID = 0; +static RegisterPass XX("naive-sensitive-leak", + "Naive sensitive data leak"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScan.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScan.cpp new file mode 100644 index 0000000..363a394 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScan.cpp @@ -0,0 +1,155 @@ +/* + * + * PotentiallyDangerousScan + * + * This is yet another naive scan :-). This is just + * checking for CWE 676 which is just the use of potentially + * dangerous functions. + * + * There are, again, multiple ways that one might do this + * check in LLVM (ie, ignoring objdump | grep :)). You + * could use a visitor, instruction iteration, or even + * the User checking of the functions in question. + * Each of those are valid, but here we perform this + * by relying on the CallGraph pass being run prior + * to this pass. We then just go through those results + * and perform the analysis. So this code illustrates + * pass dependency (via getAnalysisUsage()) and using + * the CallgraphPass as a source of data. + * + */ +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/Pass.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Analysis/CallGraph.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace llvm; + +#include "PotentiallyDangerousScan.h" + +/* + * This informs the pass manager that prior to running this pass, the + * CallGraphWrapperPass should be run. This helps in ordering passes so + * you can have a reasonable expectation of state of the IR (or other) + * upon entry to your runOn*() function. + * + */ +void +PotentiallyDangerousScan::getAnalysisUsage(AnalysisUsage &AU) const +{ + AU.addRequired(); +} + + +bool +PotentiallyDangerousScan::runOnModule(Module &M) +{ + Json::Value fnDict; + std::ifstream cfgFileStream; + std::vector pdFunctions; + + /* + * Make use of the libjsoncpp to ingest a json config file. + * This file houses the set of functions that one might consider + * to fall under CWE 676. Then see if any of them exist in this + * module. + * + * I am being trusting of the configs.. + */ + cfgFileStream.open(this->getConfigFilePath()); + cfgFileStream >> fnDict; + cfgFileStream.close(); + Json::Value fnList = fnDict["functions"]; + assert(fnList.isArray() && "fnList was not an array"); + Json::ArrayIndex aLen = fnList.size(); + for (Json::ArrayIndex ai = 0; ai < aLen; ai++) { + Function *f = M.getFunction(fnList[ai].asString()); + if (f != NULL) { + pdFunctions.push_back(f); + } + } + + /* + * A great thing about the pass design is that you can share information + * between them. Here we are getting the call graph as previously built + * by the call graph pass. If you see the getAnalysisUsage() function at + * the bottom of this file, you will note the dependency on that pass + * being run prior to this one. + * + */ + CallGraphWrapperPass &cgPass = getAnalysis(); + + /* store results in pairs of caller and callee */ + typedef std::pair PDRes; + std::vector results; + + /* + * The container we go through is a map with key Function * and value of + * CallGraphNode list. The key is the caller and value the callees. + * + * The first entry this map is NULL caller and contains the set of all functions. + * + */ + CallGraph &cg = cgPass.getCallGraph(); + for (auto cgIt = cg.begin(); cgIt != cg.end(); ++cgIt) { + /* + * Calling function + */ + Function *caller = const_cast(cgIt->first); + if (caller == NULL) { + continue; + } + + CallGraphNode &callees = *cgIt->second; + if (callees.size() == 0) { + continue; + } + + /* + * We iterate through a vector of CallRecords, which is: + * typedef std::pair CallRecord; + * in which each CGN is a called function. + * + */ + for (const auto &crIt : callees) { + if (Function *callee = crIt.second->getFunction()) { + + /* determine if the callee is something we consider dangerous */ + for (auto pdIt = pdFunctions.begin(); pdIt != pdFunctions.end(); ++pdIt) { + Function *pdFn = *pdIt; + if (pdFn == callee) { + /* Save a result since matched a pd function */ + auto r = std::make_pair(caller, callee); + results.push_back(r); + break; + } + } + } + } + } + + errs() << "Results for potentially dangerous function call usage:\n"; + for (auto rIt = results.begin(); rIt != results.end(); ++rIt) { + Function *caller = rIt->first; + Function *callee = rIt->second; + errs() << " " << caller->getName().str() << " calls " << \ + callee->getName().str() << "\n"; + } + + return false; +} + +char PotentiallyDangerousScan::ID = 1; +static RegisterPass XX("pot-danger", "Potentially Dangerous Call (CWE 676)"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScan.h b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScan.h new file mode 100644 index 0000000..cf0aff0 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScan.h @@ -0,0 +1,19 @@ +#ifndef __POTENTIALLYDANGEROUSSCAN_H +#define __POTENTIALLYDANGEROUSSCAN_H + +struct PotentiallyDangerousScan : public ModulePass { +private: + std::string _cfgFilePath; + +public: + static char ID; + + PotentiallyDangerousScan() : ModulePass(ID) { } + virtual bool runOnModule(Module &); + virtual void getAnalysisUsage(AnalysisUsage &) const; + + void setConfigFilePath(std::string s) { _cfgFilePath = s; } + std::string getConfigFilePath() { return _cfgFilePath; } +}; + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanFunctionPass.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanFunctionPass.cpp new file mode 100644 index 0000000..d5741e2 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanFunctionPass.cpp @@ -0,0 +1,97 @@ +/* + * + * PotentiallyDangerousScanFunctionPass + * + * This example implements the scan as a function pass and + * then iterate through the instructions for calls. This could + * also be done as a visitor. + * + */ +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/Pass.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Analysis/CallGraph.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace llvm; + +#include "PotentiallyDangerousScanFunctionPass.h" + +void +PotentiallyDangerousScanFunctionPass::getAnalysisUsage(AnalysisUsage &AU) const +{ +} + +void +PotentiallyDangerousScanFunctionPass::setConfigFilePath(std::string s) +{ + + _cfgFilePath = s; + pdFunctions.clear(); + lookupPDFunctions = true; +} + + +bool +PotentiallyDangerousScanFunctionPass::runOnFunction(Function &f) +{ + std::string caller = "unnamed_func"; + + if (lookupPDFunctions) { + Json::Value fnDict; + std::ifstream cfgFileStream; + + cfgFileStream.open(this->getConfigFilePath()); + cfgFileStream >> fnDict; + cfgFileStream.close(); + Json::Value fnList = fnDict["functions"]; + assert(fnList.isArray() && "fnList was not an array"); + Json::ArrayIndex aLen = fnList.size(); + Module *m = f.getParent(); + for (Json::ArrayIndex ai = 0; ai < aLen; ai++) { + Function *pdFn = m->getFunction(fnList[ai].asString()); + if (pdFn != NULL) { + pdFunctions.push_back(pdFn); + } + } + lookupPDFunctions = false; + } + // Nothing to find. + if (pdFunctions.empty()) { + return false; + } + + if (f.hasName()) { + caller = f.getName().str(); + } + for (auto ii = inst_begin(f); ii != inst_end(f); ++ii) { + Instruction *in = &*ii; + if (isa(in) || isa(in)) { + CallSite cs(in); + Function *called = cs.getCalledFunction(); + for (auto pdi = pdFunctions.begin(); pdi != pdFunctions.end(); ++pdi) { + Function *pdf = *pdi; + if (called == pdf) { + std::cout << " " << caller << " called " << pdf->getName().str() << "\n"; + break; + } + } + } + } + return false; +} + +char PotentiallyDangerousScanFunctionPass::ID = 1; +static RegisterPass XX("pot-danger-function-pas", "Potentially Dangerous Call (CWE 676) func pass"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanFunctionPass.h b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanFunctionPass.h new file mode 100644 index 0000000..351191e --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanFunctionPass.h @@ -0,0 +1,25 @@ +#ifndef __POTENTIALLYDANGEROUSSCANFUNCTIONPASS_H +#define __POTENTIALLYDANGEROUSSCANFUNCTIONPASS_H + +struct PotentiallyDangerousScanFunctionPass : public FunctionPass { +private: + std::string _cfgFilePath; + std::vector pdFunctions; + bool lookupPDFunctions; + + +public: + static char ID; + + PotentiallyDangerousScanFunctionPass() : FunctionPass(ID) { + pdFunctions.clear(); + lookupPDFunctions = true; + } + virtual bool runOnFunction(Function &); + virtual void getAnalysisUsage(AnalysisUsage &) const; + + std::string getConfigFilePath() { return _cfgFilePath; } + void setConfigFilePath(std::string); +}; + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanUserMethod.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanUserMethod.cpp new file mode 100644 index 0000000..a32ec13 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanUserMethod.cpp @@ -0,0 +1,76 @@ +/* + * PotentiallyDangerousScanUserMethodUserMethod + * + * This example is implemented looking at User list associated + * with p.d. function. + * + * Similar to PotentiallyDangerousScanUserMethod and + * PotentiallyDangerousScanUserMethodFunctionPass + * + */ +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/Pass.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/CallSite.h" +#include "llvm/Analysis/CallGraph.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace llvm; + +#include "PotentiallyDangerousScanUserMethod.h" + +void +PotentiallyDangerousScanUserMethod::getAnalysisUsage(AnalysisUsage &AU) const +{ +} + + +bool +PotentiallyDangerousScanUserMethod::runOnModule(Module &M) +{ + Json::Value fnDict; + std::ifstream cfgFileStream; + + cfgFileStream.open(this->getConfigFilePath()); + cfgFileStream >> fnDict; + cfgFileStream.close(); + Json::Value fnList = fnDict["functions"]; + assert(fnList.isArray() && "fnList was not an array"); + Json::ArrayIndex aLen = fnList.size(); + for (Json::ArrayIndex ai = 0; ai < aLen; ai++) { + Function *f = M.getFunction(fnList[ai].asString()); + if (f == NULL) { + continue; + } + for (auto fi = f->user_begin(); fi != f->user_end(); ++fi) { + User *u = *fi; + if (isa(u) || isa(u)) { + + /* CallSite is a nice container for call and invoke */ + CallSite cs(u); + Function *caller = cs.getCaller(); + std::string callerName = "unnamed_func"; + if (caller->hasName()) { + callerName = caller->getName().str(); + } + std::cout << " " << callerName << " calls " + << fnList[ai].asString() << "\n"; + } + } + } + return false; +} + +char PotentiallyDangerousScanUserMethod::ID = 1; +static RegisterPass XX("pot-danger-user-method", "Potentially Dangerous Call (CWE 676) done with User list"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanUserMethod.h b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanUserMethod.h new file mode 100644 index 0000000..cfd3175 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/PotentiallyDangerousScanUserMethod.h @@ -0,0 +1,19 @@ +#ifndef __POTENTIALLYDANGEROUSSCANUSERMETHOD_H +#define __POTENTIALLYDANGEROUSSCANUSERMETHOD_H + +struct PotentiallyDangerousScanUserMethod : public ModulePass { +private: + std::string _cfgFilePath; + +public: + static char ID; + + PotentiallyDangerousScanUserMethod() : ModulePass(ID) { } + virtual bool runOnModule(Module &); + virtual void getAnalysisUsage(AnalysisUsage &) const; + + void setConfigFilePath(std::string s) { _cfgFilePath = s; } + std::string getConfigFilePath() { return _cfgFilePath; } +}; + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/StoreCollector.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/StoreCollector.cpp new file mode 100644 index 0000000..12287d2 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/StoreCollector.cpp @@ -0,0 +1,38 @@ +/* + * There are methods that are much better than what I am doing. There are + * aggressive methods such as Andersen's Alias Analysis and there are + * lazy methods such as making use of the MemoryDependenceAnalysis API. + * + * What is going on here is quite basic and will miss many things. + */ +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" + +#include +#include + +using namespace llvm; + +#include "StoreCollector.h" + +void +StoreCollector::collect(Function *f) +{ + collectedFunction = f; + if (storeMap.empty() == false) { + storeMap.clear(); + } + for (auto ii = inst_begin(*f); ii != inst_end(*f); ++ii) { + Instruction *in = &*ii; + if (!isa(in)) { + continue; + } + StoreInst *s = cast(in); + Value *storedVal = s->getValueOperand(); + Value *storedLoc = s->getPointerOperand(); + storeMap[storedLoc] = storedVal; + continue; + } +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/StoreCollector.h b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/StoreCollector.h new file mode 100644 index 0000000..a0cca8b --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/StoreCollector.h @@ -0,0 +1,26 @@ +#ifndef __STORECOLLECTOR_H +#define __STORECOLLECTOR_H + +class StoreCollector { + // key is pointer and value is the stored value + std::map storeMap; + Function *collectedFunction; + +public: + StoreCollector() { + collectedFunction = NULL; + } + void collect(Function *); + Function *getFunction() { + return collectedFunction; + } + + Value *find(Value *storeLoc) { + auto s = storeMap.find(storeLoc); + if (s == storeMap.end()) { + return NULL; + } + return s->second; + } +}; +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/TargetCallSitesPass.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/TargetCallSitesPass.cpp new file mode 100644 index 0000000..85cd988 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/TargetCallSitesPass.cpp @@ -0,0 +1,116 @@ +/* + * This is a dependency for a few of the passes. Collects + * call sites and organizes them by TargetCallType. + * + */ + +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/Pass.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/CallSite.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +#include +#include +#include + +using namespace llvm; + +#include "TargetCallSitesPass.h" +#include "../Transform/FunctionExternalizer.h" + +void +TargetCallSitesPass::getAnalysisUsage(AnalysisUsage &AU) const +{ +} + +void +TargetCallSitesPass::parseConfig(std::string configFilePath, TargetCallType tct, + Module *M) +{ + Json::Value dict; + std::ifstream strm; + + // XXX quite trusting + strm.open(configFilePath); + strm >> dict; + strm.close(); + Json::Value::Members mems = dict.getMemberNames(); + for (auto memIt = mems.begin(); memIt != mems.end(); ++memIt) { + std::string fnName = *memIt; + + int argIdx = dict[fnName].asInt(); + assert(argIdx >= -1 && "Argument index should be >= -1"); + + /* + * Determine if the name given for the function in the config is + * a name of a function in this module. + */ + Function *fp = M->getFunction(fnName); + if (fp == NULL) { + continue; + } + + /* + * See if argument counts match up + * If we were cool, we would check arg types if we detected + * no name mangling. + * + * The difference between sink and source cases is that at some point + * want to not just handle return value of source but allow for in/out + * or out arguments to be tainted. + */ + if (argIdx != -1 && \ + (fp->arg_size() == 0 || fp->arg_size() <= (unsigned)argIdx)) { + continue; + } + + /* + * Check this Function's User list. If there is no instruction using + * this function, then we have nothing to check for it. + */ + if (fp->user_empty() == true) { + continue; + } + + /* Ok, so we have name, argument, function, and a non-empty user list */ + for (auto userIt = fp->user_begin(); userIt != fp->user_end(); + ++userIt) { + User *targUser = *userIt; + + /* + * Not handling functions passed call backs or entry pts based on + * RT environment, so just get CallSites. Then make sure the called + * function is the targeted function (from config file) + */ + if (!isa(targUser) && !isa(targUser)) { + continue; + } + Instruction *targInst = cast(targUser); + std::unique_ptr tcs(new TargetCallSite(targInst, + argIdx)); + targetCallMap[tct].push_back(std::move(tcs)); + } + } +} + +bool +TargetCallSitesPass::runOnModule(Module &M) +{ + errs() << "Running target call sites pass.\n"; + + for (auto k = targetConfigMap.begin(); k != targetConfigMap.end(); ++k) { + TargetCallType t = k->first; + std::string p = k->second; + parseConfig(p, t, &M); + } + return false; +} +char TargetCallSitesPass::ID = 0; +static RegisterPass XX("target-call-sites", ""); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/TargetCallSitesPass.h b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/TargetCallSitesPass.h new file mode 100644 index 0000000..4924abd --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Analysis/TargetCallSitesPass.h @@ -0,0 +1,102 @@ +#ifndef __TARGETCALLSITESPASS_H +#define __TARGETCALLSITESPASS_H + +// Probably should just derive from CallSite, but so it goes. +class TargetCallSite { + CallSite callSite; + int argOperandIndex; + +public: + TargetCallSite(Instruction *c, int i) : callSite(c), argOperandIndex(i) {} + ~TargetCallSite() { } + + int getArgIndex() { + return argOperandIndex; + } + + Instruction *getInstruction() { + return callSite.getInstruction(); + } + + Function *getCaller() { + return callSite.getCaller(); + } + + Function *getCalled() { + return callSite.getCalledFunction(); + } + + Value *getTarget() { + if (argOperandIndex == -1) { + return callSite.getInstruction(); + } + return callSite.getArgOperand(argOperandIndex); + } +}; + +struct TargetCallSitesPass : public ModulePass { + static char ID; + + typedef enum _TargetCallType { + SinkCall, + SourceCall + } TargetCallType; + + TargetCallSitesPass() : ModulePass(ID) { + // There is probably a better, c++-ier way to do this with templates + // or something. + targetConfigMap[SinkCall] = ""; + targetCallMap[SinkCall].reserve(0); + targetConfigMap[SourceCall] = ""; + targetCallMap[SourceCall].reserve(0); + } + ~TargetCallSitesPass() { + for (auto k = targetCallMap.begin(); k != targetCallMap.end(); ++k) { + targetCallMap[k->first].clear(); + } + } + + virtual bool runOnModule(Module &); + virtual void getAnalysisUsage(AnalysisUsage &) const; + + void setConfig(TargetCallType ty, std::string path) { + targetConfigMap[ty] = path; + } + + typedef std::vector> TargetVector; + typedef TargetVector::const_iterator iterator; + + iterator src_begin() { + return targetCallMap[SourceCall].begin(); + } + iterator src_end() { + return targetCallMap[SourceCall].end(); + } + bool src_empty() { + return targetCallMap[SourceCall].empty(); + } + iterator src_erase(iterator pos) { + return targetCallMap[SourceCall].erase(pos); + } + + iterator snk_begin() { + return targetCallMap[SinkCall].begin(); + } + iterator snk_end() { + return targetCallMap[SinkCall].end(); + } + bool snk_empty() { + return targetCallMap[SinkCall].empty(); + } + iterator snk_erase(iterator pos) { + return targetCallMap[SinkCall].erase(pos); + } + +private: + void parseConfig(std::string, TargetCallType, Module *); + std::map targetConfigMap; + std::map targetCallMap; +}; + + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Comminute.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Comminute.cpp new file mode 100644 index 0000000..f49b730 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Comminute.cpp @@ -0,0 +1,211 @@ +/* + * Comminute + * + * This is a very basic example of using a (legacy) pass + * manager. We configure passes to run based on command + * line program options given. Some passes have dependencies, + * some do not. It is meant to help show how you can + * not have to do passes via opt, but via a programmatic + * means. + * + */ + +#include "llvm/LinkAllPasses.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Analysis/MemoryDependenceAnalysis.h" +#include "llvm/IRReader/IRReader.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Bitcode/BitcodeWriterPass.h" +#include "llvm-c/Core.h" +#include "llvm/Analysis/CallGraph.h" + +#include +#include + +using namespace llvm; + +#include "Analysis/TargetCallSitesPass.h" +#include "Transform/FunctionExternalizer.h" +#include "Transform/ChoosePhiValue.h" +#include "Analysis/NaiveConstantArgCheck.h" +#include "Analysis/NaiveSensitiveDataLeak.h" +#include "Analysis/NaiveFileDescLeak.h" +#include "Analysis/PotentiallyDangerousScan.h" +#include "Analysis/PotentiallyDangerousScanUserMethod.h" +#include "Analysis/PotentiallyDangerousScanFunctionPass.h" + +/* + * Command line arguments... + * + * comminute + * + * commands: + * -choose-phi-value :: choose incoming edge to phi node + * -naive-sensitive-data-leak :: very basic sensitive data leak check + * -naive-fd-leak :: very basic file descriptor leak check + * -naive-constant-arg :: check some functions for constant arg usage + * -dangerous-function :: looks for calls a ``weak'' API + * -dangerous-function-user-method :: " but using User list + * -dangerous-function-function-pass :: " but as a Function pass + * + */ +cl::opt InputBitcodeFile(cl::Positional, cl::desc(""), + cl::Required); +cl::opt OutputBitcodeFile(cl::Positional, cl::desc(""), + cl::Required); +cl::opt ChoosePhiValuePass("choose-phi-value", + cl::desc("Choose value to use from PhiNode (defaults to first)"), + cl::init(-1)); +cl::opt NaiveSDL("naive-sensitive-data-leak", + cl::desc("Perform Naive Sensitive Data Leak Analysis"), cl::init(false)); +cl::opt NaiveCAC("naive-constant-arg", + cl::desc("Perform Naive Constant Argument Check"), cl::init(false)); +cl::opt NaiveFDL("naive-fd-leak", + cl::desc("Perform Naive File Desc Leak check"), cl::init(false)); +cl::opt PotentiallyDangerous("dangerous-function", + cl::desc("Silly CWE 676"), cl::init(false)); +cl::opt PotentiallyDangerousUserMethod("dangerous-function-user-method", + cl::desc("Silly CWE 676 using User list"), cl::init(false)); +cl::opt PotentiallyDangerousFunctionPass("dangerous-function-fpass", + cl::desc("Silly CWE 676 using function pass"), cl::init(false)); + +int +main(int argc, char **argv) +{ + std::error_code ec; + + legacy::PassManager passManager; + std::unique_ptr irModule; + ModulePass *modPass; + SMDiagnostic err; + raw_fd_ostream *outputStream; + + cl::ParseCommandLineOptions(argc, argv); + + std::cout << " Reading input bitcode file: " << InputBitcodeFile << "\n"; + irModule = parseIRFile(InputBitcodeFile, err, + *unwrap(LLVMGetGlobalContext())); + if (irModule == nullptr) { + std::cout << " IR issue: " << err.getMessage().str() << "\n"; + return -1; + } + + /* + * Add the pass that removes the body of some functions we do not + * wish to have as local to this module. + */ + std::cout << " Adding function externalizer pass.\n"; + FunctionExternalizer *fe = new FunctionExternalizer(); + fe->setFunctionListFilePath("conf/fexternalizer.txt"); + passManager.add(fe); + + /* + * The mem2reg pass promotes alloc+load+store to register based. + * This helps with analysis by reducing load/store chasing. + */ + std::cout << " Adding mem2reg pass.\n"; + passManager.add(createPromoteMemoryToRegisterPass()); + + std::cout << " Adding constant propagation passes.\n"; + passManager.add(createConstantPropagationPass()); + passManager.add(createIPConstantPropagationPass()); + + /* + * The issue here is that one selection is made. To be better, + * you would want to reason, as best you can, about the paths + * selected. The same goes for branch analysis, etc. This is like + * taking an axe to things :-P. + */ + if (ChoosePhiValuePass >= 0) { + std::cout << " Adding phi value selector pass\n"; + std::cout << " Using edge index: " << ChoosePhiValuePass << "\n"; + ChoosePhiValue *c = new ChoosePhiValue(); + c->setEdgeIndex(ChoosePhiValuePass); + passManager.add(c); + } + + if (NaiveSDL) { + /* + * Add the naive sensitive data leak checking pass. + * + */ + std::cout << " Adding naive sensitive data leak pass.\n"; + TargetCallSitesPass *pt = new TargetCallSitesPass(); + pt->setConfig(TargetCallSitesPass::SourceCall, + "conf/sensitivesource.cfg"); + pt->setConfig(TargetCallSitesPass::SinkCall, + "conf/sensitivesink.cfg"); + passManager.add(pt); + NaiveSensitiveDataLeak *n = new NaiveSensitiveDataLeak(); + passManager.add(n); + } else if (NaiveFDL) { + /* + * Add the fd leak check. + */ + std::cout << " Adding naive file descriptor leak pass.\n"; + TargetCallSitesPass *pt = new TargetCallSitesPass(); + pt->setConfig(TargetCallSitesPass::SourceCall, + "conf/fdsource.cfg"); + pt->setConfig(TargetCallSitesPass::SinkCall, + "conf/fdsink.cfg"); + passManager.add(pt); + NaiveFileDescLeak *n = new NaiveFileDescLeak(); + passManager.add(n); + } else if (NaiveCAC) { + /* + * Add the naive constant argument checker pass. This also adds + * the ConstantPropagation pass which attempts to lower cases like + * int i = 0; foo(i); to foo(0);. This makes it easier for us to + * do the constant checking without having to follow-back. + * + */ + std::cout << " Adding naive constant argument pass.\n"; + NaiveConstantArgCheck *nca = new NaiveConstantArgCheck(); + nca->setConfigFilePath("conf/constantarg.cfg"); + passManager.add(nca); + } else if (PotentiallyDangerous) { + std::cout << " Adding call graph pass\n"; + passManager.add(new CallGraphWrapperPass()); + std::cout << " Adding dangerous fn scan pass.\n"; + PotentiallyDangerousScan *p = new PotentiallyDangerousScan(); + p->setConfigFilePath("conf/pdfunctions.cfg"); + passManager.add(p); + } else if (PotentiallyDangerousUserMethod) { + std::cout << " Adding dangerous fn scan user method pass.\n"; + PotentiallyDangerousScanUserMethod *p = new PotentiallyDangerousScanUserMethod(); + p->setConfigFilePath("conf/pdfunctions.cfg"); + passManager.add(p); + } else if (PotentiallyDangerousFunctionPass) { + std::cout << " Adding dangerous fn scan function pass.\n"; + PotentiallyDangerousScanFunctionPass *p = new PotentiallyDangerousScanFunctionPass(); + p->setConfigFilePath("conf/pdfunctions.cfg"); + passManager.add(p); + } + + /* + * Open output stream and use that as conduit for writing output + * bitcode file. + * + */ + std::cout << " Adding bitcode writer pass\n"; + outputStream = new raw_fd_ostream(OutputBitcodeFile, ec, sys::fs::F_None); + modPass = createBitcodeWriterPass(*outputStream, false, true); + passManager.add(modPass); + + /* + * Actually run the passes added on this module. With this very + * basic tool, there is just results to std[out|err]. + * + */ + std::cout << " Running passes\n"; + passManager.run(*irModule.get()); + outputStream->close(); + std::cout << " Finished...\n"; + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/ChoosePhiValue.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/ChoosePhiValue.cpp new file mode 100644 index 0000000..a6c3a69 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/ChoosePhiValue.cpp @@ -0,0 +1,129 @@ +/* + * Choose a value from a Phi node and replace all + * Phi node uses with it. This ignores some paths, but + * simplifies analysis. Will attempt to drop no longer + * used basic blocks. + */ +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/Pass.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/SymbolTableListTraits.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#include "ChoosePhiValue.h" + +bool +ChoosePhiValue::runOnModule(Module &M) +{ + errs() << "Running choose phi value pass.\n"; + bool rv = false; + + /* + * For every function in this compilation unit, iterate through + * the instructions looking for PHINodes. When a PHINode is found, + * the chosen incoming edge will be used, if it exists, otherwise + * the first (0) is chosen. The edge is removed. + * + * Take all the removed edges and replace the corresponding PHINode + * uses with the edge's value. So, where before things were using + * PHINode as the Value, they will use the incoming edge Value. + * Remove all other incoming edges and then erase the PHINode. + * Then, for each unused incoming edge, attempt to erase it's + * BasicBlock. + * + */ + for (auto &f : M) { + std::vector> replaceList; + + for (auto ii = inst_begin(f); ii != inst_end(f); ++ii) { + Instruction *in = &*ii; + if (PHINode *pn = dyn_cast(in)) { + unsigned usedEdge = edgeIndex; + if (pn->getNumIncomingValues() <= edgeIndex) { + errs() << "Not enough incoming values...using 0\n"; + usedEdge = 0; + } + // Remove chosen incoming value, add to replacement list. + Value *x = pn->removeIncomingValue(usedEdge, false); + replaceList.push_back(std::make_pair(pn, x)); + + } + } + // We know we are going to change the CFG. + if (replaceList.empty() == false) { + rv = true; + } + for (auto pc : replaceList) { + /* Replace all uses of the PHINode with the selected Value */ + pc.first->replaceAllUsesWith(pc.second); + while (pc.first->getNumIncomingValues() > 0) { + Value *d = pc.first->removeIncomingValue((unsigned)0, false); + // Each instruction resides in a BasicBlock + assert(isa(d) == true); + Instruction *vi = cast(d); + BasicBlock *bb = vi->getParent(); + if (bb->user_empty()) { + bb->eraseFromParent(); + continue; + } + // Attempt to remove users of BasicBlock so we can axe it + attemptUserReduction(bb); + if (bb->user_empty()) { + bb->eraseFromParent(); + continue; + } + } + assert(pc.first->users_empty()); + pc.first->eraseFromParent(); + } +#ifdef DEBUG + for (auto ii = inst_begin(f); ii != inst_end(f); ++ii) { + Instruction *in = &*ii; + assert(!isa(in) && "PHINode chooser missed."); + } +#endif + } + return rv; +} + +void +ChoosePhiValue::attemptUserReduction(BasicBlock *bb) +{ + /* + * Go through each user of this and we should just be finding + * BranchInst. If there is just one operand, then this is + * an unconditional branch and cannot be mucked with (unless + * we did deeper analysis), so we just return because + * we know there will always be a user of this BasicBlock. + * + * Otherwise, we make the true/false branch be the same and + * not our basic block. ... Repeat all this until gone + * through all users... + */ + for (auto ui = bb->user_begin(); ui != bb->user_end(); ++ui) { + User *u = *ui; + if (Instruction *i = dyn_cast(u)) { + if (BranchInst *bi = dyn_cast(i)) { + if (bi->getNumOperands() == 1) { + return; + } + Value *tb = bi->getOperand(1); + Value *fb = bi->getOperand(2); + if (tb == cast(bb)) { + bi->setOperand(1, fb); + } else if (fb == cast(bb)) { + bi->setOperand(2, tb); + } + } + } + } +} + +char ChoosePhiValue::ID = 0; +static RegisterPass XX("choose-phi-value", + "Choose Phi value to use"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/ChoosePhiValue.h b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/ChoosePhiValue.h new file mode 100644 index 0000000..c45327b --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/ChoosePhiValue.h @@ -0,0 +1,23 @@ +#ifndef __CHOOSEPHIVALUE_H +#define __CHOOSEPHIVALUE_H + +struct ChoosePhiValue : public ModulePass { +private: + unsigned edgeIndex; + void attemptUserReduction(BasicBlock *bb); + +public: + static char ID; + ChoosePhiValue() : ModulePass(ID) { } + virtual bool runOnModule(Module &); + + // phi [ a, b], [ c, d] .... + // this gets us [a, b] if edgeIndex = 0. + void setEdgeIndex(unsigned e) { + edgeIndex = e; + } + unsigned getEdgeIndex() { + return edgeIndex; + } +}; +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/FunctionExternalizer.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/FunctionExternalizer.cpp new file mode 100644 index 0000000..494bdae --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/FunctionExternalizer.cpp @@ -0,0 +1,70 @@ +/* + * Often in Android a thing to do is to + * grab source to a project and just build it + * in with your native code. This is painful from + * the analysis perspective because you (we) do + * not want to scan non-customer code. So, what + * this attempts to do is to look for any functions + * that are libc, libssl, DESLib, etc and convert + * them from their lifted-wrapper versions to + * just be the external declaration. + * + * To do this, you just deleteBody() on the function. + * + */ +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/Pass.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/SymbolTableListTraits.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include + +using namespace llvm; + +#include "FunctionExternalizer.h" + +bool +FunctionExternalizer::runOnModule(Module &M) +{ + errs() << "Running function externalizer pass.\n"; + + + std::ifstream fileHandle(this->_functionListFile); + std::string fnName; + bool rv = false; + + /* + * Each line is a function name to extern. It does not do any + * checking of the target function's signature etc, so be aware. + */ + while (std::getline(fileHandle, fnName)) { + // skip comment line. + if (fnName.find("#", 0) == 0) { + continue; + } + // Does the function exist within this module? + Function *f = M.getFunction(fnName); + if (f == NULL) { + continue; + } + // Definition is already outside of this module. + if (f->isDeclaration()) { + continue; + } + // Remove the body (definition) of the function. Leave declaration. + errs() << "Deleting body of function: " << f->getName().str() << "\n"; + f->deleteBody(); + rv = true; + } + return rv; +} +char FunctionExternalizer::ID = 0; +static RegisterPass XX("fn-extern", + "Function externalizer"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/FunctionExternalizer.h b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/FunctionExternalizer.h new file mode 100644 index 0000000..4f1eded --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/src/Transform/FunctionExternalizer.h @@ -0,0 +1,16 @@ +#ifndef __FUNCTIONEXTERNALIZER_H +#define __FUNCTIONEXTERNALIZER_H + +struct FunctionExternalizer : public ModulePass { +private: + std::string _functionListFile; + +public: + static char ID; + FunctionExternalizer() : ModulePass(ID) { } + virtual bool runOnModule(Module &); + void setFunctionListFilePath(std::string a) { this->_functionListFile = a; } + std::string getFunctionListFilePath() { return this->_functionListFile; } +}; + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/FE001.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/FE001.c new file mode 100644 index 0000000..e60697e --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/FE001.c @@ -0,0 +1,13 @@ +#include + +int +FE001_foo() +{ + return 0; +} + +int +main(int argc, char **argv) +{ + return 1; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NCA001.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NCA001.c new file mode 100644 index 0000000..d2e57f1 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NCA001.c @@ -0,0 +1,26 @@ +/* + * NCA001 + * + * NaiveConstantArg 001 + * + */ +#include +#include + +void +seed_random() +{ + + srandom(0xdeadbeef); +} + +int +main(int argc, char **argv) +{ + long int rv; + + seed_random(); + rv = random(); + (void)printf("random value = %ld\n", rv); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NCA002.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NCA002.c new file mode 100644 index 0000000..23a65f5 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NCA002.c @@ -0,0 +1,35 @@ +/* + * NCA002 + * + * NaiveConstantArg 002 + * + * The diff between this and 001 is using a pointer + * which causes load/store to occur. They should be + * removed by mem2reg. Let's see. + * + */ +#include +#include + +void +seed_random() +{ + unsigned int *seedp; + + seedp = (unsigned int *)malloc(sizeof(unsigned int)); + if (seedp == NULL) return; + *seedp = 0xdeadbeef; + srandom(*seedp); + free(seedp); +} + +int +main(int argc, char **argv) +{ + long int rv; + + seed_random(); + rv = random(); + (void)printf("random value = %ld\n", rv); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL001.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL001.c new file mode 100644 index 0000000..b46129d --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL001.c @@ -0,0 +1,27 @@ +/* + * NFDL001 + * + * Naive File Descriptor Leak 001 + * + */ +#include +#include +#include + +void +leaks_fd() +{ + int fd; + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket"); + } + return; +} + +int +main(int argc, char **argv) +{ + leaks_fd(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL002.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL002.c new file mode 100644 index 0000000..24921b3 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL002.c @@ -0,0 +1,38 @@ +/* + * NFDL002 + * + * Naive File Descriptor Leak 002 + * .. well this does not leak. + * + */ +#include +#include +#include +#include + +void +foo(char *k) +{ + return; +} + +void +leaks_fd() +{ + int fd; + + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket"); + } + close(fd); + return; +} + +int +main(int argc, char **argv) +{ + leaks_fd(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL003.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL003.c new file mode 100644 index 0000000..1d37ebb --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL003.c @@ -0,0 +1,40 @@ +/* + * NFDL003 + * + * Naive File Descriptor Leak 003 + * + * copies fd to another local variable and closes that... so no leak + */ +#include +#include +#include +#include + +void +foo(char *k) +{ + return; +} + +void +leaks_fd() +{ + int fd; + int fd2; + + fd2 = 0; + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket"); + } + fd2 = fd; + close(fd2); + return; +} + +int +main(int argc, char **argv) +{ + leaks_fd(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL004.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL004.c new file mode 100644 index 0000000..3f8928e --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL004.c @@ -0,0 +1,43 @@ +/* + * NFDL004 + * + * Naive File Descriptor Leak 004 + * + * One leaks one does not + * + */ +#include +#include +#include +#include + +void +foo(char *k) +{ + return; +} + +void +leaks_fd() +{ + int fd, fd2; + + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket"); + } + fd2 = socket(AF_INET, SOCK_STREAM, 0); + if (fd2 == -1) { + perror("socket"); + } + close(fd); + return; +} + +int +main(int argc, char **argv) +{ + leaks_fd(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL005.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL005.c new file mode 100644 index 0000000..a0722e5 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL005.c @@ -0,0 +1,37 @@ +/* + * NFDL005 + * + * Naive File Descriptor Leak 005 + * + * global variable that ``seems'' to leak. + * + */ +#include +#include +#include +#include + +void +foo(char *k) +{ + return; +} + +int fd; + +void +leaks_fd() +{ + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket"); + } + return; +} + +int +main(int argc, char **argv) +{ + leaks_fd(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL006.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL006.c new file mode 100644 index 0000000..7b9dd78 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL006.c @@ -0,0 +1,44 @@ +/* + * NFDL006 + * + * Naive File Descriptor Leak 005 + * + * global variable that does not leak, but naive analysis won't catch. + * + */ +#include +#include +#include +#include + +void +foo(char *k) +{ + return; +} + +int fd; + +void +leaks_fd() +{ + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket"); + } + return; +} + +void +closes_fd() +{ + close(fd); +} + +int +main(int argc, char **argv) +{ + leaks_fd(); + closes_fd(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL007.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL007.c new file mode 100644 index 0000000..49fef6f --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NFDL007.c @@ -0,0 +1,38 @@ +/* + * NFDL005 + * + * Naive File Descriptor Leak 005 + * + * opens and closes a global var fd + * + */ +#include +#include +#include +#include + +void +foo(char *k) +{ + return; +} + +int fd; + +void +leaks_fd() +{ + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) { + perror("socket"); + } + close(fd); + return; +} + +int +main(int argc, char **argv) +{ + leaks_fd(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NSDL001.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NSDL001.c new file mode 100644 index 0000000..4c28067 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NSDL001.c @@ -0,0 +1,36 @@ +/* + * NSDL001 + * + * Naive Sensitive Data Leak 001 + * + */ +#include +#include +#include +#include +#include +#include + +void +leaks_passwd() +{ + char *p; + struct addrinfo hints, *result; + + p = getpass("enter passwd: "); + /* l.v. p is now tainted with sensitive data */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + /* leak password via getaddrinfo() DNS lookup. contrived af. */ + (void)getaddrinfo(p, "http", &hints, &result); +} + +int +main(int argc, char **argv) +{ + leaks_passwd(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NSDL002.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NSDL002.c new file mode 100644 index 0000000..c7330a7 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NSDL002.c @@ -0,0 +1,37 @@ +/* + * NSDL002 + * + * Naive Sensitive Data Leak 002 + * + */ +#include +#include +#include +#include +#include +#include +#include + +void +leaks_passwd(unsigned lookup) +{ + char *p; + struct addrinfo hints, *result; + + p = getpass("enter passwd: "); + /* l.v. p is now tainted with sensitive data */ + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + /* leak password via getaddrinfo() DNS lookup. contrived af. */ + memset(p, 0, strlen(p)); // XXX :PpPp + (void)getaddrinfo(p, "http", &hints, &result); +} +int +main(int argc, char **argv) +{ + leaks_passwd(random()); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NSDL003.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NSDL003.c new file mode 100644 index 0000000..70990ab --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/NSDL003.c @@ -0,0 +1,37 @@ +/* + * NSDL003 + * + * Naive Sensitive Data Leak 003 + * + */ +#include +#include +#include +#include +#include +#include +#include + +void +leaks_passwd(unsigned lookup) +{ + char *p, *a2l = "www.cw-complex.com"; + struct addrinfo hints, *result; + if (lookup) { + p = getpass("enter passwd: "); + } else { + p = a2l; + } + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + (void)getaddrinfo(p, "http", &hints, &result); /* which path did p take? */ +} +int +main(int argc, char **argv) +{ + leaks_passwd(random()); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/PD001.c b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/PD001.c new file mode 100644 index 0000000..9a45672 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/tests/PD001.c @@ -0,0 +1,44 @@ +/* + * PD001 + * + * Potentially Dangerous 001 + * + */ +#include +#include +#include +#include +#include +#include + +void +blind_copy() +{ + char buf[512]; + char buf2[32]; + struct addrinfo hints, *result; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + + (void)getaddrinfo("www.evilgoogle.com", "http", &hints, &result); + int sfd = socket(result->ai_family, result->ai_socktype, result->ai_protocol); + if (sfd == -1) { + return; + } + memset(&buf, 0, 512); + connect(sfd, result->ai_addr, result->ai_addrlen); + read(sfd, &buf, 511); + strcpy(buf2, buf); + +} + +int +main(int argc, char **argv) +{ + blind_copy(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/comminute/thirdparty/jsoncpp-1.8.0.tar.gz b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/thirdparty/jsoncpp-1.8.0.tar.gz new file mode 100644 index 0000000..a25d895 Binary files /dev/null and b/Security Research and Development with LLVM - Andrew Reiter/code/comminute/thirdparty/jsoncpp-1.8.0.tar.gz differ diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/Makefile b/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/Makefile new file mode 100644 index 0000000..f8b2981 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/Makefile @@ -0,0 +1,46 @@ +LLVM_VER=3.9 +LLVM_HOME=/usr/bin +LLVM_CONFIG?=$(LLVM_HOME)/llvm-config-$(LLVM_VER) + +ifndef VERBOSE +QUIET:=@ +endif + +SRC_DIR?=$(PWD)/src + +CXX=$(LLVM_HOME)/clang++-$(LLVM_VER) +CC=$(LLVM_HOME)/clang-$(LLVM_VER) +OPT=$(LLVM_HOME)/opt-$(LLVM_VER) +DIS=$(LLVM_HOME)/llvm-dis-$(LLVM_VER) +LNK=$(LLVM_HOME)/llvm-link-$(LLVM_VER) + +LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags) +LDFLAGS+=-shared -Wl,-O1 + +CXXFLAGS+=-I$(shell $(LLVM_CONFIG) --includedir) +CXXFLAGS+=-std=c++11 -fPIC -fvisibility-inlines-hidden +CXXFLAGS+=-Wall -Wextra -g -Wno-unused-parameter -Wno-unused-variable + +CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) +CPPFLAGS+=-I$(SRC_DIR) + + +PASS=FPSkel.so +PASS_OBJECTS=FPSkel.o + +default: prep $(PASS) + +prep: + $(QUIET)mkdir -p built + +%.o : $(SRC_DIR)/%.cpp + @echo Compiling $*.cpp + $(QUIET)$(CXX) -o built/$*.o -c $(CPPFLAGS) $(CXXFLAGS) $< + +$(PASS) : $(PASS_OBJECTS) + @echo Linking $@ + $(QUIET)$(CXX) -o built/$@ $(LDFLAGS) $(CXXFLAGS) built/*.o + +clean: + $(QUIET)rm -rf built + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/README.md b/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/README.md new file mode 100644 index 0000000..366781f --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/README.md @@ -0,0 +1,19 @@ + +# FPSkel + +This is a function pass skeleton. + + +# Build & Run + +First check the Makefile to set path to llvm-config and version. +3.8, 3.9 should be fine, so should 4.0 + +``` +$ make +$ opt-X.Y -load built/FPSkel.so -fpskel < file.bc +... +$ +``` + + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/src/FPSkel.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/src/FPSkel.cpp new file mode 100644 index 0000000..e54ebc9 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/src/FPSkel.cpp @@ -0,0 +1,56 @@ +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#include "FPSkel.h" + +void +FPSkel::getAnalysisUsage(AnalysisUsage &AU) const +{ + AU.setPreservesCFG(); +} + + +bool +FPSkel::runOnFunction(Function &F) +{ + unsigned nbb = 0; + unsigned ins = 0; + + if (F.isDeclaration()) { + errs() << "Ignoring function declaration.\n"; + return false; + } + if (F.hasName()) { + errs() << "\nFunction: " << F.getName() << "\n"; + } else { + errs() << "\nFunction: not named\n"; + } + + for (auto &B : F) { // Iterate through Basic Blocks in a function + ++nbb; + errs() << " Basic Block found:\n"; + B.dump(); + for (auto &I : B) { // Iterate through instructions in the block + ++ins; + } + errs() << " --- end of basic block ---\n"; + } + errs() << " Total of " << nbb << " blocks in this function\n"; + errs() << " Total of " << ins << " instructions in this function\n"; + errs() << "--- end of function ---\n"; + + // return true if CFG has changed. + return false; +} + +/* + * Register this pass to be made usable with -fpskel option. + * Needs the static ID initialized and the pass declaration given. + */ +char FPSkel::ID = 0; +static RegisterPass XX("fpskel", "Function Pass Skeleton"); + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/src/FPSkel.h b/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/src/FPSkel.h new file mode 100644 index 0000000..29db14c --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/fpskel/src/FPSkel.h @@ -0,0 +1,25 @@ +#ifndef __FPSKEL_H +#define __FPSKEL_H + +struct FPSkel : public FunctionPass { + /* + * For all of your passes you will need this and to define it. + * It's address is used by pass system, so the value does not matter. + */ + static char ID; + + FPSkel() : FunctionPass(ID) { } + + // Called on each function in given compilation unit + virtual bool runOnFunction(Function &); + + /* + * Used to help order passes by pass manager. + * Declare any passes you need run prior here.. as well as + * any information such as preserving CFG or similar. + */ + virtual void getAnalysisUsage(AnalysisUsage &) const; + +}; + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/Makefile b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/Makefile new file mode 100644 index 0000000..0ae6d30 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/Makefile @@ -0,0 +1,134 @@ +# +# This is all a bit hack-ish, but should give the idea +# about llvm-config usage, which is the key tool to make +# life easy^Hier. +# +# make jsoncpp (once) +# make +# +# I assume you have things in /usr/bin. Often this is the +# case, but providing a path for you to set. +# +LLVM_VER=3.9 +LLVM_HOME=/usr/bin +LLVM_CONFIG?=$(LLVM_HOME)/llvm-config-$(LLVM_VER) + +ifndef VERBOSE +QUIET:=@ +endif + +SRC_DIR?=$(PWD)/src + +CXX=$(LLVM_HOME)/clang++-$(LLVM_VER) +CC=$(LLVM_HOME)/clang-$(LLVM_VER) +OPT=$(LLVM_HOME)/opt-$(LLVM_VER) +DIS=$(LLVM_HOME)/llvm-dis-$(LLVM_VER) +LNK=$(LLVM_HOME)/llvm-link-$(LLVM_VER) + +LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags) +LDFLAGS+=-Lthirdparty/jsoncpp-1.8.0/build/src/lib_json -ljsoncpp +LDFLAGS+=-shared -Wl,-O1 + +CXXFLAGS+=-I$(shell $(LLVM_CONFIG) --includedir) +CXXFLAGS+=-std=c++11 -fPIC -fvisibility-inlines-hidden +CXXFLAGS+=-Wall -Wextra -g -Wno-unused-parameter -Wno-unused-variable + +CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) +CPPFLAGS+=-I$(SRC_DIR) -Ithirdparty/jsoncpp-1.8.0/include + + +PASS=libIntFlip.so +PASS_OBJECTS=FlipConfig.o \ + LiftConstantIntPass.o \ + ReplaceRandomizer.o \ + BitFlipRandomizer.o \ + InjectRandomizers.o \ + IntReplacerVisitor.o \ + IntReplacerIterate.o + + +# IntReplacerVisitor.o + + +default: prep $(PASS) + +# Quite the hack :-P +jsoncpp: + @echo Building jsoncpp-1.8.0 + cd thirdparty && \ + tar zxvf jsoncpp-1.8.0.tar.gz && \ + cd jsoncpp-1.8.0 && \ + rm -rf build && \ + mkdir -p build && \ + cd build && \ + cmake .. && \ + make && \ + cd ../../ + + +prep: + $(QUIET)mkdir -p built + +%.o : $(SRC_DIR)/%.cpp + @echo "CPPFLAGS: ${CPPFLAGS}" + @echo "CXXFLAGS: ${CXXFLAGS}" + @echo Compiling $*.cpp + $(QUIET)$(CXX) -o built/$*.o -c $(CPPFLAGS) $(CXXFLAGS) $< + +$(PASS) : $(PASS_OBJECTS) + @echo Linking $@ + $(QUIET)$(CXX) -o built/$@ $(LDFLAGS) $(CXXFLAGS) built/*.o + +clean: + $(QUIET)rm -rf built + +jsonclean: + $(QUIET)rm -rf thirdparty/jsoncpp-1.8.0 + +tests: + $(QUIET)echo "Generating bitcode from C" + $(QUIET)$(CC) -emit-llvm -c -o test/foo.bc test/foo.c + $(QUIET)echo "Lifting constants to local variables" + $(QUIET)$(OPT) -load built/libIntFlip.so -lift-constant-int-args -o test/foo2.bc < test/foo.bc + $(QUIET)echo "Injecting randomizer functions" + $(QUIET)$(OPT) -load built/libIntFlip.so -inject-randomizers -o test/foo3.bc < test/foo2.bc + $(QUIET)echo "Replacing ints with visitor method based on replace.cfg" + $(QUIET)$(OPT) -load built/libIntFlip.so -replace-ints-visitor -o test/foo4.bc -repcfg=replace.cfg < test/foo3.bc + $(QUIET)echo "Replacing ints with iteration method based on replace.cfg" + $(QUIET)$(OPT) -load built/libIntFlip.so -replace-ints-iterate -o test/foo5.bc -repcfg=replace.cfg < test/foo3.bc + $(QUIET)echo "llvm-dissing..." + $(QUIET)$(DIS) --o=test/foo.ll test/foo.bc + $(QUIET)$(DIS) --o=test/foo2.ll test/foo2.bc + $(QUIET)$(DIS) --o=test/foo3.ll test/foo3.bc + $(QUIET)$(DIS) --o=test/foo4.ll test/foo4.bc + $(QUIET)$(DIS) --o=test/foo5.ll test/foo5.bc + $(QUIET)echo "Building foo, foo4, foo5 executables" + $(QUIET)$(CC) -o test/foo5 test/foo5.bc -pthread -lbsd + $(QUIET)$(CC) -o test/foo4 test/foo4.bc -pthread -lbsd + $(QUIET)$(CC) -o test/foo test/foo.bc -pthread -lbsd + $(QUIET)echo "" + $(QUIET)echo "Generating bitcode from C++ source" + $(QUIET)$(CXX) -emit-llvm -c -o test/foopp.bc test/foo.cpp + $(QUIET)echo "Lifting constants to local variables" + $(QUIET)$(OPT) -load built/libIntFlip.so -lift-constant-int-args -o test/foopp2.bc < test/foopp.bc + $(QUIET)echo "Injecting randomizer functions" + $(QUIET)$(OPT) -load built/libIntFlip.so -inject-randomizers -o test/foopp3.bc < test/foopp2.bc + $(QUIET)echo "Replacing ints with visitor method based on replacepp.cfg" + $(QUIET)$(OPT) -load built/libIntFlip.so -replace-ints-visitor -o test/foopp4.bc -repcfg=replacepp.cfg < test/foopp3.bc + $(QUIET)echo "Replacing ints with iteration method based on replacepp.cfg" + $(QUIET)$(OPT) -load built/libIntFlip.so -replace-ints-iterate -o test/foopp5.bc -repcfg=replacepp.cfg < test/foopp3.bc + $(QUIET)echo "llvm-dissing..." + $(QUIET)$(DIS) --o=test/foopp.ll test/foopp.bc + $(QUIET)$(DIS) --o=test/foopp2.ll test/foopp2.bc + $(QUIET)$(DIS) --o=test/foopp3.ll test/foopp3.bc + $(QUIET)$(DIS) --o=test/foopp4.ll test/foopp4.bc + $(QUIET)$(DIS) --o=test/foopp5.ll test/foopp5.bc + $(QUIET)echo "Building foopp, foopp4, foopp5 executables" + $(QUIET)$(CXX) -o test/foopp5 test/foopp5.bc -pthread -lbsd + $(QUIET)$(CXX) -o test/foopp4 test/foopp4.bc -pthread -lbsd + $(QUIET)$(CXX) -o test/foopp test/foopp.bc -pthread -lbsd + +cleantests: + rm -f test/*.bc test/*.ll foo foo4 foo5 foopp foopp4 foopp5 + +cleanall: clean jsonclean cleantests diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/README.md b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/README.md new file mode 100644 index 0000000..9791203 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/README.md @@ -0,0 +1,138 @@ + +# intflip + +Currently, what this does is replaces all 8, 16, 32, and 64 bit integers arguments to functions +with possibly randomly changed values. The purpose is to re-run test suites +with the modified application in order to simulate the low-probability bit or +more flips that could occur in certain extreme situations. The aim is to perform +some basic analysis as to the stability of the code given random changes. + +## Aside + +- I do not do much of anything with being sane about memory usage. You're warned. :-P + +- The way I do the RNG bit is possibly overkill. *shrug*. ISO C standard +one should be fine. + +- The randomizer insertion could just be C code that gets linked in, but +going through the generation and insertion of a function is a good +exercise. + +# Requirements + +- LLVM 3.9.0 (should work with 3.8 & 4.0) + +# Building + +$ make jsoncpp +$ make + +# Process + +All executables listed below are supposed to be in your path. You will +``compile'' to IR and then work on that. I would follow the basic steps +and then determine how you want to handle performing the analysis. The +analysis would be a combination of running unit, or other, tests with +the injected randomizers and analyzing how those runs performed given +the probability distribution you are looking at. + +## Passes + +This is a list of passes available. They are intended to be used per the +``basic steps'' section below. + +- -lift-constant-int-args +- -inject-randomizers +- -replace-ints-visitor +- -replace-ints-iterate +- -replace-ints-cgpass + +## Basic Work Flow + +*Setup replace.cfg* + +The file replace.cfg informs the passes how to setup the random integer replacement action. As the +key, you specify the function that will have any call instructions /in/ it that have at least one +integer argument, replaced to use an integer value that is randomly selected. + +Each value is a dict that should have the keys/values: +- "analyze" : true|false +- "type" : 0|1 ... 0 for randomly replace with random value. 1 for randomly replace with random bit flipp +- "mean" : we are dealing with 32-bit integers, and compare <= mean on random number. +The for +{ + "foo" : { + "analyze" : true, + "type" : 0, + "mean" : 500 + } +} + +*Compile your code to IR* + +> clang++-3.9 -emit-llvm -o foo.bc -c foo.c + +Of course with a larger code base there will be more work involved. +There is a tool that is out there to help with, at least, the merging +of multiple bitcode files, it may be found [link](https://github.com/travitch/whole-program-llvm "whole-program-llvm"). + +*Lift ConstantInt to local variable* + +> opt-3.9 -load built/libIntFlip.so -lift-constant-ints -o foo2.bc < foo.bc + +This will convert constant integers into local variables. This helps +the next step of replacing integers used with randomizer function as +there is no special casing for constant integers.. we just go after +the local vars. + +*Inject the randomizer functions* + +> opt-3.9 -load built/libIntFlip.so -inject-randomizers -o foo3.bc < foo2.bc + +This generates the functions that will possibly change integer values +and injects them into the bitcode file. We could just link in code, but +we do this to demonstrate some writing of our own functions via the API. + +*Modify integer arguments to use randomizer functions* + +> opt-3.9 -load built/libIntFlip.so -replace-ints -o foo4.bc < foo3.bc + +*Build the executable* + +> llc-3.9 -o=foo4.s foo4.bc +> clang++-3.9 -o foo4 foo4.s + +or however you want... + +*Dump IR from resultant bitcode file* + +> llvm-dis-3.9 -o=foo.ll test/foo.bc + +You can do the above for each bitcode file and compare them. + + +# Some things one might wish to do + +- Wrap all and use a pass manager +-- add pass dependencies for ordering +- Improved control over configurations +- Build out a whole test run harness +-- run test cases that have known outcomes (typically, just unit tests and some other) +-- adjusting probability distribution mean and seeing how that impacts results +- Improved probability distributions.. +-- evolutionary (evolve with execution steps) +- Overall model of app that is intelligently injected based on a model of a specific event +-- that would be like a model based on a real gamma ray birst or something weird +- Randomly change instructions +-- Could be done in a few ways, but would want to be arch specific +-- to find all 1-bit mutatable instructions for instruction i, find all instructions j st dist(i,j) = 1 +-- similar for 2 bit.. just make dist(i,j) = 2... +-- Then lift those sets to IR +-- so.. you attempt to fix it in IR.. this will not always work because of ``nice graph'' desires. +- whatever. + + +# Inspirational credits +- NASA +- John Regehr (Utah) +- Gamma rays, alpha particles diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/replace.cfg b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/replace.cfg new file mode 100644 index 0000000..c4a3da2 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/replace.cfg @@ -0,0 +1,49 @@ +{ + "global" : { + }, + "skip" : [ + "printf" + ], + "functions" : { + "thd_bf8" : { + "analyze" : true, + "type" : 1, + "mean" : 100000000 + }, + "thd_bf16" : { + "analyze" : true, + "type" : 1, + "mean" : 100000000 + }, + "thd_bf32" : { + "analyze" : true, + "type" : 1, + "mean" : 100000000 + }, + "thd_bf64" : { + "analyze" : true, + "type" : 1, + "mean" : 1000000000 + }, + "thd_rr8" : { + "analyze" : true, + "type" : 0, + "mean" : 100000000 + }, + "thd_rr16" : { + "analyze" : true, + "type" : 0, + "mean" : 100000000 + }, + "thd_rr32" : { + "analyze" : true, + "type" : 0, + "mean" : 100000000 + }, + "thd_rr64" : { + "analyze" : true, + "type" : 0, + "mean" : 100000000 + } + } +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/replacepp.cfg b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/replacepp.cfg new file mode 100644 index 0000000..23b8b81 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/replacepp.cfg @@ -0,0 +1,49 @@ +{ + "global" : { + }, + "skip" : [ + "printf" + ], + "functions" : { + "_ZL7thd_bf8Pv" : { + "analyze" : true, + "type" : 1, + "mean" : 100000000 + }, + "_ZL8thd_bf16Pv" : { + "analyze" : true, + "type" : 1, + "mean" : 100000000 + }, + "_ZL8thd_bf32Pv" : { + "analyze" : true, + "type" : 1, + "mean" : 100000000 + }, + "_ZL8thd_bf64Pv" : { + "analyze" : true, + "type" : 1, + "mean" : 1000000000 + }, + "_ZL7thd_rr8Pv" : { + "analyze" : true, + "type" : 0, + "mean" : 100000000 + }, + "_ZL8thd_rr16Pv" : { + "analyze" : true, + "type" : 0, + "mean" : 100000000 + }, + "_ZL8thd_rr32Pv" : { + "analyze" : true, + "type" : 0, + "mean" : 100000000 + }, + "_ZL8thd_rr64Pv" : { + "analyze" : true, + "type" : 0, + "mean" : 100000000 + } + } +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/BaseRandomizer.h b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/BaseRandomizer.h new file mode 100644 index 0000000..7f65510 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/BaseRandomizer.h @@ -0,0 +1,14 @@ +#ifndef __BASERANDOMIZER_H +#define __BASERANDOMIZER_H + +class BaseRandomizer { +public: + static void inject(llvm::Module& M); +}; + +typedef enum { + Replace = 1, + BitFlip = 2 +} RandomizerKind; + +#endif // !__BASERANDOMIZER_H diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/BitFlipRandomizer.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/BitFlipRandomizer.cpp new file mode 100644 index 0000000..4a06395 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/BitFlipRandomizer.cpp @@ -0,0 +1,126 @@ +#include "llvm/IR/Module.h" +#include "llvm/IR/IRBuilder.h" + +#include "BitFlipRandomizer.h" + +using namespace llvm; + +/* + * This macro helps with the varying bit cases. It generates the code + * that generates the code where K = nBits is a value: + * + * intK_t + * __bitflip_randomize_iK(intK inArg0) + * { + * unsigned rv = arc4random(); + * if (rv <= (unsigned)2^31) { + * rv = 1 << (rv % K); + * return inArg0 ^ rv; + * } + * return inArg0; + * } + * + * So this says get a random number and if it is less than some mean + * then we flip a random bit of the input integer and return it. + * Otherwise, we just return it unscathed. + * + */ +#define injectBFIntN(nBits) \ + static void \ + injectInt##nBits(llvm::Module& M, Function *fnRand) \ + { \ + /* \ + * Add the function intN_t __bitflip_randomizer_iN__(intN_t, int32_t) \ + */ \ + LLVMContext& ctx = M.getContext(); \ + /* \ + * define i8 @__bitflip_randomizer_i8__(i8 %intToFlip, i32 %meanValue) { \ + * } \ + */ \ + std::string int##nBits##_rand = "__bitflip_randomizer_i" #nBits "__"; \ + Constant *cTmp = M.getOrInsertFunction(int##nBits##_rand, \ + Type::getInt##nBits##Ty(ctx), \ + Type::getInt##nBits##Ty(ctx), \ + Type::getInt32Ty(ctx), \ + NULL); \ + Function *bf_i##nBits = cast(cTmp); \ + bf_i##nBits->setCallingConv(CallingConv::C); \ + \ + Argument& inArg0 = bf_i##nBits->getArgumentList().front(); \ + inArg0.setName("intToFlip"); \ + Argument& inArg1 = bf_i##nBits->getArgumentList().back(); \ + inArg1.setName("meanValue"); \ + \ + /* \ + * entry: \ + * bf_it: \ + * return: \ + */ \ + BasicBlock *blkEntry = BasicBlock::Create(ctx, "entry", bf_i##nBits); \ + BasicBlock *blkBitFlipIt = BasicBlock::Create(ctx, "bf_it", bf_i##nBits); \ + BasicBlock *blkReturn = BasicBlock::Create(ctx, "return", bf_i##nBits); \ + /* \ + * entry: \ + * %__bf_rand_ = call i32 @arc4random() \ + * %__bf_lessthan_ = icmp ule i32 %__bf_rand_, %meanValue \ + * br i1 %__bf_lessthan_, label %bf_it, label %return \ + */ \ + IRBuilder<> builder(blkEntry); \ + Value *callArc4Random = builder.CreateCall(fnRand, None, "__bf_rand_", nullptr); \ + Value *lessThan = builder.CreateICmpULE(callArc4Random, &inArg1, "__bf_lessthan_"); \ + Value *branchBitFlip = builder.CreateCondBr(lessThan, blkBitFlipIt, blkReturn); \ + \ + /* \ + * bf_it: ; preds = %entry \ + * %__bf_bitflip_ = urem i32 %__bf_rand_, 8 \ + * %__bf_cast_randrem_ = trunc i32 %__bf_bitflip_ to i8 \ + * %__bf_shifted_bit_ = shl i8 1, %__bf_cast_randrem_ \ + * %__bf_xord_retval_ = xor i8 %intToFlip, %__bf_shifted_bit_ \ + * ret i8 %__bf_xord_retval_ \ + */ \ + builder.SetInsertPoint(blkBitFlipIt); \ + Value *randModulus = ConstantInt::get(IntegerType::get(ctx, 32), nBits, false); \ + Value *randRemainder = builder.CreateURem(callArc4Random, randModulus, \ + "__bf_bitflip_"); \ + Value *defaultBit = ConstantInt::get(IntegerType::get(ctx, nBits), 1, false); \ + Value *castRandRem = builder.CreateZExtOrTrunc(randRemainder, \ + Type::getInt##nBits##Ty(ctx), "__bf_cast_randrem_"); \ + Value *shiftedBit = builder.CreateShl(defaultBit, castRandRem, \ + "__bf_shifted_bit_"); \ + Value *xordReturnVal = builder.CreateXor(&inArg0, shiftedBit, "__bf_xord_retval_"); \ + builder.CreateRet(xordReturnVal); \ + \ + /* \ + * return: ; preds = %entry \ + * ret i8 %intToFlip \ + */ \ + builder.SetInsertPoint(blkReturn); \ + builder.CreateRet(&inArg0); \ + } \ + + + +injectBFIntN(64) +injectBFIntN(32) +injectBFIntN(16) +injectBFIntN(8) + +void +BitFlipRandomizer::inject(Module& M) +{ + LLVMContext& ctx = M.getContext(); + + /* + * If arc4random is already in the module, then return the Function for it; otherwise, + * declare it so it will be pulled in. It should be within scope, so we assert. + */ + Constant *lookupRand = M.getOrInsertFunction("arc4random", Type::getInt32Ty(ctx), NULL); + assert(lookupRand != NULL && "BitFlipRandomizer::inject: Unable to getFunction(arc4random)\n"); + + Function *fnRand = cast(lookupRand); + + injectInt64(M, fnRand); + injectInt32(M, fnRand); + injectInt16(M, fnRand); + injectInt8(M, fnRand); +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/BitFlipRandomizer.h b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/BitFlipRandomizer.h new file mode 100644 index 0000000..1e9f235 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/BitFlipRandomizer.h @@ -0,0 +1,11 @@ +#ifndef __BITFLIPRANDOMIZER_H +#define __BITFLIPRANDOMIZER_H + +#include "BaseRandomizer.h" + +class BitFlipRandomizer : BaseRandomizer { +public: + static void inject(llvm::Module& M); +}; + +#endif // !__BITFLIPRANDOMIZER_H diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/FlipConfig.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/FlipConfig.cpp new file mode 100644 index 0000000..aa4e4a6 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/FlipConfig.cpp @@ -0,0 +1,57 @@ +#include +#include + +#include +#include + +#include +#include +#include + +#include "FlipConfig.h" + +std::vector skip_replace_functions = { + "__rep_randomizer_i64__", + "__rep_randomizer_i32__", + "__rep_randomizer_i16__", + "__rep_randomizer_i8__", + "__bitflip_randomizer_i64__", + "__bitflip_randomizer_i32__", + "__bitflip_randomizer_i16__", + "__bitflip_randomizer_i8__", + "__cxa_allocate_exception", + "__cxa_throw" // ... There are many RT and other functions to skip... but so it goes. +}; + + +FlipConfig::FlipConfig(std::string c) +{ + _configFile = c; + std::ifstream cStream; + cStream.open(_configFile); + cStream >> _configDict; + cStream.close(); + + Json::Value globalConfig =_configDict["global"]; // XXX Not used yet + Json::Value fnConfig = _configDict["functions"]; + Json::Value skipFn = _configDict["skip"]; + Json::Value::Members m = fnConfig.getMemberNames(); + for (auto iii = m.begin(); iii != m.end(); ++iii) { + std::string name = *iii; + + Json::Value nv = fnConfig[name]; + Json::Value meanVal = nv["mean"]; + Json::Value typeVal = nv["type"]; + Json::Value analyzeVal = nv["analyze"]; + + FunctionConfig fc{analyzeVal.asBool(), typeVal.asUInt(), meanVal.asUInt()}; + _replace[name] = fc; + } + if (skipFn.isArray()) { + Json::ArrayIndex aLen = skipFn.size(); + for (Json::ArrayIndex ai = 0; ai < aLen; ai++) { + skip_replace_functions.push_back(skipFn[ai].asString()); + } + } +} + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/FlipConfig.h b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/FlipConfig.h new file mode 100644 index 0000000..e69c652 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/FlipConfig.h @@ -0,0 +1,29 @@ +#ifndef __FLIPCONFIG_H +#define __FLIPCONFIG_H + +struct FunctionConfig { + bool shouldAnalyze; + unsigned randomType; // weak, i know. 0 = full replace, 1 = bit replace + unsigned mean; // replace int, if random value is <= mean + + FunctionConfig() { shouldAnalyze = false; randomType = 0; mean = 2828282; } + FunctionConfig(bool a, unsigned t, unsigned m) : shouldAnalyze(a), randomType(t), mean(m) {} +}; + +typedef std::map ReplaceMap; + +class FlipConfig { +private: + std::string _configFile; + Json::Value _configDict; + ReplaceMap _replace; + +public: + FlipConfig(std::string c); + Json::Value getDict() { return _configDict; } + ReplaceMap getReplaceMap() { return _replace; } +}; + +extern std::vector skip_replace_functions; + +#endif // !__FLIPCONFIG_H diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/InjectRandomizers.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/InjectRandomizers.cpp new file mode 100644 index 0000000..43b7c3e --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/InjectRandomizers.cpp @@ -0,0 +1,23 @@ +#include "llvm/IR/Module.h" + +#include "ReplaceRandomizer.h" +#include "BitFlipRandomizer.h" + +using namespace llvm; + +struct InjectRandomizers : public ModulePass { + static char ID; + + InjectRandomizers() : ModulePass(ID) {} + + virtual bool + runOnModule(Module &M) + { + ReplaceRandomizer::inject(M); + BitFlipRandomizer::inject(M); + return true; + } +}; + +char InjectRandomizers::ID = 0; +static RegisterPass XX("inject-randomizers", "Inject randomizer functions"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/IntReplacerIterate.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/IntReplacerIterate.cpp new file mode 100644 index 0000000..79ea37c --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/IntReplacerIterate.cpp @@ -0,0 +1,134 @@ + +#include "llvm/IR/Module.h" +#include "llvm/Support/Casting.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/CallSite.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/CommandLine.h" + +#include "TypeValueSupport.h" +#include "BaseRandomizer.h" + +#include +#include "FlipConfig.h" + +#include +#include + +using namespace llvm; + +extern cl::opt ReplaceConfigFileName; + +struct IntReplacerIterate: public ModulePass { + static char ID; + FlipConfig *_zConfig; + + + IntReplacerIterate() : ModulePass(ID) + { + _zConfig = new FlipConfig(ReplaceConfigFileName); + + } + virtual bool + runOnModule(Module &M) + { + for (auto mIt = _zConfig->getReplaceMap().begin(); + mIt != _zConfig->getReplaceMap().end(); ++mIt) { + + std::string fnName = mIt->first; + FunctionConfig mFc = mIt->second; + + if (mFc.shouldAnalyze == false) { + errs() << "Skipping analysis of " << fnName << " \n"; + continue; + } + + Function *f = M.getFunction(fnName); + if (f == NULL) { + continue; + } + + for (inst_iterator I = inst_begin(f), E = inst_end(f); I != E; ++I) { + if (isa(&*I) || isa(&*I)) { + CallSite cs(&*I); + Function *called = cs.getCalledFunction(); + if (!called->hasName()) { + continue; // XXX Currently require functions to have names + } + + /* + * Determine if the call is of a function we don't want to replace args of.. + */ + if (std::find(skip_replace_functions.begin(), + skip_replace_functions.end(), + called->getName()) != skip_replace_functions.end()) { + errs() << "Skipping: " << called->getName().str() << "\n"; + continue; // Skip it. + } + + /* + * Go through all the called function's arguments. See if + * any are supported by replacement. + */ + unsigned numArgOps = cs.getNumArgOperands(); + for (unsigned ii = 0; ii < numArgOps; ii++) { + Value *va = cs.getArgOperand(ii); + Type *ta = va->getType(); + + /* + * If not a 8, 16, 32, or 64 bit integer, we skip it. + */ + if (TypeValueSupport::isReplaceable(ta, va) == false) { + continue; + } + + /* + * Based on configuration, choose the randomization method. + */ + std::string rndtype = ""; + if (mFc.randomType == 0) { + rndtype = "rep"; + } else { + rndtype = "bitflip"; + } + unsigned nBits = ta->getIntegerBitWidth(); + std::string rndFnName = "__" + rndtype + "_randomizer_i" + std::to_string(nBits) + "__"; + + /* + * The randomizer functions /should/ already be in the module, so get the handle. + */ + Function *insertedRndFn = M.getFunction(rndFnName); + assert(insertedRndFn != NULL); + + /* + * We allow different means for different functions. + */ + ConstantInt *mn = ConstantInt::get(M.getContext(), APInt(32, mFc.mean, false)); + + /* + * Insert call to randomizer with input integer and a mean value. + * It will be inserted before the CallInst. + */ + CallInst *callNewFunc = CallInst::Create(insertedRndFn, + { va, mn }, // Arguments are the integer to maybe flip and the mean value + "__rnd_replicant_", + cs.getInstruction()); // insert our call to the rnd fn before the targeted call instruction + + /* + * Replace the old integer argument with the randomized one + */ + cs.setArgument(ii, callNewFunc); + + } + } + } + } + return true; + } + +}; + +char IntReplacerIterate::ID = 0; +static RegisterPass XX("replace-ints-iterate", "Replace int function args with randomizer-integers using instruction iteration"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/IntReplacerVisitor.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/IntReplacerVisitor.cpp new file mode 100644 index 0000000..24a3ed9 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/IntReplacerVisitor.cpp @@ -0,0 +1,184 @@ +/* + * This is one of three examples of integer replacer pass. + * In this example, we make use of the visitor patterned + * API.. which allows us to implement an InstVisitor which + * let's avoid the if statment checking of instructions + * that you can see in the second integer replacer pass + * + * We implement visitCallSite() which handles both CallInst and + * InvokeInst cases as one. + * + */ + + +#include "llvm/IR/Module.h" +#include "llvm/IR/InstVisitor.h" +#include "llvm/IR/CallSite.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/CommandLine.h" + +#include "TypeValueSupport.h" +#include "BaseRandomizer.h" + +#include +#include "FlipConfig.h" + +#include +#include + +using namespace llvm; + +cl::opt ReplaceConfigFileName("repcfg", cl::desc("")); + +class CodeModificationLocation { +private: + Instruction *callLocation; + Type *argumentType; + Value *argumentValue; + unsigned argumentIdx; + +public: + CodeModificationLocation(Instruction *c, Type *t, Value *v, unsigned i) : callLocation(c), argumentType(t), argumentValue(v), argumentIdx(i) { }; + CallSite getCallSite() { return CallSite(callLocation); } + Type *getArgumentType() { return argumentType; } + Value *getArgumentValue() { return argumentValue; } + unsigned getArgumentIdx() { return argumentIdx; } +}; + +struct IntReplacerVisitor: public ModulePass { + static char ID; + + std::vector modificationList; + FlipConfig *_zConfig; + + IntReplacerVisitor() : ModulePass(ID) + { + _zConfig = new FlipConfig(ReplaceConfigFileName); + } + + virtual bool + runOnModule(Module &M) + { + for (auto mIt = _zConfig->getReplaceMap().begin(); + mIt != _zConfig->getReplaceMap().end(); ++mIt) { + + std::string fnName = mIt->first; + FunctionConfig mFc = mIt->second; + if (mFc.shouldAnalyze == false) { + errs() << "Per config: skipping analysis of " << fnName << " \n"; + continue; + } + + Function *f = M.getFunction(fnName); + if (f == NULL) { + errs() << "Can't find function: " << fnName << " \n"; + continue; + } + + /* + * The way this currently works -- you can do it many ways -- but the + * way this works is that the visit finds any/all call instructions in + * the target function. There, it looks to see if there are any integer + * arguments that we want to replace with a randomizer.. if there are, + * we save them to a list of locations to change. Once gathering that + * list, we iterate and modify. + */ + CheckCallInsts cCheck; + cCheck.setIntReplacerVisitor(this); + cCheck.visit(*f); + + for (auto iml = modificationList.begin(); + iml != modificationList.end(); ++iml) { + CodeModificationLocation cLoc = *iml; + CallSite cs = cLoc.getCallSite(); + IntegerType *t = cast(cLoc.getArgumentType()); + unsigned nBits = t->getBitWidth(); + + /* Lookup randomizer function to use */ + std::string rndtype = ""; + if (mFc.randomType == 0) { + rndtype = "rep"; + } else { + rndtype = "bitflip"; + } + std::string rndFnName = "__" + rndtype + "_randomizer_i" \ + + std::to_string(nBits) + "__"; + + // the randomizers should already be in, so we assert. + Function *insertedRndFn = cs.getParent()->getModule()->getFunction(rndFnName); + assert(insertedRndFn != NULL); + + // Base mean value on what the configuration says + ConstantInt *mn = ConstantInt::get(M.getContext(), APInt(32, mFc.mean, false)); + + CallInst *callNewFunc = CallInst::Create(insertedRndFn, + { cLoc.getArgumentValue(), mn }, // Arguments are the integer to maybe flip and the mean value + "__rnd_replicant_", + cs.getInstruction()); // insert our call to the rnd fn before the targeted call instruction + + cs.setArgument(cLoc.getArgumentIdx(), callNewFunc); + } + modificationList.clear(); + } + return true; + } + + struct CheckCallInsts : public InstVisitor { + IntReplacerVisitor *__ziInst; + + void + setIntReplacerVisitor(IntReplacerVisitor *p) + { + __ziInst = p; + } + + /* + * Could do this with two separate functions visitCallInst() and + * visitInvokeInst().. the difference is one is in the exception handling + * case and tthe other (the former) is for normal calling contexts. + * CallSite provides a reasonable common ground for the two. + * + */ + void + visitCallSite(CallSite callSite) + { + /* + * Skip called functions that are on the skip_replace list. + */ + Function *called = callSite.getCalledFunction(); + if (!called->hasName()) { + return; + } + if (std::find(skip_replace_functions.begin(), + skip_replace_functions.end(), + called->getName()) != skip_replace_functions.end()) { + errs() << "Skipping replace function: " << called->getName() << "\n"; + return; + } + + /* + * For each argument, determine if it of type and value that is replaceable. + * At this point, we just note the location by storing CallSite, Type, + * Value, and an arg index as a place to change. + * + */ + unsigned numArgOps = callSite.getNumArgOperands(); + for (unsigned ii = 0; ii < numArgOps; ii++) { + Value *va = callSite.getArgOperand(ii); + Type *ta = va->getType(); + if (TypeValueSupport::isReplaceable(ta, va)) { + CodeModificationLocation ml = CodeModificationLocation( + callSite.getInstruction(), + ta, + va, + ii); + __ziInst->modificationList.push_back(ml); + } + } + } + private: + }; +}; + +char IntReplacerVisitor::ID = 0; +static RegisterPass XX("replace-ints-visitor", "Replace int function args with randomizer-integers using instruction visitor"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/LiftConstantIntPass.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/LiftConstantIntPass.cpp new file mode 100644 index 0000000..00daff0 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/LiftConstantIntPass.cpp @@ -0,0 +1,113 @@ +/* + * This is a module pass that likely will not have + * impact given possibly run passes, but for our + * purposes we should have it just in case. + * + * What it does is identifies call instructions that + * are passed a integral constant to the target function. + * We lift that constant into a local variable and + * adjust the function call to use the variable. + * + * The reason for doing this is that the passes run after + * this want to act on variables of integer type and so + * this makes that possible to do without checking types.. + * + */ + +#include "llvm/IR/Module.h" +#include "llvm/IR/InstVisitor.h" +#include "llvm/IR/CallSite.h" + +#include "TypeValueSupport.h" + +using namespace llvm; + +struct LiftConstantIntPass : public ModulePass { + static char ID; + + LiftConstantIntPass() : ModulePass(ID) {} + + virtual bool + runOnModule(Module &M) + { + bool modified = false; + + /* + * Visit the call instructions of each function in this + * module. + */ + for (auto &f : M) { + + CheckCallInsts cCheck; + cCheck.visit(f); + if (cCheck.modified) { + modified = true; + } + } + return modified; + } + + struct CheckCallInsts : public InstVisitor { + bool modified = false; + + void + visitCallSite(CallSite callSite) + { + unsigned numArgOps = callSite.getNumArgOperands(); + unsigned argIdx; + + /* + * Check all arguments to the called function to see + * they are a constant integer of a size we can lift. + * + * If an argument is liftable, we allocated space for it + * and store the constant to it. Then, load value and use + * it to replace the constant integer argument to the + * function called. + */ + for (argIdx = 0; argIdx < numArgOps; argIdx++) { + Value *va = callSite.getArgOperand(argIdx); + + if (TypeValueSupport::isLiftable(va) == true) { + ConstantInt *con = cast(va); + + unsigned nBits = con->getBitWidth(); + + AllocaInst *localized__alloc = new AllocaInst( + IntegerType::get(callSite.getParent()->getContext(), nBits), // type to allocate + "__intflip_localized", // give the slot a label + callSite.getInstruction()); // Insert before call instruction + + StoreInst *localized__store = new StoreInst( + con, // value to store + localized__alloc, // where to store it + callSite.getInstruction()); // Insert before call instruction + + LoadInst *localized__load = new LoadInst( + localized__alloc, // pointer to load from + (const char *)"__intflip_loaded", // label the slot + callSite.getInstruction()); // Insert before call instruction + + /* + * after that series we now have: + * alloca + * store + * load + * call + * sequence of instructions + */ + + /* replace the constant in the function call */ + callSite.setArgument(argIdx, localized__load); + new_vars++; + modified = true; + } + } + } + private: + unsigned new_vars = 0; + }; +}; + +char LiftConstantIntPass::ID = 0; +static RegisterPass XX("lift-constant-int-args", "Lifts constant int fn args to a local variable"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/ReplaceRandomizer.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/ReplaceRandomizer.cpp new file mode 100644 index 0000000..bcbc04e --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/ReplaceRandomizer.cpp @@ -0,0 +1,113 @@ +#include "llvm/IR/Module.h" +#include "llvm/IR/IRBuilder.h" + +#include "ReplaceRandomizer.h" + +using namespace llvm; +/* + + * This, for each K bits integer type, will inject the function + * + * intK_t + * __rep_randomizer_iK(intK_t inArg0) + * { + * unsigned rv = arc4random(); + * if (rv <= (unsigned)meanValue) { + * return rv; + * } + * return inArg0 + * } + * + * The comments in the macro below show the generated IR along each step..but for + * K=64. + */ +#define injectRIntN(nBits) \ + static void \ + injectInt##nBits(llvm::Module& M, Function *fnRand) \ + { \ + LLVMContext& ctx = M.getContext(); \ + /* \ + * define i64 @__rep_randomizer_i64__(i64 %intToFlip, i32 %meanValue) { \ + * } \ + */ \ + std::string int##nBits##_rand = "__rep_randomizer_i" #nBits "__"; \ + Constant *cTmp = M.getOrInsertFunction(int##nBits##_rand, \ + Type::getInt##nBits##Ty(ctx), \ + Type::getInt##nBits##Ty(ctx), \ + Type::getInt32Ty(ctx), \ + NULL); \ + Function *rep_i##nBits = cast(cTmp); \ + rep_i##nBits->setCallingConv(CallingConv::C); \ + Argument& inArg0 = rep_i##nBits->getArgumentList().front(); \ + inArg0.setName("intToFlip"); \ + Argument& inArg1 = rep_i##nBits->getArgumentList().back(); \ + inArg1.setName("meanValue"); \ + /* \ + * entry: \ + * replace_it: \ + * return: \ + */ \ + BasicBlock *blkEntry = BasicBlock::Create(ctx, "entry", rep_i##nBits); \ + BasicBlock *blkRepIt = BasicBlock::Create(ctx, "replace_it", rep_i##nBits); \ + BasicBlock *blkReturn = BasicBlock::Create(ctx, "return", rep_i##nBits); \ + /* \ + * entry: \ + * %__rep_rand_ = call i32 @arc4random() \ + * %__rep_lessthan_ = icmp ule i32 %__rep_rand_, %meanValue \ + * br i1 %__rep_lessthan_, label %replace_it, label %return \ + * replace_it: \ + * return: \ + */ \ + IRBuilder<> builder(blkEntry); \ + Value *callArc4Random = builder.CreateCall(fnRand, None, "__rep_rand_", nullptr); \ + Value *lessThan = builder.CreateICmpULE(callArc4Random, &inArg1, "__rep_lessthan_");\ + Value *branchRep = builder.CreateCondBr(lessThan, blkRepIt, blkReturn); \ + \ + /* \ + * ... \ + * replace_it: ; preds = %entry \ + * %__rep_cast_ = zext i32 %__rep_rand_ to i64 \ + * ret i64 %__rep_cast_ \ + */ \ + builder.SetInsertPoint(blkRepIt); \ + Value *castRand = builder.CreateZExtOrTrunc(callArc4Random, \ + Type::getInt##nBits##Ty(ctx), "__rep_cast_"); \ + Value *cr = builder.CreateRet(castRand); \ + \ + /* \ + * ... \ + * return: ; preds = %entry \ + * ret i64 %intToFlip \ + */ \ + builder.SetInsertPoint(blkReturn); \ + Value *cr2 = builder.CreateRet(&inArg0); \ + } \ + + +injectRIntN(64) +injectRIntN(32) +injectRIntN(16) +injectRIntN(8) + +void +ReplaceRandomizer::inject(Module& M) +{ + LLVMContext& ctx = M.getContext(); + + /* + * If arc4random is already in the module, then return the Function for it; otherwise, + * declare it so it will be pulled in. It should be within scope, so we assert. + */ + Constant *lookupRand = M.getOrInsertFunction("arc4random", Type::getInt32Ty(ctx), NULL); + assert(lookupRand != NULL && "ReplaceRandomizer::inject(): failed getFunction(arc4random)\n"); + + Function *fnRand = cast(lookupRand); + + injectInt64(M, fnRand); + injectInt32(M, fnRand); + injectInt16(M, fnRand); + injectInt8(M, fnRand); + +} + + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/ReplaceRandomizer.h b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/ReplaceRandomizer.h new file mode 100644 index 0000000..440eaa3 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/ReplaceRandomizer.h @@ -0,0 +1,10 @@ +#ifndef __REPLACERANDOMIZER_H +#define __REPLACERANDOMIZER_H + +#include "BaseRandomizer.h" + +class ReplaceRandomizer : BaseRandomizer { +public: + static void inject(llvm::Module& M); +}; +#endif // !__REPLACERANDOMIZER_H diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/TypeValueSupport.h b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/TypeValueSupport.h new file mode 100644 index 0000000..02c3a6f --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/src/TypeValueSupport.h @@ -0,0 +1,53 @@ +#ifndef __TYPEVALUESUPPORT_H +#define __TYPEVALUESUPPORT_H + +class TypeValueSupport { + +public: + TypeValueSupport() {} + + static bool + isLiftable(llvm::Value *v) + { + /* dyn_cast<>() will return NULL if cast fails */ + if (llvm::ConstantInt *c = llvm::dyn_cast(v)) { + unsigned nBits = c->getBitWidth(); + switch (nBits) { + case 64: + case 32: + case 16: + case 8: + return true; + } + } + return false; + } + + static bool + isReplaceable(llvm::Type *t, llvm::Value *v) + { + + /* isa<>() returns boolean as to whether can cast */ + if (llvm::isa(v) == true) { + /* + * Maybe assert() and say you should run the lifting + * pass before this one? Or just report that... + */ + return false; + } + + /* dyn_cast<>() will return NULL if cast fails */ + if (llvm::IntegerType *intType = llvm::dyn_cast(t)) { + unsigned nBits = intType->getBitWidth(); + switch (nBits) { + case 64: + case 32: + case 16: + case 8: + return true; + } + } + return false; + } +}; +#endif // !__TYPEVALUESUPPORT_H diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/test/foo.c b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/test/foo.c new file mode 100644 index 0000000..d1b557f --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/test/foo.c @@ -0,0 +1,142 @@ +#include +#include +#include + +#define MAXITER (4 * 4096) + +char +bf8(char in) +{ + return in; +} + +static void * +thd_bf8(void *a) +{ + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_bf8: %d\n", bf8(0)); + return a; +} + +short +bf16(short in) +{ + return in; +} + +static void * +thd_bf16(void *a) +{ + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_bf16: %d\n", bf16(0)); + return a; +} + +int +bf32(int in) +{ + return in; +} + +static void * +thd_bf32(void *a) +{ + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_bf32: %d\n", bf32(0)); + return a; +} + +int64_t +bf64(int64_t in) +{ + return in; +} + +static void * +thd_bf64(void *a) +{ + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_bf64: %ld\n", bf64(0)); + return a; +} + +char +rr8(char in) +{ + return in; +} + +static void * +thd_rr8(void *a) +{ + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_rr8: %d\n", rr8(0)); + return a; +} + +short +rr16(short in) +{ + return in; +} + +static void * +thd_rr16(void *a) +{ + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_rr16: %d\n", rr16(0)); + return a; +} + +int +rr32(int in) +{ + return in; +} + +static void * +thd_rr32(void *a) +{ + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_rr32: %d\n", rr32(0)); + return a; +} + +int64_t +rr64(int64_t in) +{ + return in; +} + +static void * +thd_rr64(void *a) +{ + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_rr64: %ld\n", rr64(0)); + return a; +} + +int +main(int argc, char **argv) +{ + pthread_t a,b,c,d,e,f,g,h; + printf("Creating.\n"); + pthread_create(&a, NULL, &thd_bf8, NULL); + pthread_create(&b, NULL, &thd_bf16, NULL); + pthread_create(&c, NULL, &thd_bf32, NULL); + pthread_create(&d, NULL, &thd_bf64, NULL); + pthread_create(&e, NULL, &thd_rr8, NULL); + pthread_create(&f, NULL, &thd_rr16, NULL); + pthread_create(&g, NULL, &thd_rr32, NULL); + pthread_create(&h, NULL, &thd_rr64, NULL); + printf("Created.\n"); + pthread_join(a, NULL); + pthread_join(b, NULL); + pthread_join(c, NULL); + pthread_join(d, NULL); + pthread_join(e, NULL); + pthread_join(f, NULL); + pthread_join(g, NULL); + pthread_join(h, NULL); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/test/foo.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/test/foo.cpp new file mode 100644 index 0000000..81c9d20 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/test/foo.cpp @@ -0,0 +1,183 @@ +#include +#include +#include + +#define MAXITER (8 * 4096) + +char +bf8(char in) +{ + if (in != 0 && " 0" == NULL) { + throw 2; + } + return in; +} + +static void * +thd_bf8(void *a) +{ + try { + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_bf8: %d\n", bf8(0)); + } catch (int e) {} + return a; +} + +short +bf16(short in) +{ + if (in != 0 && " 0" == NULL) { + throw 2; + } + return in; +} + +static void * +thd_bf16(void *a) +{ + try { + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_bf16: %d\n", bf16(0)); + } catch (int e) {} + return a; +} + +int +bf32(int in) +{ + if (in != 0 && " 0" == NULL) { + throw 2; + } + return in; +} + +static void * +thd_bf32(void *a) +{ + try { + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_bf32: %d\n", bf32(0)); + } catch (int e) {} + return a; +} + +int64_t +bf64(int64_t in) +{ + if (in != 0 && " 0" == NULL) { + throw 2; + } + return in; +} + +static void * +thd_bf64(void *a) +{ + try { + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_bf64: %ld\n", bf64(0)); + } catch (int e) {} + return a; +} + +char +rr8(char in) +{ + if (in != 0 && " 0" == NULL) { + throw 2; + } + return in; +} + +static void * +thd_rr8(void *a) +{ + try { + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_rr8: %d\n", rr8(0)); + } catch (int e) {} + return a; +} + +short +rr16(short in) +{ + if (in != 0 && " 0" == NULL) { + throw 2; + } + return in; +} + +static void * +thd_rr16(void *a) +{ + try { + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_rr16: %d\n", rr16(0)); + } catch (int e) {} + return a; +} + +int +rr32(int in) +{ + if (in != 0 && " 0" == NULL) { + throw 2; + } + return in; +} + +static void * +thd_rr32(void *a) +{ + try { + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_rr32: %d\n", rr32(0)); + } catch (int e) {} + return a; +} + +int64_t +rr64(int64_t in) +{ + if (in != 0 && " 0" == NULL) { + throw 2; + } + return in; +} + +static void * +thd_rr64(void *a) +{ + try { + for (unsigned i = 0; i < MAXITER; i++) + printf("thd_rr64: %ld\n", rr64(0)); + } catch (int e) {} + return a; +} + +int +main(int argc, char **argv) +{ + pthread_t a,b,c,d,e,f,g,h; + printf("Max iter = %u\n", MAXITER); + printf("Creating.\n"); + pthread_create(&a, NULL, &thd_bf8, NULL); + pthread_create(&b, NULL, &thd_bf16, NULL); + pthread_create(&c, NULL, &thd_bf32, NULL); + pthread_create(&d, NULL, &thd_bf64, NULL); + pthread_create(&e, NULL, &thd_rr8, NULL); + pthread_create(&f, NULL, &thd_rr16, NULL); + pthread_create(&g, NULL, &thd_rr32, NULL); + pthread_create(&h, NULL, &thd_rr64, NULL); + printf("Created.\n"); + pthread_join(a, NULL); + pthread_join(b, NULL); + pthread_join(c, NULL); + pthread_join(d, NULL); + pthread_join(e, NULL); + pthread_join(f, NULL); + pthread_join(g, NULL); + pthread_join(h, NULL); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/intflip/thirdparty/jsoncpp-1.8.0.tar.gz b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/thirdparty/jsoncpp-1.8.0.tar.gz new file mode 100644 index 0000000..a25d895 Binary files /dev/null and b/Security Research and Development with LLVM - Andrew Reiter/code/intflip/thirdparty/jsoncpp-1.8.0.tar.gz differ diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/Makefile b/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/Makefile new file mode 100644 index 0000000..6cfa5c1 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/Makefile @@ -0,0 +1,51 @@ +LLVM_VER=3.9 +LLVM_HOME=/usr/bin +LLVM_CONFIG?=$(LLVM_HOME)/llvm-config-$(LLVM_VER) + +ifndef VERBOSE +QUIET:=@ +endif + +SRC_DIR?=$(PWD)/src + +CXX=$(LLVM_HOME)/clang++-$(LLVM_VER) +CC=$(LLVM_HOME)/clang-$(LLVM_VER) +OPT=$(LLVM_HOME)/opt-$(LLVM_VER) +DIS=$(LLVM_HOME)/llvm-dis-$(LLVM_VER) +LNK=$(LLVM_HOME)/llvm-link-$(LLVM_VER) + +LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags) +LDFLAGS+=-shared -Wl,-O1 + +CXXFLAGS+=-I$(shell $(LLVM_CONFIG) --includedir) +CXXFLAGS+=-std=c++11 -fPIC -fvisibility-inlines-hidden +CXXFLAGS+=-Wall -Wextra -g -Wno-unused-parameter -Wno-unused-variable + +CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) +CPPFLAGS+=-I$(SRC_DIR) + +PASS=LPSkel.so +PASS_OBJECTS=LPSkel.o + +default: prep $(PASS) + +prep: + $(QUIET)mkdir -p built + +%.o : $(SRC_DIR)/%.cpp + @echo Compiling $*.cpp + $(QUIET)$(CXX) -o built/$*.o -c $(CPPFLAGS) $(CXXFLAGS) $< + +$(PASS) : $(PASS_OBJECTS) + @echo Linking $@ + $(QUIET)$(CXX) -o built/$@ $(LDFLAGS) $(CXXFLAGS) built/*.o + +clean: + $(QUIET)rm -rf built test/*.bc + + +tests: + $(CC) -emit-llvm -o test/foo.bc -c test/foo.c + +runtests: + $(OPT) -load built/LPSkel.so -lpskel < test/foo.bc diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/README.md b/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/README.md new file mode 100644 index 0000000..5513679 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/README.md @@ -0,0 +1,18 @@ + +# LoopPass Skeleton + +Visit loops in code; outer loop met last. + +# Build & Run + +First check the Makefile to set path to llvm-config and version. +3.8, 3.9 should be fine, so should 4.0 + +``` +$ make +$ opt-X.Y -load built/LPSkel.so -lpskel < file.bc +... +$ +``` + + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/src/LPSkel.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/src/LPSkel.cpp new file mode 100644 index 0000000..2fad39d --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/src/LPSkel.cpp @@ -0,0 +1,47 @@ +#include "llvm/IR/Module.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Analysis/LoopPass.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#include "LPSkel.h" + +void +LPSkel::getAnalysisUsage(AnalysisUsage &AU) const +{ + // No changes to CFG, so tell the pass manager + AU.setPreservesCFG(); +} + +bool +LPSkel::doFinalization() +{ + return false; +} + +bool +LPSkel::doInitialization(Loop *L, LPPassManager &LP) +{ + return false; +} + +bool +LPSkel::runOnLoop(Loop *L, LPPassManager &LP) +{ + errs() << " Loop found:\n"; + L->print(errs(), 1); + errs() << " --- end of Loop ---\n"; + + // return true if Function has been changed. + return false; +} + +/* + * Register this pass to be made usable. + * Needs the static ID initialized and the pass declaration given. + */ +char LPSkel::ID = 0; +static RegisterPass XX("lpskel", "Loop Pass Skeleton"); + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/src/LPSkel.h b/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/src/LPSkel.h new file mode 100644 index 0000000..73200e7 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/src/LPSkel.h @@ -0,0 +1,28 @@ +#ifndef __LPSKEL_H +#define __LPSKEL_H + +struct LPSkel : public LoopPass { + /* + * For all of your passes you will need this and to define it. + * It's address is used by pass system, so the value does not matter. + */ + static char ID; + + LPSkel() : LoopPass(ID) { + } + + // Return true if Function was modified, otherwise false. + virtual bool runOnLoop(Loop *L, LPPassManager &LP); + + /* + * Used to help order passes by pass manager. + * Declare any passes you need run prior here.. as well as + * any information such as preserving CFG or similar. + */ + virtual void getAnalysisUsage(AnalysisUsage &) const; + + virtual bool doInitialization(Loop *L, LPPassManager &LPM); + virtual bool doFinalization(); +}; + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/test/foo.c b/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/test/foo.c new file mode 100644 index 0000000..1da3364 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/lpskel/test/foo.c @@ -0,0 +1,13 @@ +#include + +int +main(int argc, char **argv) +{ + unsigned z = 0; + if (argc <= 0) argc = 30; + for (unsigned k = 0; k < argc; ++k) { + z += k * 2; + } + printf("zeta: %u\n", z); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/Makefile b/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/Makefile new file mode 100644 index 0000000..b9d3614 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/Makefile @@ -0,0 +1,46 @@ +LLVM_VER=3.9 +LLVM_HOME=/usr/bin +LLVM_CONFIG?=$(LLVM_HOME)/llvm-config-$(LLVM_VER) + +ifndef VERBOSE +QUIET:=@ +endif + +SRC_DIR?=$(PWD)/src + +CXX=$(LLVM_HOME)/clang++-$(LLVM_VER) +CC=$(LLVM_HOME)/clang-$(LLVM_VER) +OPT=$(LLVM_HOME)/opt-$(LLVM_VER) +DIS=$(LLVM_HOME)/llvm-dis-$(LLVM_VER) +LNK=$(LLVM_HOME)/llvm-link-$(LLVM_VER) + +LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags) +LDFLAGS+=-shared -Wl,-O1 + +CXXFLAGS+=-I$(shell $(LLVM_CONFIG) --includedir) +CXXFLAGS+=-std=c++11 -fPIC -fvisibility-inlines-hidden +CXXFLAGS+=-Wall -Wextra -g -Wno-unused-parameter -Wno-unused-variable + +CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) +CPPFLAGS+=-I$(SRC_DIR) + + +PASS=MPSkel.so +PASS_OBJECTS=MPSkel.o + +default: prep $(PASS) + +prep: + $(QUIET)mkdir -p built + +%.o : $(SRC_DIR)/%.cpp + @echo Compiling $*.cpp + $(QUIET)$(CXX) -o built/$*.o -c $(CPPFLAGS) $(CXXFLAGS) $< + +$(PASS) : $(PASS_OBJECTS) + @echo Linking $@ + $(QUIET)$(CXX) -o built/$@ $(LDFLAGS) $(CXXFLAGS) built/*.o + +clean: + $(QUIET)rm -rf built + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/README.md b/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/README.md new file mode 100644 index 0000000..a26bed4 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/README.md @@ -0,0 +1,19 @@ + +# MPSkel + +This is a module pass skeleton. + + +# Build & Run + +First check the Makefile to set path to llvm-config and version. +3.8, 3.9 should be fine, so should 4.0 + +``` +$ make +$ opt-X.Y -load built/MPSkel.so -mpskel < file.bc +... +$ +``` + + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/src/MPSkel.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/src/MPSkel.cpp new file mode 100644 index 0000000..6c65560 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/src/MPSkel.cpp @@ -0,0 +1,68 @@ +#include "llvm/IR/Module.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/CallSite.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#include "MPSkel.h" + +void +MPSkel::getAnalysisUsage(AnalysisUsage &AU) const +{ + AU.setPreservesCFG(); +} + +bool +MPSkel::runOnModule(Module &M) +{ + + /* Iterate through all functions in this module */ + for (auto &F : M) { + std::string fname = "not named"; + if (F.hasName()) { + fname = F.getName().str(); + } + + // If no uses, don't look further. + if (F.user_empty()) { + errs() << "Function (" << fname << ") not used.\n"; + continue; + } + errs() << "Listing uses for function (" << fname << ")\n"; + for (auto uit = F.user_begin(); uit != F.user_end(); ++uit) { + User *u = *uit; + errs() << " "; + std::string pn = ""; + + // Is this use a Call or Invoke instruction? + if (isa(u) || isa(u)) { + // It is, so let's use the common class CallSite + CallSite cs(dyn_cast(u)); + + // Instruction in a BasicBlock in a Function. + Function *caller = cs.getParent()->getParent(); + if (caller->hasName()) { + pn = caller->getName().str(); + } else { + pn = "not named"; + } + errs() << pn << ": "; + } + + // Just print out what Value is + u->dump(); + // If has debug info, we should just dump that as well + } + errs() << "\n"; + } + return false; // CFG did not change +} + +/* + * Register this pass to be made usable. + * Needs the static ID initialized and the pass declaration given. + */ +char MPSkel::ID = 0; +static RegisterPass XX("mpskel", "Module Pass Skeleton"); + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/src/MPSkel.h b/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/src/MPSkel.h new file mode 100644 index 0000000..db79f49 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/mpskel/src/MPSkel.h @@ -0,0 +1,25 @@ +#ifndef __MPSKEL_H +#define __MPSKEL_H + +struct MPSkel : public ModulePass { + /* + * For all of your passes you will need this and to define it. + * It's address is used by pass system, so the value does not matter. + */ + static char ID; + + MPSkel() : ModulePass(ID) { } + + // Called on each compilation unit + virtual bool runOnModule(Module &); + + /* + * Used to help order passes by pass manager. + * Declare any passes you need run prior here.. as well as + * any information such as preserving CFG or similar. + */ + virtual void getAnalysisUsage(AnalysisUsage &) const; + +}; + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/npassert/Makefile b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/Makefile new file mode 100644 index 0000000..c5e60ae --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/Makefile @@ -0,0 +1,76 @@ +LLVM_VER=3.8 +#LLVM_VER=3.9 +#LLVM_VER=4.0 +LLVM_HOME=/usr/bin +LLVM_CONFIG?=$(LLVM_HOME)/llvm-config-$(LLVM_VER) + +ifndef VERBOSE +QUIET:=@ +endif + +SRC_DIR?=$(PWD)/src + +CXX=$(LLVM_HOME)/clang++-$(LLVM_VER) +CC=$(LLVM_HOME)/clang-$(LLVM_VER) +OPT=$(LLVM_HOME)/opt-$(LLVM_VER) +DIS=$(LLVM_HOME)/llvm-dis-$(LLVM_VER) +LNK=$(LLVM_HOME)/llvm-link-$(LLVM_VER) + +LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags) +LDFLAGS+=-shared -Wl,-O1 + +CXXFLAGS+=-I$(shell $(LLVM_CONFIG) --includedir) +CXXFLAGS+=-std=c++11 -fPIC -fvisibility-inlines-hidden +CXXFLAGS+=-Wall -Wextra -g -Wno-unused-parameter -Wno-unused-variable + +CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) +CPPFLAGS+=-I$(SRC_DIR) + +PASS=libnpassert.so +PASS_OBJECTS=NullPtrAssertPass.o + +default: prep $(PASS) + +prep: + $(QUIET)mkdir -p built + +%.o : $(SRC_DIR)/%.cpp + @echo Compiling $*.cpp + $(QUIET)$(CXX) -o built/$*.o -c $(CPPFLAGS) $(CXXFLAGS) $< + +$(PASS) : $(PASS_OBJECTS) + @echo Linking $@ + $(QUIET)$(CXX) -o built/$@ $(LDFLAGS) $(CXXFLAGS) built/*.o + +clean: + $(QUIET)rm -rf built + +tests: + $(QUIET)echo "Generating bitcode from C" + $(QUIET)$(CC) -g -emit-llvm -c -o test/ex01.bc test/ex01.c + $(QUIET)$(CC) -g -emit-llvm -c -o test/ex02.bc test/ex02.c + $(QUIET)$(OPT) -load built/libnpassert.so -null-ptr-assert -npa-use-function -o test/ex02c.bc < test/ex02.bc + $(QUIET)echo "Attempting to inject assertions" + $(QUIET)$(OPT) -load built/libnpassert.so -null-ptr-assert -o test/ex01a.bc < test/ex01.bc + $(QUIET)$(OPT) -load built/libnpassert.so -null-ptr-assert -o test/ex02a.bc < test/ex02.bc + $(QUIET)echo "Running inject with config file" + $(QUIET)$(OPT) -load built/libnpassert.so -null-ptr-assert -npa-target-config conf/targ.cfg -o test/ex01b.bc < test/ex01.bc + $(QUIET)$(OPT) -load built/libnpassert.so -null-ptr-assert -npa-target-config conf/targ.cfg -o test/ex02b.bc < test/ex02.bc + $(QUIET)echo "Running llvm-dis on the bitcode files" + $(QUIET)$(DIS) --o=test/ex01a.ll test/ex01a.bc + $(QUIET)$(DIS) --o=test/ex01b.ll test/ex01b.bc + $(QUIET)$(DIS) --o=test/ex01.ll test/ex01.bc + $(QUIET)$(DIS) --o=test/ex02a.ll test/ex02a.bc + $(QUIET)$(DIS) --o=test/ex02b.ll test/ex02b.bc + $(QUIET)$(DIS) --o=test/ex02.ll test/ex02.bc + $(QUIET)echo "Compiling to machine code (elf)" + $(QUIET)$(CC) -g -o test/ex01a test/ex01a.bc + $(QUIET)$(CC) -g -o test/ex01 test/ex01.bc + $(QUIET)$(CC) -g -o test/ex02a test/ex02a.bc + $(QUIET)$(CC) -g -o test/ex02c test/ex02c.bc + $(QUIET)$(CC) -g -o test/ex02 test/ex02.bc + +cleantests: + rm -f test/*.bc test/*.ll test/ex01 test/ex01a test/ex02 test/ex02a test/ex02c + +cleanall: clean cleantests diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/npassert/README.md b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/README.md new file mode 100644 index 0000000..bff98dd --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/README.md @@ -0,0 +1,118 @@ + +The code will look for any/all pointer function arguments and will +insert an assert(ptr != NULL); statement. It shows looking at +functions, their arguments, a function pass, declaring a function, +and inserting code. Why? Eh. A few reasons that are BS, but mostly +to help learn API. + + +## Build and Run + +This requires LLVM and Clang 3.8, 3.9, or 4.0 releases. You should +review the Makefile to setup the LLVM path and version. + +``` +$ make +$ make tests +$ cd tests +``` + +If you do not specify a configuration file, the code will look for all +functions and their arguments. If you specify a configuration file, +it will specify the function and the argument to check. The tests/ex0*b.... +files are those in which a configuration file was specified and the +ex0*a are those in which none was specified.. so you should see a difference + +### Example running by hand +``` +$ clang -g -emit-llvm -c -o FOO.bc FOO.c +$ opt -load built/libnpassert.so -null-ptr-assert -o FOO_assertall.bc < FOO.bc +$ opt -load built/libnpassert.so -null-ptr-assert -npa-target-config FOO.cfg -o FOO_assertbyconfigfile.bc < FOO.bc +$ clang -g -o FOO_assertall FOO_assertall.bc +$ clang -g -o FOO_assertbyconfigfile FOO_assertbyconfigfile.bc +``` + +The last clang steps generate an runnable executable. +Use llvm-dis on bitcode (.bc) files to get the human readable IR +to view the differences. One may also use the -npa-use-function option +which will tell the pass to create a separate function to perform +the assertion in. + +So with the above instead of getting a crash like: +``` +(gdb) r +Starting program: /home/hoser/code/npassert/test/ex02 + +Program received signal SIGSEGV, Segmentation fault. +0x0000000000400549 in foo (s=0x0) at test/ex02.c:16 +16 return s->one; +(gdb) disass foo +Dump of assembler code for function foo: + 0x0000000000400530 <+0>: push %rbp + 0x0000000000400531 <+1>: mov %rsp,%rbp + 0x0000000000400534 <+4>: sub $0x10,%rsp + 0x0000000000400538 <+8>: mov %rdi,-0x8(%rbp) + 0x000000000040053c <+12>: callq 0x400420 + 0x0000000000400541 <+17>: mov %rax,-0x10(%rbp) + 0x0000000000400545 <+21>: mov -0x8(%rbp),%rax +=> 0x0000000000400549 <+25>: mov (%rax),%eax + 0x000000000040054b <+27>: add $0x10,%rsp + 0x000000000040054f <+31>: pop %rbp + 0x0000000000400550 <+32>: retq +End of assembler dump. +(gdb) +``` + +You would get a crash early in the function.. +``` +(gdb) r +Starting program: /home/hoser/code/npassert/test/ex02a +Program received signal SIGSEGV, Segmentation fault. +0x0000000000400554 in foo (s=0x0) at test/ex02.c:12 +12 { +(gdb) disass foo +Dump of assembler code for function foo: + 0x0000000000400530 <+0>: push %rbp + 0x0000000000400531 <+1>: mov %rsp,%rbp + 0x0000000000400534 <+4>: sub $0x20,%rsp + 0x0000000000400538 <+8>: cmp $0x0,%rdi + 0x000000000040053c <+12>: mov %rdi,-0x8(%rbp) + 0x0000000000400540 <+16>: jne 0x400558 + 0x0000000000400546 <+22>: xor %eax,%eax + 0x0000000000400548 <+24>: mov %eax,%ecx + 0x000000000040054a <+26>: mov %rsp,%rdx + 0x000000000040054d <+29>: add $0xfffffffffffffff0,%rdx + 0x0000000000400551 <+33>: mov %rdx,%rsp +=> 0x0000000000400554 <+36>: mov (%rcx),%eax + 0x0000000000400556 <+38>: mov %eax,(%rdx) + 0x0000000000400558 <+40>: mov %rsp,%rax + 0x000000000040055b <+43>: add $0xfffffffffffffff0,%rax + 0x000000000040055f <+47>: mov %rax,%rsp + 0x0000000000400562 <+50>: mov %rsp,%rcx + 0x0000000000400565 <+53>: add $0xfffffffffffffff0,%rcx + 0x0000000000400569 <+57>: mov %rcx,%rsp + 0x000000000040056c <+60>: mov -0x8(%rbp),%rdx + 0x0000000000400570 <+64>: mov %rdx,(%rax) + 0x0000000000400573 <+67>: mov %rax,-0x10(%rbp) + 0x0000000000400577 <+71>: mov %rcx,-0x18(%rbp) + 0x000000000040057b <+75>: callq 0x400420 + 0x0000000000400580 <+80>: mov -0x18(%rbp),%rcx + 0x0000000000400584 <+84>: mov %rax,(%rcx) + 0x0000000000400587 <+87>: mov -0x10(%rbp),%rax + 0x000000000040058b <+91>: mov (%rax),%rdx + 0x000000000040058e <+94>: mov (%rdx),%eax + 0x0000000000400590 <+96>: mov %rbp,%rsp + 0x0000000000400593 <+99>: pop %rbp + 0x0000000000400594 <+100>: retq +``` + +Or if you add the -npa-use-function option +``` +(gdb) r +Starting program: /home/hoser/code/npassert/test/ex02c + +Program received signal SIGSEGV, Segmentation fault. +0x00000000004005b3 in __NPA_assert_8__ () +(gdb) +``` +it will fault in the assertion function. diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/npassert/conf/targ.cfg b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/conf/targ.cfg new file mode 100644 index 0000000..df2bd3c --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/conf/targ.cfg @@ -0,0 +1,5 @@ +# Ignore lines with # +# index by 0 +foo,0 +foo3,1 +foo3,0 diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/npassert/src/NullPtrAssertPass.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/src/NullPtrAssertPass.cpp new file mode 100644 index 0000000..7783084 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/src/NullPtrAssertPass.cpp @@ -0,0 +1,251 @@ +#include "llvm/IR/Module.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/CommandLine.h" + +#include +#include +#include +#include +#include + +using namespace llvm; + +#include "NullPtrAssertPass.h" + +/* + * cl::opt represent options taken from the command line, they can include defaults + * help descriptions, etc. This is how a pass can be made more granular or specifify + * a type of analysis for instance. + */ +cl::opt ReplaceConfigFileName("npa-target-config", + cl::desc("configuration file for np asserts"), cl::init("")); + +cl::opt AssertFunction("npa-use-function", + cl::desc("if set, then create new assertion function"), cl::init(false)); + +void +NullPtrAssertPass::insertAssertionFunction(Module *M) +{ + LLVMContext &ctx = M->getContext(); + + /* + * Insert our own assertion function. void __NPA_assert_8__(i8 *, i32) + */ + Constant *assertFnCon = M->getOrInsertFunction("__NPA_assert_8__", + Type::getVoidTy(ctx), + Type::getInt8PtrTy(ctx), Type::getInt32Ty(ctx), NULL); + assertFn = cast(assertFnCon); + assertFn->setCallingConv(CallingConv::C); + Argument *arg = &assertFn->getArgumentList().front(); + arg->setName("ptrToCheck"); + + /* + * Insert blocks for entry and branches + */ + BasicBlock *blkEntry = BasicBlock::Create(ctx, "npa_entry_blk", assertFn); + BasicBlock *blkAssert = BasicBlock::Create(ctx, "npa_assert_blk", assertFn); + BasicBlock *blkReturn = BasicBlock::Create(ctx, "npa_return_blk", assertFn); + + /* + * Creates a null pointer and compares it with the argument. + * If equal, branch to blkAssert, if not, return block + */ + IRBuilder<> builder8(blkEntry); + PointerType *ptNull = cast(Type::getInt8PtrTy(ctx)); + Value *cpNull0 = ConstantPointerNull::get(ptNull); + Value *eqNull = builder8.CreateICmpEQ(arg, cpNull0); + (void)builder8.CreateCondBr(eqNull, blkAssert, blkReturn); + + /* + * attempt to deref null + */ + builder8.SetInsertPoint(blkAssert); + Value *crLoad = builder8.CreateAlloca(IntegerType::get(ctx, 32)); + auto ptNullB = PointerType::get(IntegerType::get(ctx, 32), 0); + Value *cpNull = ConstantPointerNull::get(ptNullB); + Value *doLoad = builder8.CreateLoad(cpNull); + Value *doStore = builder8.CreateStore(doLoad, crLoad, true); + (void)builder8.CreateRetVoid(); + + /* return block */ + builder8.SetInsertPoint(blkReturn); + (void)builder8.CreateRetVoid(); + +} + +void +NullPtrAssertPass::insertAssertionFunctionCall(Module *M, Function *F, + Argument *A) +{ + LLVMContext &ctx = M->getContext(); + BasicBlock *oe = &F->front(); + Instruction *oi = &oe->front(); + APInt a(32, A->getArgNo(), false); + ConstantInt *cv = ConstantInt::get(ctx, a); + Value *v = new BitCastInst(A, Type::getInt8PtrTy(ctx), "bitcastme_", oi); + CallInst::Create(assertFn, {v, cv}, "", oi); + return; +} + +void +NullPtrAssertPass::insertAssertion(Module *M, Function *F, Argument *A) +{ + LLVMContext &ctx = M->getContext(); + + /* + * Get original first BasicBlock in the function. + */ + BasicBlock *origEntry = &F->front(); + + /* + * Add a new BasicBlock before this original first one. + * This block will hold code that contains the compare and + * conditional branch statements. + */ + BasicBlock *entryBlock = BasicBlock::Create(ctx, "npa_entry_blk", F, + origEntry); + /* + * Add block between the new entry block and the original entry that + * will hold code for causing crash. + */ + BasicBlock *assertBlock = BasicBlock::Create(ctx, "npa_assert_blk", F, + origEntry); + + /* + * Using the IRBuilder API to add code + * Get a NULL pointer and see if it and the argument A + * are equal. + * Branch to the assert block if equal, otherwise, go to + * the original entry block and continue. + */ + IRBuilder<> builder(entryBlock); + Type *typeNull = A->getType(); + assert(isa(typeNull) && "typeNull not PointerType"); + PointerType *ptNull = cast(typeNull); + Value *cpNull0 = ConstantPointerNull::get(ptNull); + Value *eqNull = builder.CreateICmpEQ(A, cpNull0); + (void)builder.CreateCondBr(eqNull, assertBlock, origEntry); + + /* + * Add the crash code to the assertBlock. + * The basic idea is trying to deref null ptr. We could do this + * to re-use some NULLs we might have, but to show more of the API + * we do it in the following manner. + */ + builder.SetInsertPoint(assertBlock); + Value *crLoad = builder.CreateAlloca(IntegerType::get(ctx, 32)); + auto ptNullB = PointerType::get(IntegerType::get(ctx, 32), 0); + Value *cpNull = ConstantPointerNull::get(ptNullB); + Value *doLoad = builder.CreateLoad(cpNull); + Value *doStore = builder.CreateStore(doLoad, crLoad, true); + // Add a terminator for this block so the IR is sane + builder.CreateBr(origEntry); +} + +bool +NullPtrAssertPass::attemptInsertAssert(Module *M, Function *f, int targetIdx) +{ + bool chg = false; + int argIdx = -1; + + /* Decl not defn */ + if (f->isDeclaration() == true) { + return false; + } + + /* No body, nothing to inject */ + if (f->empty() == true) { + return false; + } + + /* Deal with just named functions. */ + if (f->hasName() == false) { + return false; + } + + /* No arguments, nothing to possibly assert. */ + if (f->arg_empty() == true) { + return false; + } + /* We have a specified argument index */ + if (targetIdx >= 0 && f->arg_size() <= (unsigned)targetIdx) { + return false; + } + for (auto ait = f->arg_begin(); ait != f->arg_end(); ++ait) { + ++argIdx; + if (targetIdx != -1 && argIdx != targetIdx) { + continue; + } + Argument *a = &*ait; + Type *ty = a->getType(); + + // The type of this argument is not of pointer; nothing to do. + if (ty->isPointerTy() == false) { + continue; + } + if (AssertFunction) { + insertAssertionFunctionCall(M, f, a); + } else { + insertAssertion(M, f, a); + } + chg = true; + } + return chg; +} + +bool +NullPtrAssertPass::runOnModule(Module &M) +{ + bool chg = false; + + if (AssertFunction) { + insertAssertionFunction(&M); + } + /* Do'em all */ + if (ReplaceConfigFileName == "") { + for (auto fit = M.functions().begin(); + fit != M.functions().end(); ++fit) { + Function *f = &*fit; + if (f->hasName()) { + if (f->getName().str().find("__NPA_",0) == 0) { + continue; + } + } + chg = attemptInsertAssert(&M, f, -1); + } + } else { + std::ifstream hand(ReplaceConfigFileName); + std::string line; + std::string fnName; + std::string argIdx; + int idx; + // We trust that the user is giving us a sane file. + while (std::getline(hand, line)) { + if (line.find("#", 0) == 0) { + continue; + } + size_t i = line.find(",", 0); + fnName = line.substr(0, i); + argIdx = line.substr(i+1); // XXX ;^p + idx = stoi(argIdx, nullptr, 10); + if (idx < 0) { + idx = -1; + } + Function *f = M.getFunction(fnName); + if (f == NULL) { + errs() << "Unable to find function: " << fnName << "\n"; + continue; + } + chg = attemptInsertAssert(&M, f, idx); + } + } + return chg; +} + +char NullPtrAssertPass::ID = 0; +static RegisterPass XX("null-ptr-assert", "Inject null ptr checks"); + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/npassert/src/NullPtrAssertPass.h b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/src/NullPtrAssertPass.h new file mode 100644 index 0000000..78dd82f --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/src/NullPtrAssertPass.h @@ -0,0 +1,19 @@ +#ifndef __NULLPTRASSERTPASS_H +#define __NULLPTRASSERTPASS_H + +struct NullPtrAssertPass : public ModulePass { + static char ID; + + NullPtrAssertPass() : ModulePass(ID) { } + virtual bool runOnModule(Module &); + +private: + void insertAssertion(Module *M, Function *F, Argument *A); + bool attemptInsertAssert(Module *M, Function *F, int); + void insertAssertionFunction(Module *M); + void insertAssertionFunctionCall(Module *M, Function *F, Argument *A); + + Function *assertFn; +}; + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/npassert/test/ex01.c b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/test/ex01.c new file mode 100644 index 0000000..3e35c1e --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/test/ex01.c @@ -0,0 +1,38 @@ +#include +#include + +void +foo(int *ptr) +{ + long int k = 0; + k = random(); + printf("Yessir %ld %d\n", k, *ptr); + return; +} + +void +foo2(char *dingle) +{ + long int k = 0; + + k = random(); + printf("dingle %ld %s\n", k, dingle); +} +void +foo3(int *ptr, char *foo) +{ + long int k = 0; + k = random(); + printf("Yessir %ld %d %s\n", k, *ptr, foo); +} + +int +main(int argc, char **argv) +{ + foo(&argc); + foo2("hi there"); + foo3(&argc, "hi there"); + foo2(NULL); + foo((int *)NULL); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/npassert/test/ex02.c b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/test/ex02.c new file mode 100644 index 0000000..b843cd7 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/npassert/test/ex02.c @@ -0,0 +1,25 @@ +#include +#include + +struct shame { + int one; + int two; + int three; +}; + +int +foo(struct shame *s) +{ + long int z; + + z = random(); + return s->one; +} + +int +main(int argc, char **argv) +{ + struct shame *s = (struct shame *)NULL; + foo(s); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/Makefile b/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/Makefile new file mode 100644 index 0000000..eb542cf --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/Makefile @@ -0,0 +1,51 @@ +LLVM_VER=3.9 +LLVM_HOME=/usr/bin +LLVM_CONFIG?=$(LLVM_HOME)/llvm-config-$(LLVM_VER) + +ifndef VERBOSE +QUIET:=@ +endif + +SRC_DIR?=$(PWD)/src + +CXX=$(LLVM_HOME)/clang++-$(LLVM_VER) +CC=$(LLVM_HOME)/clang-$(LLVM_VER) +OPT=$(LLVM_HOME)/opt-$(LLVM_VER) +DIS=$(LLVM_HOME)/llvm-dis-$(LLVM_VER) +LNK=$(LLVM_HOME)/llvm-link-$(LLVM_VER) + +LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags) +LDFLAGS+=-shared -Wl,-O1 + +CXXFLAGS+=-I$(shell $(LLVM_CONFIG) --includedir) +CXXFLAGS+=-std=c++11 -fPIC -fvisibility-inlines-hidden +CXXFLAGS+=-Wall -Wextra -g -Wno-unused-parameter -Wno-unused-variable + +CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) +CPPFLAGS+=-I$(SRC_DIR) + +PASS=RPSkel.so +PASS_OBJECTS=RPSkel.o + +default: prep $(PASS) + +prep: + $(QUIET)mkdir -p built + +%.o : $(SRC_DIR)/%.cpp + @echo Compiling $*.cpp + $(QUIET)$(CXX) -o built/$*.o -c $(CPPFLAGS) $(CXXFLAGS) $< + +$(PASS) : $(PASS_OBJECTS) + @echo Linking $@ + $(QUIET)$(CXX) -o built/$@ $(LDFLAGS) $(CXXFLAGS) built/*.o + +clean: + $(QUIET)rm -rf built test/*.bc + + +tests: + $(CC) -emit-llvm -o test/foo.bc -c test/foo.c + +runtests: + $(OPT) -load built/RPSkel.so -rpskel < test/foo.bc diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/README.md b/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/README.md new file mode 100644 index 0000000..ae132c5 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/README.md @@ -0,0 +1,17 @@ + +# RegionPass Skeleton + + +# Build & Run + +First check the Makefile to set path to llvm-config and version. +3.8, 3.9 should be fine, so should 4.0 + +``` +$ make +$ opt-X.Y -load built/RPSkel.so -rpskel < file.bc +... +$ +``` + + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/src/RPSkel.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/src/RPSkel.cpp new file mode 100644 index 0000000..0f00bb9 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/src/RPSkel.cpp @@ -0,0 +1,50 @@ +#include "llvm/IR/Module.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Analysis/RegionPass.h" +#include "llvm/Analysis/RegionInfo.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#include "RPSkel.h" + +void +RPSkel::getAnalysisUsage(AnalysisUsage &AU) const +{ + // No changes to CFG, so tell the pass manager + AU.setPreservesCFG(); +} + +bool +RPSkel::doFinalization() +{ + return false; +} + +bool +RPSkel::doInitialization(Region *R, RGPassManager &RGPM) +{ + return false; +} + +bool +RPSkel::runOnRegion(Region *R, RGPassManager &RGPM) +{ + errs() << " Region found:\n"; + + R->print(errs(), true, 1, Region::PrintNone); + errs() << " --- end of Region ---\n"; + + // return true if Region has been changed. + return false; +} + + + +/* + * Register this pass to be made usable. + * Needs the static ID initialized and the pass declaration given. + */ +char RPSkel::ID = 0; +static RegisterPass XX("rpskel", "Region Pass Skeleton"); + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/src/RPSkel.h b/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/src/RPSkel.h new file mode 100644 index 0000000..dadf47c --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/src/RPSkel.h @@ -0,0 +1,28 @@ +#ifndef __RPSKEL_H +#define __RPSKEL_H + +struct RPSkel : public RegionPass { + /* + * For all of your passes you will need this and to define it. + * It's address is used by pass system, so the value does not matter. + */ + static char ID; + + RPSkel() : RegionPass(ID) { + } + + // Return true if Region was modified, otherwise false. + virtual bool runOnRegion(Region *R, RGPassManager &RGM); + + /* + * Used to help order passes by pass manager. + * Declare any passes you need run prior here.. as well as + * any information such as preserving CFG or similar. + */ + virtual void getAnalysisUsage(AnalysisUsage &) const; + + virtual bool doInitialization(Region *R, RGPassManager &RGM); + virtual bool doFinalization(); +}; + +#endif diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/test/foo.c b/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/test/foo.c new file mode 100644 index 0000000..3979e2c --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/rpskel/test/foo.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include +#include + +void +leaks_passwd() +{ + char *p; + struct addrinfo hints, *result; + + p = getpass("enter passwd: "); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + (void)getaddrinfo(p, "http", &hints, &result); +} + +int +main(int argc, char **argv) +{ + leaks_passwd(); + return 0; +} diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/visitorskel/Makefile b/Security Research and Development with LLVM - Andrew Reiter/code/visitorskel/Makefile new file mode 100644 index 0000000..2e3c387 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/visitorskel/Makefile @@ -0,0 +1,46 @@ +LLVM_VER=3.9 +LLVM_HOME=/usr/bin +LLVM_CONFIG?=$(LLVM_HOME)/llvm-config-$(LLVM_VER) + +ifndef VERBOSE +QUIET:=@ +endif + +SRC_DIR?=$(PWD)/src + +CXX=$(LLVM_HOME)/clang++-$(LLVM_VER) +CC=$(LLVM_HOME)/clang-$(LLVM_VER) +OPT=$(LLVM_HOME)/opt-$(LLVM_VER) +DIS=$(LLVM_HOME)/llvm-dis-$(LLVM_VER) +LNK=$(LLVM_HOME)/llvm-link-$(LLVM_VER) + +LDFLAGS+=$(shell $(LLVM_CONFIG) --ldflags) +LDFLAGS+=-shared -Wl,-O1 + +CXXFLAGS+=-I$(shell $(LLVM_CONFIG) --includedir) +CXXFLAGS+=-std=c++11 -fPIC -fvisibility-inlines-hidden +CXXFLAGS+=-Wall -Wextra -g -Wno-unused-parameter -Wno-unused-variable + +CPPFLAGS+=$(shell $(LLVM_CONFIG) --cppflags) +CPPFLAGS+=-I$(SRC_DIR) + + +PASS=VisitorSkel.so +PASS_OBJECTS=VisitorSkelModulePass.o + +default: prep $(PASS) + +prep: + $(QUIET)mkdir -p built + +%.o : $(SRC_DIR)/%.cpp + @echo Compiling $*.cpp + $(QUIET)$(CXX) -o built/$*.o -c $(CPPFLAGS) $(CXXFLAGS) $< + +$(PASS) : $(PASS_OBJECTS) + @echo Linking $@ + $(QUIET)$(CXX) -o built/$@ $(LDFLAGS) $(CXXFLAGS) built/*.o + +clean: + $(QUIET)rm -rf built + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/visitorskel/README.md b/Security Research and Development with LLVM - Andrew Reiter/code/visitorskel/README.md new file mode 100644 index 0000000..b67fba3 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/visitorskel/README.md @@ -0,0 +1,22 @@ + +# VisitorSkel + +This is a module pass that runs an instruction visitor +on each function it encounters in the given compilation +unit. + +## Build + +Check the makefile to be sure the LLVM version and llvm-config +paths are ok. Then just make. This will produce build/VisitorSkel.so. + +## Run + +``` +$ clang -emit-llvm -o file.bc -c file.c +$ opt-X.Y -load built/VisitorSkel.so -vskel < file.bc +... +$ opt-X.Y -load built/VisitorSkel.so -vskel -fn-to-visit someFuncName < file.bc +... +``` + diff --git a/Security Research and Development with LLVM - Andrew Reiter/code/visitorskel/src/VisitorSkelModulePass.cpp b/Security Research and Development with LLVM - Andrew Reiter/code/visitorskel/src/VisitorSkelModulePass.cpp new file mode 100644 index 0000000..09ec66c --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/code/visitorskel/src/VisitorSkelModulePass.cpp @@ -0,0 +1,145 @@ +/* + * Module pass that makes use of an InstVisitor but + * does nothing but dump values. + */ + +#include "llvm/IR/Module.h" +#include "llvm/IR/InstVisitor.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; + +cl::opt FunctionToVisit("fn-to-visit", cl::init("")); + +struct VisitorSkelModulePass : public ModulePass { + static char ID; + + VisitorSkelModulePass() : ModulePass(ID) {} + + /* + * The point of this pass is to demonstrate how easily we can find a specific instruction type, rather + * than looping through each instruction... + */ + virtual bool + runOnModule(Module &M) + { + if (FunctionToVisit != "") { + Function *f = M.getFunction(FunctionToVisit); + if (f == NULL || f->isDeclaration()) { + errs() << "Unable to find the function you specified.\n"; + return false; + } + errs() << "Visiting function: " << f->getName() << "\n"; + SkelInstVisitor v; + v.visit(*f); + return false; + } + for (auto &f : M) { + SkelInstVisitor v; + if (f.isDeclaration()) { + errs() << "Skipping function declaration\n"; + continue; + } + if (f.hasName()) { + errs() << "\nVisiting function: " << f.getName() << "\n"; + } else { + errs() << "\nVisiting unnamed function:\n"; + } + // You can call on a module, a function, or a basicblock.... + // depends on what you need. + v.visit(f); + errs() << "\n"; + } + return false; + } + + /* See llvm/IR/InstVisitor.h for full set... */ + struct SkelInstVisitor : public InstVisitor { + void + visitReturnInst(ReturnInst &I) { + errs() << "X return instruction\n "; + I.dump(); + } + void visitBranchInst(BranchInst &I) { + errs() << "X branch instruction\n "; + I.dump(); + } + void visitSwitchInst(SwitchInst &I) { + errs() << "X switch instruction\n "; + I.dump(); + } + void visitIndirectBrInst(IndirectBrInst &I) { + errs() << "X indirect branch instruction\n "; + I.dump(); + } + void visitCallInst(CallInst &I) { + errs() << "X call instruction\n "; + I.dump(); + } + void visitInvokeInst(InvokeInst &I) { + errs() << "X invoke instruction\n "; + I.dump(); + } + void visitCallSite(CallSite &I) { + errs() << "X call site instruction\n "; + } + + void visitBinaryOperator(BinaryOperator &I) { + errs() << "X binary instruction\n "; + I.dump(); + } + void visitCmpInst(CmpInst &I) { + errs() << "X compare instruction\n "; + I.dump(); + } + void visitBitCastInst(BitCastInst &I) { + errs() << "X bit cast instruction\n "; + I.dump(); + } + void visitICmpInst(ICmpInst &I) { + errs() << "X int compare instruction\n "; + I.dump(); + } + void visitAllocaInst(AllocaInst &I) { + errs() << "X alloca instruction\n "; + I.dump(); + } + void visitLoadInst(LoadInst &I) { + errs() << "X load instruction\n "; + I.dump(); + } + void visitStoreInst(StoreInst &I) { + errs() << "X store instruction\n "; + I.dump(); + } + void visitGetElementPtrInst(GetElementPtrInst &I){ + errs() << "X get element pointer instruction\n "; + I.dump(); + } + void visitPHINode(PHINode &I) { + errs() << "X PHI node instruction\n "; + I.dump(); + } + void visitTruncInst(TruncInst &I) { + errs() << "X truncate instruction\n "; + I.dump(); + } + void visitZExtInst(ZExtInst &I) { + errs() << "X zero extend instruction\n "; + I.dump(); + } + void visitSExtInst(SExtInst &I) { + errs() << "X signed exstend instruction\n "; + I.dump(); + } + void visitUnaryInstruction(UnaryInstruction &I) { + errs() << "X unary instruction\n "; + I.dump(); + } + }; +}; + +char VisitorSkelModulePass::ID = 0; +static RegisterPass XX("vskel", + "Skeleton code for a module pass that visits function instructions"); diff --git a/Security Research and Development with LLVM - Andrew Reiter/possible_projects.txt b/Security Research and Development with LLVM - Andrew Reiter/possible_projects.txt new file mode 100644 index 0000000..f54199a --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/possible_projects.txt @@ -0,0 +1,28 @@ + +There are many possible projects, but if you are looking for some +ideas to get you going, here are some. Note, you may need to look +at the slide deck or the projects.md file for some idea of what is +being said. + + +- Revive foreign-inference project to newer LLVM. Add support for LibFuzzer + +- Passes that look at slices or pruning or other for improvements in fuzzing + +- Use SAW on open source projects to flesh out things + +- Create a tool that analyzes code meant to use Divine or Seahorn for the +purposes of cataloging or policy validation + +- Build on Comminute to just be more realistic of a tool + +- Build on IntFlip + +- Build on npassert to determine asymptotic behaviors of code (think ASAP +from EPFL) + +- Snapshotting kernel regions for replay + +There are more, will add as i recall them. + + diff --git a/Security Research and Development with LLVM - Andrew Reiter/projects.md b/Security Research and Development with LLVM - Andrew Reiter/projects.md new file mode 100644 index 0000000..c109639 --- /dev/null +++ b/Security Research and Development with LLVM - Andrew Reiter/projects.md @@ -0,0 +1,301 @@ +# Security Related LLVM Projects + +Some entries are on the cusp of security and non-security related. Please +submit a pull request (or a friendly email) to add or remove projects. I +highly doubt it is a complete list, so always welcoming additions and/or +corrections. Further, I had thought to break out papers into it's own +section, but decided against it for reasons related to sleep. And even +further... There are some things I just wanted in here for informational +reasons; i.e. they may not be projects. :camel: + +## Projects + +### AddressSanitizer (ASan) +> Memory error detector for C/C++ finding UAF, buffer overflow, +> UAR, etc + +[GitHub](https://github.com/google/sanitizers/wiki/AddressSanitizer) +Note the code in lib/Transform/Instrumentation. + +[``AddressSanitizer: A Fast Address Sanity Checker''](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/37752.pdf) + +### American Fuzzy Lop (AFL) +> a security-oriented fuzzer that employs a novel type of compile-time +> instrumentation and genetic algorithms to automatically discover +> clean, interesting test cases that trigger new internal states in the +> targeted binary + +http://lcamtuf.coredump.cx/afl + +### Andersen's Analysis +[``Program Analysis and Specialization for the C Programming Language''](http://www.cs.cornell.edu/courses/cs711/2005fa/papers/andersen-thesis94.pdf) + +[Standalone LLVM impl](https://github.com/grievejia/andersen) + +### ASAP (EPFL) +> Analyze runtime checks to balance those that are needed and those that are not + +http://dslab.epfl.ch/proj/asap/ + +### Causal, Adaptive, Distributed, and Efficient Tracing System (CADETS) +> address flaws in current audit and information-flow systems through +> fundamental improvements in dynamic instrumentation, scalable +> distributed tracing, and programming-language support. + +http://www.cl.cam.ac.uk/research/security/cadets/ + +### cclyzer +> A tool for analyzing LLVM bitcode using Datalog. + +[GitHub](https://github.com/plast-lab/cclyzer) + +### cspgen (Draper) +> Map IR to models in Communicating Sequential Processes (CSP) process calculus. + +[GitHub](https://github.com/draperlaboratory/cspgen) + +### DangSan (VUSec) +> Dangling pointer detection + +[GitHub](https://github.com/vusec/dangsan) + +[Paper](http://www.cs.vu.nl/~giuffrida/papers/dangsan_eurosys17.pdf) + +### DataFlowSanitizer +> Generalized data flow API + +http://clang.llvm.org/docs/DataFlowSanitizerDesign.html + +### Divine +> Explicit-state model checker + +https://divine.fi.muni.cz + +[Thesis](https://is.muni.cz/th/373979/fi_m/thesis.pdf) + +### DynamicTools +> This project consists of several useful tool for dealing with LLVM +> IR runtime behaviors. Currently it consists of two parts, +> a custom-written LLVM IR interpreter, and an LLVM IR fuzzer (abandoned). + +[GitHub](https://github.com/grievejia/LLVMDynamicTools) + +### fdc +> An optimizing decompiler (for reversing) + +http://zneak.github.io/fcd/ + +[GitHub](https://github.com/zneak/fcd) + +### FindFlows +https://llvm.org/svn/llvm-project/giri/trunk/lib/Static/FindFlows.cpp + +### Foreign Inference +> Auto-generate wrappers for C code for Python etc. + +[GitHub](https://github.com/travitch/foreign-inference) +Out of date, someone should revive and build LibFuzzer wrappers + +### Fracture (Draper) +> Arch independent decompiler to LLVM IR (ver 3.6) + +[GitHub](https://github.com/draperlaboratory/fracture) + + +### Gist Static Analyzer (EPFL) +> Failure-sketching to help determine reasons for faults + +http://dslab.epfl.ch/proj/gist/ + +[Paper](http://dslab.epfl.ch/pubs/gist.pdf) + +### Trail of Bits CGC +[``How we fared in the Cyber Grand Challenge''](https://blog.trailofbits.com/2015/07/15/how-we-fared-in-the-cyber-grand-challenge/) + +### Infer (Facebook) +> Compile time static analyzer + +http://fbinfer.com/ + +[GitHub](https://github.com/facebook/infer) + +[Infer Clang Plugin](https://github.com/facebook/facebook-clang-plugins/tree/ee26293dd046acc5c2dd862d3201aa9f7dace96a) + +### Kryptonite obfuscator +[GitHub](https://github.com/0vercl0k/stuffz/blob/master/llvm-funz/kryptonite/llvm-functionpass-kryptonite-obfuscater.cpp) + +### KULFI (Utah) +> Instruction level fault injector + +[GitHub](https://github.com/soarlab/KULFI) + +http://formalverification.cs.utah.edu/fmr/#kulfi + +### IKOS (NASA) +> a C++ library designed to facilitate the development of sound static analyzers based on Abstract Interpretation + +https://ti.arc.nasa.gov/opensource/ikos/ + +### lafindel's transforms +> Splitting certain compares to improve fuzzing + +[``Circumventing Fuzzing Roadblocks with Compiler Transformations''](https://lafintel.wordpress.com/2016/08/15/circumventing-fuzzing-roadblocks-with-compiler-transformations/) + +### LeakSanitizer +> Memory leak detection + +[GitHub](https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer) + +### LibFuzzer +> Evolutionary, in-process guided fuzzing library + +http://llvm.org/docs/LibFuzzer.html + +[GitHub](https://github.com/llvm-mirror/llvm/tree/master/lib/Fuzzer) + +[LibFuzzer Tutorial](https://github.com/google/fuzzer-test-suite/blob/master/tutorial/libFuzzerTutorial.md) + +### llmc +[``Model checking LLVM IR using LTSmin''](http://fmt.cs.utwente.nl/files/sprojects/190.pdf) + +### llStar +> Pre/post condition intra-procedural verifier + +https://bitbucket.org/jvillard/llstar/wiki/Home + +### Mc Sema (ToB) +> Lift MC to IR for retargeting, patching, recompilation, symbolic exec + +[Github](https://github.com/trailofbits/mcsema) + +### MemorySanitizer +> Detect pointer misalignment etc + +[GitHub](https://github.com/google/sanitizers/wiki/MemorySanitizer) and see source in lib/Transform/Instrumentation + +### Obfuscator-LLVM +[GitHub](https://github.com/obfuscator-llvm/obfuscator) + +Note: https://github.com/obfuscator-llvm/obfuscator/tree/llvm-3.6.1/lib/Transforms/Obfuscation + +### Passes from QuarksLab +[GitHub](https://github.com/quarkslab/llvm-passes/tree/master/llvm-passes) + +[``Turning regular code into atrocities''](http://blog.quarkslab.com/turning-regular-code-into-atrocities-with-llvm.html) + +### Path Analysis for invariant Generation by Abstract Interpretation (PAGAI) (VERIMAG) +http://pagai.forge.imag.fr/ + +Also check out *screen* from trail of bits which makes use of PAGAI: https://github.com/trailofbits/screen + +### pmGen +> Translate IR to Promela for verification + +[GitHub](https://github.com/roselone/pmGen) + +### PRESAGE (Utah) +> protecting structured address computations against soft errors + +http://formalverification.cs.utah.edu/fmr/#presage + +[Git]https://utahfmr.github.io/PRESAGE/ + +[Paper](https://arxiv.org/abs/1606.08948) +Basically, it attempts to reorganize GetElementPtr's to best handle alpha particle hits. + +### Pointer analysis with tunable precision (TPA) +[GitHub](https://github.com/grievejia/tpa) + +### Remill (ToB) +> Lift MC instructions to IR + +[GitHub](https://github.com/trailofbits/remill) + +### Return-less code +> Transform IR to have no return statements.. attempt to avoid ROP + +[Paper](http://www4.ncsu.edu/~mcgrace/EUROSYS10.pdf) + +### Rev.ng +> Lift MC to IR by using QEMU + +https://rev.ng/ + +[Rev.ng LLVM developer mtg 2016](http://llvm.org/devmtg/2016-11/Slides/DiFederico-rev.ng.pdf) + +### s2e (EPFL) +[GitHub](https://github.com/dslab-epfl/s2e) + +### SAFECode +http://safecode.cs.illinois.edu/ + +[``Memory Safety for Low-Level Software/Hardware Interactions''](http://llvm.org/pubs/2009-08-12-UsenixSecurity-SafeSVAOS.html) + +### SafeInit (VUSec) +> Detect uninitialized memory use errors + +[GitHub](https://github.com/vusec/safeinit) + +[Paper](https://www.vusec.net/download/?t=papers/safeinit_ndss17.pdf) + +### Seahorn +> Intraprocedural model checker + +[GitHub](https://github.com/seahorn/seahorn) + +See the links there to CRAB etc + +### Security-Oriented Analysis of Application Programs (SOAAP) (Cambridge) +http://www.cl.cam.ac.uk/research/security/ctsrd/soaap + +[GitHub](https://github.com/CTSRD-SOAAP) + +### Sloopy +http://forsyte.at/people/pani/sloopy/ + +### Smack +[GitHub](https://github.com/smackers/smack) + +http://soarlab.org/2014/05/smack-decoupling-source-language-details-from-verifier-implementations/ + +### Software Analysis Workbench (SAW) (Galois Inc) +> Formal verification via equivelancy checks + +http://saw.galois.com/ + +[GitHub SAW Script](https://github.com/GaloisInc/saw-script) + +[GitHub llvm-verifier](https://github.com/GaloisInc/llvm-verifier) + +### Static Value Flow (SVF) (UNSW) +> Pointer Analysis and Program Dependence Analysis for C and C++ Programs + +http://unsw-corg.github.io/SVF/ + +[GitHub](https://github.com/unsw-corg/SVF) + + +### Temporally Enhanced Security Logic Assertions (TESLA) (Cambridge) +http://www.cl.cam.ac.uk/research/security/ctsrd/tesla + +[GitHub](https://github.com/CTSRD-TESLA/) + +### TokenCap +> Find tokens/magics in code so as to quickly pass fuzzing blockers + +[GitHub](https://github.com/0vercl0k/stuffz/blob/master/llvm-funz/afl-llvm-tokencap-pass.so.cc) + +### Typesan (VUSec) +[GitHub](https://github.com/vusec/typesan) + +### Verified LLVM (VeLLVM) +> Model syntax and semantics of LLVM IR in Coq for proving things about code reasoning on IR + +http://www.cis.upenn.edu/~stevez/vellvm/ + +https://deepspec.org/main + +### Whole program LLVM +> Help linking multiple .bc files to one + +[GitHub](https://github.com/travitch/whole-program-llvm) diff --git a/Security Research and Development with LLVM - Andrew Reiter/slides/ExtraNonsense.pdf b/Security Research and Development with LLVM - Andrew Reiter/slides/ExtraNonsense.pdf new file mode 100644 index 0000000..3368f8c Binary files /dev/null and b/Security Research and Development with LLVM - Andrew Reiter/slides/ExtraNonsense.pdf differ diff --git a/Security Research and Development with LLVM - Andrew Reiter/slides/MainDeck.pdf b/Security Research and Development with LLVM - Andrew Reiter/slides/MainDeck.pdf new file mode 100644 index 0000000..55abe70 Binary files /dev/null and b/Security Research and Development with LLVM - Andrew Reiter/slides/MainDeck.pdf differ diff --git a/Security Research and Development with LLVM - Andrew Reiter/slides/SecurityRDprojectsLLVM.pdf b/Security Research and Development with LLVM - Andrew Reiter/slides/SecurityRDprojectsLLVM.pdf new file mode 100644 index 0000000..0d7ae81 Binary files /dev/null and b/Security Research and Development with LLVM - Andrew Reiter/slides/SecurityRDprojectsLLVM.pdf differ