Этот коммит содержится в:
Matt Suiche 2017-04-29 17:14:43 +04:00
родитель 0c9e8df91c
Коммит 9dd1b44a14
111 изменённых файлов: 0 добавлений и 9675 удалений

Просмотреть файл

@ -1 +0,0 @@
*~

Просмотреть файл

@ -1,18 +0,0 @@
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.

Просмотреть файл

@ -1,13 +0,0 @@
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

Просмотреть файл

@ -1,52 +0,0 @@
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

Просмотреть файл

@ -1,20 +0,0 @@
# 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
...
$
```

Просмотреть файл

@ -1,61 +0,0 @@
#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<CallInst>(I) || isa<InvokeInst>(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<BBSkel> XX("bbskel", "BasicBlock Pass Skeleton");

Просмотреть файл

@ -1,35 +0,0 @@
#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

Просмотреть файл

@ -1,28 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
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;
}

Просмотреть файл

@ -1,51 +0,0 @@
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

Просмотреть файл

@ -1,18 +0,0 @@
# 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
...
$
```

Просмотреть файл

@ -1,58 +0,0 @@
#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<CGSSkel> XX("cgsskel", "CallGraphSCC Pass Skeleton");

Просмотреть файл

@ -1,28 +0,0 @@
#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

Просмотреть файл

@ -1,28 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
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;
}

Просмотреть файл

@ -1,235 +0,0 @@
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

Просмотреть файл

@ -1,31 +0,0 @@
# 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...

Просмотреть файл

@ -1,4 +0,0 @@
{
"srandom" : 0,
"srand48" : 0
}

Просмотреть файл

@ -1,3 +0,0 @@
{
"close" : 0
}

Просмотреть файл

@ -1,4 +0,0 @@
{
"socket" : -1,
"open" : -1
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,3 +0,0 @@
{
"functions" : [ "strcpy" ]
}

Просмотреть файл

@ -1,3 +0,0 @@
{
"getaddrinfo" : 0
}

Просмотреть файл

@ -1,3 +0,0 @@
{
"getpass" : -1
}

Просмотреть файл

@ -1,194 +0,0 @@
/*
* 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 <string>
#include <iostream>
#include <fstream>
#include <json/config.h>
#include <json/value.h>
#include <json/reader.h>
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<std::string, std::pair<Function *, unsigned>> _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<CallInst>(&fInst) {
* } else if (InvokeInst *ii ....)
* instead...
*
*/
Instruction *fInst = &*iIt;
if (!isa<CallInst>(fInst) && !isa<InvokeInst>(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<Constant>(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<NaiveConstantArgCheck> XX("naive-con-arg-check", "Basic constant arg check");

Просмотреть файл

@ -1,46 +0,0 @@
#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<NaiveConstantArgCheckResult> _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

Просмотреть файл

@ -1,180 +0,0 @@
/*
* 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 <string>
using namespace llvm;
#include "StoreCollector.h"
#include "TargetCallSitesPass.h"
#include "NaiveFileDescLeak.h"
void
NaiveFileDescLeak::getAnalysisUsage(AnalysisUsage &AU) const
{
AU.addRequired<TargetCallSitesPass>();
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<TargetCallSitesPass>();
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<Argument>(closingVar)) {
printLikelyFP(snkSite, "Value is an Argument to parent function (unsupported)");
} else if (isa<GlobalVariable>(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<Argument>(v)) {
printLikelyFP(srcSite, "Value is an Argument to parent function (unsupported)");
} else if (isa<GlobalVariable>(v)) {
printLikelyFP(srcSite, "Value is a GlobalVariable (unsupported)");
} else {
printLeak(srcSite);
}
}
return false;
}
char NaiveFileDescLeak::ID = 0;
static RegisterPass<NaiveFileDescLeak> XX("naive-fd-leak", "Naive fd leak");

Просмотреть файл

@ -1,22 +0,0 @@
#ifndef __NAIVEFILEDESCLEAK_H
#define __NAIVEFILEDESCLEAK_H
struct NaiveFileDescLeak : public ModulePass {
public:
static char ID;
typedef std::pair<Function *, unsigned> FuncArg;
typedef std::map<std::string, FuncArg> 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

Просмотреть файл

@ -1,104 +0,0 @@
/*
* 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 <string>
using namespace llvm;
#include "TargetCallSitesPass.h"
#include "NaiveSensitiveDataLeak.h"
void
NaiveSensitiveDataLeak::getAnalysisUsage(AnalysisUsage &AU) const
{
AU.addRequired<TargetCallSitesPass>();
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<TargetCallSitesPass>();
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<CallInst>(leakData) || isa<InvokeInst>(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<NaiveSensitiveDataLeak> XX("naive-sensitive-leak",
"Naive sensitive data leak");

Просмотреть файл

@ -1,19 +0,0 @@
#ifndef __NAIVESENSITIVEDATALEAK_H
#define __NAIVESENSITIVEDATALEAK_H
struct NaiveSensitiveDataLeak : public ModulePass {
static char ID;
typedef std::pair<Function *, unsigned> FuncArg;
typedef std::map<std::string, FuncArg> 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

Просмотреть файл

@ -1,155 +0,0 @@
/*
* 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 <string>
using namespace llvm;
#include "TargetCallSitesPass.h"
#include "NaiveSensitiveDataLeak.h"
#include "StoreCollector.h"
void
NaiveSensitiveDataLeak::getAnalysisUsage(AnalysisUsage &AU) const
{
AU.addRequired<TargetCallSitesPass>();
AU.preservesCFG();
}
bool
NaiveSensitiveDataLeak::runOnModule(Module &M)
{
errs() << "Running naive sensitive data leak pass\n";
TargetCallSitesPass &p = getAnalysis<TargetCallSitesPass>();
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<CallInst>(leakData) || isa<InvokeInst>(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<Constant>(leakData)) {
break;
}
if (isa<AllocaInst>(leakData)) {
break;
}
if (CastInst *ci = dyn_cast<CastInst>(leakData)) {
User *cu = cast<User>(ci);
leakData = cu->getOperand(0);
continue;
}
if (LoadInst *li = dyn_cast<LoadInst>(leakData)) {
Value *memLoc = li->getPointerOperand();
leakData = store->find(memLoc);
assert(leakData != NULL && "memLoc not in storeCollect");
continue;
}
if (GetElementPtrInst *gp =
dyn_cast<GetElementPtrInst>(leakData)) {
leakData = gp->getPointerOperand();
continue;
}
if (isa<Argument>(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<NaiveSensitiveDataLeak> XX("naive-sensitive-leak",
"Naive sensitive data leak");

Просмотреть файл

@ -1,155 +0,0 @@
/*
*
* 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 <map>
#include <string>
#include <iostream>
#include <fstream>
#include <json/config.h>
#include <json/value.h>
#include <json/reader.h>
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<CallGraphWrapperPass>();
}
bool
PotentiallyDangerousScan::runOnModule(Module &M)
{
Json::Value fnDict;
std::ifstream cfgFileStream;
std::vector<Function *> 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<CallGraphWrapperPass>();
/* store results in pairs of caller and callee */
typedef std::pair<Function *, Function *> PDRes;
std::vector<PDRes> 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<Function *>(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<WeakVH, CallGraphNode *> 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<PotentiallyDangerousScan> XX("pot-danger", "Potentially Dangerous Call (CWE 676)");

Просмотреть файл

@ -1,19 +0,0 @@
#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

Просмотреть файл

@ -1,97 +0,0 @@
/*
*
* 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 <map>
#include <string>
#include <iostream>
#include <fstream>
#include <json/config.h>
#include <json/value.h>
#include <json/reader.h>
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<CallInst>(in) || isa<InvokeInst>(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<PotentiallyDangerousScanFunctionPass> XX("pot-danger-function-pas", "Potentially Dangerous Call (CWE 676) func pass");

Просмотреть файл

@ -1,25 +0,0 @@
#ifndef __POTENTIALLYDANGEROUSSCANFUNCTIONPASS_H
#define __POTENTIALLYDANGEROUSSCANFUNCTIONPASS_H
struct PotentiallyDangerousScanFunctionPass : public FunctionPass {
private:
std::string _cfgFilePath;
std::vector<Function *> 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

Просмотреть файл

@ -1,76 +0,0 @@
/*
* 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 <map>
#include <string>
#include <iostream>
#include <fstream>
#include <json/config.h>
#include <json/value.h>
#include <json/reader.h>
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<CallInst>(u) || isa<InvokeInst>(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<PotentiallyDangerousScanUserMethod> XX("pot-danger-user-method", "Potentially Dangerous Call (CWE 676) done with User list");

Просмотреть файл

@ -1,19 +0,0 @@
#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

Просмотреть файл

@ -1,38 +0,0 @@
/*
* 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 <iostream>
#include <map>
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<StoreInst>(in)) {
continue;
}
StoreInst *s = cast<StoreInst>(in);
Value *storedVal = s->getValueOperand();
Value *storedLoc = s->getPointerOperand();
storeMap[storedLoc] = storedVal;
continue;
}
}

Просмотреть файл

@ -1,26 +0,0 @@
#ifndef __STORECOLLECTOR_H
#define __STORECOLLECTOR_H
class StoreCollector {
// key is pointer and value is the stored value
std::map<Value *, Value *> 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

Просмотреть файл

@ -1,116 +0,0 @@
/*
* 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 <string>
#include <iostream>
#include <fstream>
#include <json/config.h>
#include <json/value.h>
#include <json/reader.h>
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<CallInst>(targUser) && !isa<InvokeInst>(targUser)) {
continue;
}
Instruction *targInst = cast<Instruction>(targUser);
std::unique_ptr<TargetCallSite> 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<TargetCallSitesPass> XX("target-call-sites", "");

Просмотреть файл

@ -1,102 +0,0 @@
#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<std::unique_ptr<TargetCallSite>> 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<TargetCallType, std::string> targetConfigMap;
std::map<TargetCallType, TargetVector> targetCallMap;
};
#endif

Просмотреть файл

@ -1,211 +0,0 @@
/*
* 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 <iostream>
#include <fstream>
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 <command> <input.bc> <output.bc>
*
* commands:
* -choose-phi-value <int> :: 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<std::string> InputBitcodeFile(cl::Positional, cl::desc("<input.bc>"),
cl::Required);
cl::opt<std::string> OutputBitcodeFile(cl::Positional, cl::desc("<output.bc>"),
cl::Required);
cl::opt<int> ChoosePhiValuePass("choose-phi-value",
cl::desc("Choose value to use from PhiNode (defaults to first)"),
cl::init(-1));
cl::opt<bool> NaiveSDL("naive-sensitive-data-leak",
cl::desc("Perform Naive Sensitive Data Leak Analysis"), cl::init(false));
cl::opt<bool> NaiveCAC("naive-constant-arg",
cl::desc("Perform Naive Constant Argument Check"), cl::init(false));
cl::opt<bool> NaiveFDL("naive-fd-leak",
cl::desc("Perform Naive File Desc Leak check"), cl::init(false));
cl::opt<bool> PotentiallyDangerous("dangerous-function",
cl::desc("Silly CWE 676"), cl::init(false));
cl::opt<bool> PotentiallyDangerousUserMethod("dangerous-function-user-method",
cl::desc("Silly CWE 676 using User list"), cl::init(false));
cl::opt<bool> 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<Module> irModule;
ModulePass *modPass;
SMDiagnostic err;
raw_fd_ostream *outputStream;
cl::ParseCommandLineOptions(argc, argv);
std::cout << "<C> Reading input bitcode file: " << InputBitcodeFile << "\n";
irModule = parseIRFile(InputBitcodeFile, err,
*unwrap(LLVMGetGlobalContext()));
if (irModule == nullptr) {
std::cout << "<C> 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 << "<C> 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 << "<C> Adding mem2reg pass.\n";
passManager.add(createPromoteMemoryToRegisterPass());
std::cout << "<C> 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 << "<C> Adding phi value selector pass\n";
std::cout << "<C> 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 << "<C> 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 << "<C> 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 << "<C> Adding naive constant argument pass.\n";
NaiveConstantArgCheck *nca = new NaiveConstantArgCheck();
nca->setConfigFilePath("conf/constantarg.cfg");
passManager.add(nca);
} else if (PotentiallyDangerous) {
std::cout << "<C> Adding call graph pass\n";
passManager.add(new CallGraphWrapperPass());
std::cout << "<C> Adding dangerous fn scan pass.\n";
PotentiallyDangerousScan *p = new PotentiallyDangerousScan();
p->setConfigFilePath("conf/pdfunctions.cfg");
passManager.add(p);
} else if (PotentiallyDangerousUserMethod) {
std::cout << "<C> 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 << "<C> 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 << "<C> 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 << "<C> Running passes\n";
passManager.run(*irModule.get());
outputStream->close();
std::cout << "<C> Finished...\n";
return 0;
}

Просмотреть файл

@ -1,129 +0,0 @@
/*
* 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<std::pair<PHINode *, Value *>> replaceList;
for (auto ii = inst_begin(f); ii != inst_end(f); ++ii) {
Instruction *in = &*ii;
if (PHINode *pn = dyn_cast<PHINode>(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<Instruction>(d) == true);
Instruction *vi = cast<Instruction>(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<PHINode>(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<Instruction>(u)) {
if (BranchInst *bi = dyn_cast<BranchInst>(i)) {
if (bi->getNumOperands() == 1) {
return;
}
Value *tb = bi->getOperand(1);
Value *fb = bi->getOperand(2);
if (tb == cast<Value>(bb)) {
bi->setOperand(1, fb);
} else if (fb == cast<Value>(bb)) {
bi->setOperand(2, tb);
}
}
}
}
}
char ChoosePhiValue::ID = 0;
static RegisterPass<ChoosePhiValue> XX("choose-phi-value",
"Choose Phi value to use");

Просмотреть файл

@ -1,23 +0,0 @@
#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

Просмотреть файл

@ -1,70 +0,0 @@
/*
* 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 <iostream>
#include <fstream>
#include <sstream>
#include <string>
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<FunctionExternalizer> XX("fn-extern",
"Function externalizer");

Просмотреть файл

@ -1,16 +0,0 @@
#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

Просмотреть файл

@ -1,13 +0,0 @@
#include <stdio.h>
int
FE001_foo()
{
return 0;
}
int
main(int argc, char **argv)
{
return 1;
}

Просмотреть файл

@ -1,26 +0,0 @@
/*
* NCA001
*
* NaiveConstantArg 001
*
*/
#include <stdio.h>
#include <stdlib.h>
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;
}

Просмотреть файл

@ -1,35 +0,0 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
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;
}

Просмотреть файл

@ -1,27 +0,0 @@
/*
* NFDL001
*
* Naive File Descriptor Leak 001
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
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;
}

Просмотреть файл

@ -1,38 +0,0 @@
/*
* NFDL002
*
* Naive File Descriptor Leak 002
* .. well this does not leak.
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
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;
}

Просмотреть файл

@ -1,40 +0,0 @@
/*
* NFDL003
*
* Naive File Descriptor Leak 003
*
* copies fd to another local variable and closes that... so no leak
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
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;
}

Просмотреть файл

@ -1,43 +0,0 @@
/*
* NFDL004
*
* Naive File Descriptor Leak 004
*
* One leaks one does not
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
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;
}

Просмотреть файл

@ -1,37 +0,0 @@
/*
* NFDL005
*
* Naive File Descriptor Leak 005
*
* global variable that ``seems'' to leak.
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
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;
}

Просмотреть файл

@ -1,44 +0,0 @@
/*
* NFDL006
*
* Naive File Descriptor Leak 005
*
* global variable that does not leak, but naive analysis won't catch.
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
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;
}

Просмотреть файл

@ -1,38 +0,0 @@
/*
* NFDL005
*
* Naive File Descriptor Leak 005
*
* opens and closes a global var fd
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
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;
}

Просмотреть файл

@ -1,36 +0,0 @@
/*
* NSDL001
*
* Naive Sensitive Data Leak 001
*
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
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;
}

Просмотреть файл

@ -1,37 +0,0 @@
/*
* NSDL002
*
* Naive Sensitive Data Leak 002
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
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;
}

Просмотреть файл

@ -1,37 +0,0 @@
/*
* NSDL003
*
* Naive Sensitive Data Leak 003
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
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;
}

Просмотреть файл

@ -1,44 +0,0 @@
/*
* PD001
*
* Potentially Dangerous 001
*
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
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;
}

Двоичный файл не отображается.

Просмотреть файл

@ -1,46 +0,0 @@
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

Просмотреть файл

@ -1,19 +0,0 @@
# 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
...
$
```

Просмотреть файл

@ -1,56 +0,0 @@
#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<FPSkel> XX("fpskel", "Function Pass Skeleton");

Просмотреть файл

@ -1,25 +0,0 @@
#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

Просмотреть файл

@ -1,134 +0,0 @@
#
# 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

Просмотреть файл

@ -1,138 +0,0 @@
# 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

Просмотреть файл

@ -1,49 +0,0 @@
{
"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
}
}
}

Просмотреть файл

@ -1,49 +0,0 @@
{
"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
}
}
}

Просмотреть файл

@ -1,14 +0,0 @@
#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

Просмотреть файл

@ -1,126 +0,0 @@
#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<Function>(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<Function>(lookupRand);
injectInt64(M, fnRand);
injectInt32(M, fnRand);
injectInt16(M, fnRand);
injectInt8(M, fnRand);
}

Просмотреть файл

@ -1,11 +0,0 @@
#ifndef __BITFLIPRANDOMIZER_H
#define __BITFLIPRANDOMIZER_H
#include "BaseRandomizer.h"
class BitFlipRandomizer : BaseRandomizer {
public:
static void inject(llvm::Module& M);
};
#endif // !__BITFLIPRANDOMIZER_H

Просмотреть файл

@ -1,57 +0,0 @@
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <json/config.h>
#include <json/value.h>
#include <json/reader.h>
#include "FlipConfig.h"
std::vector<std::string> 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());
}
}
}

Просмотреть файл

@ -1,29 +0,0 @@
#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<std::string, FunctionConfig> 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<std::string> skip_replace_functions;
#endif // !__FLIPCONFIG_H

Просмотреть файл

@ -1,23 +0,0 @@
#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<InjectRandomizers> XX("inject-randomizers", "Inject randomizer functions");

Просмотреть файл

@ -1,134 +0,0 @@
#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 <json/value.h>
#include "FlipConfig.h"
#include <iostream>
#include <map>
using namespace llvm;
extern cl::opt<std::string> 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<CallInst>(&*I) || isa<InvokeInst>(&*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<IntReplacerIterate> XX("replace-ints-iterate", "Replace int function args with randomizer-integers using instruction iteration");

Просмотреть файл

@ -1,184 +0,0 @@
/*
* 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 <json/value.h>
#include "FlipConfig.h"
#include <iostream>
#include <map>
using namespace llvm;
cl::opt<std::string> ReplaceConfigFileName("repcfg", cl::desc("<replacer cfg>"));
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<CodeModificationLocation> 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<IntegerType>(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<CheckCallInsts> {
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<IntReplacerVisitor> XX("replace-ints-visitor", "Replace int function args with randomizer-integers using instruction visitor");

Просмотреть файл

@ -1,113 +0,0 @@
/*
* 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<CheckCallInsts> {
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<ConstantInt>(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<LiftConstantIntPass> XX("lift-constant-int-args", "Lifts constant int fn args to a local variable");

Просмотреть файл

@ -1,113 +0,0 @@
#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<Function>(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<Function>(lookupRand);
injectInt64(M, fnRand);
injectInt32(M, fnRand);
injectInt16(M, fnRand);
injectInt8(M, fnRand);
}

Просмотреть файл

@ -1,10 +0,0 @@
#ifndef __REPLACERANDOMIZER_H
#define __REPLACERANDOMIZER_H
#include "BaseRandomizer.h"
class ReplaceRandomizer : BaseRandomizer {
public:
static void inject(llvm::Module& M);
};
#endif // !__REPLACERANDOMIZER_H

Просмотреть файл

@ -1,53 +0,0 @@
#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<llvm::ConstantInt>(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<llvm::ConstantInt>(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<llvm::IntegerType>(t)) {
unsigned nBits = intType->getBitWidth();
switch (nBits) {
case 64:
case 32:
case 16:
case 8:
return true;
}
}
return false;
}
};
#endif // !__TYPEVALUESUPPORT_H

Просмотреть файл

@ -1,142 +0,0 @@
#include <stdio.h>
#include <sys/types.h>
#include <pthread.h>
#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;
}

Просмотреть файл

@ -1,183 +0,0 @@
#include <stdio.h>
#include <sys/types.h>
#include <pthread.h>
#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;
}

Двоичный файл не отображается.

Просмотреть файл

@ -1,51 +0,0 @@
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

Просмотреть файл

@ -1,18 +0,0 @@
# 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
...
$
```

Просмотреть файл

@ -1,47 +0,0 @@
#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<LPSkel> XX("lpskel", "Loop Pass Skeleton");

Просмотреть файл

@ -1,28 +0,0 @@
#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

Просмотреть файл

@ -1,13 +0,0 @@
#include <stdio.h>
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;
}

Просмотреть файл

@ -1,46 +0,0 @@
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

Просмотреть файл

@ -1,19 +0,0 @@
# 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
...
$
```

Просмотреть файл

@ -1,68 +0,0 @@
#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<CallInst>(u) || isa<InvokeInst>(u)) {
// It is, so let's use the common class CallSite
CallSite cs(dyn_cast<Instruction>(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<MPSkel> XX("mpskel", "Module Pass Skeleton");

Просмотреть файл

@ -1,25 +0,0 @@
#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

Просмотреть файл

@ -1,76 +0,0 @@
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

Просмотреть файл

@ -1,118 +0,0 @@
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 <random@plt>
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 <foo+40>
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 <random@plt>
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.

Просмотреть файл

@ -1,5 +0,0 @@
# Ignore lines with #
# index by 0
foo,0
foo3,1
foo3,0

Просмотреть файл

@ -1,251 +0,0 @@
#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 <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>
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<std::string> ReplaceConfigFileName("npa-target-config",
cl::desc("configuration file for np asserts"), cl::init(""));
cl::opt<bool> 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<Function>(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<PointerType>(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<PointerType>(typeNull) && "typeNull not PointerType");
PointerType *ptNull = cast<PointerType>(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<NullPtrAssertPass> XX("null-ptr-assert", "Inject null ptr checks");

Просмотреть файл

@ -1,19 +0,0 @@
#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

Просмотреть файл

@ -1,38 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
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;
}

Просмотреть файл

@ -1,25 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
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;
}

Просмотреть файл

@ -1,51 +0,0 @@
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

Просмотреть файл

@ -1,17 +0,0 @@
# 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
...
$
```

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше