From 6818849e9a49d8c39723f1eef3d8d40079540550 Mon Sep 17 00:00:00 2001 From: Jason Hiser <jdhiser@gmail.com> Date: Tue, 22 May 2018 14:33:22 +0000 Subject: [PATCH] moved p1 to irdb_transforms, changed libtransform to support the rewrite utility stuff that were being accessed from tools/transforms Former-commit-id: f76f1957149f27b1e0a804065cf95fee0b231f00 --- SConscript | 2 +- libtransform/include/Rewrite_Utility.hpp | 13 + libtransform/src/Rewrite_Utility.cpp | 111 + tools/SConscript | 1 - tools/absolutify/SConscript | 2 +- tools/c2e/SConscript | 2 +- tools/cgc_buffrecv/SConscript | 2 +- tools/cgc_hlx/SConscript | 2 +- tools/cgc_rigrandom/SConscript | 2 +- tools/cgclibc/SConscript | 2 +- tools/cinderella/SConscript | 2 +- tools/cookbook/SConscript | 2 +- tools/cover/SConscript | 2 +- tools/dump_map/SConscript | 2 +- tools/fix_canaries/SConscript | 2 +- tools/fix_rets/SConscript | 4 +- tools/hook_dynamic_call/SConscript | 2 +- tools/hook_start/SConscript | 4 +- tools/hook_start/hook_start.cpp | 1 + tools/inferfn/SConscript | 2 +- tools/meds2pdb/SConscript | 4 +- tools/memcover/SConscript | 2 +- tools/prince/SConscript | 2 +- tools/print_cfi_stats/SConscript | 2 +- tools/ret_shadow_stack/SConscript | 2 +- tools/safefn/SConscript | 2 +- tools/safefr/SConscript | 2 +- tools/selective_cfi/SConscript | 4 +- tools/selective_cfi/scfi_instr.cpp | 10 + tools/simple_cdi/SConscript | 2 +- tools/spasm/SConscript | 2 +- .../AnnotationBoundaryGenerator.cpp | 98 - .../AnnotationBoundaryGenerator.hpp | 40 - tools/transforms/DirectOffsetInference.cpp | 42 - tools/transforms/DirectOffsetInference.hpp | 39 - tools/transforms/EhUpdater.cpp | 192 - tools/transforms/EhUpdater.hpp | 33 - tools/transforms/General_Utility.cpp | 64 - tools/transforms/General_Utility.hpp | 28 - tools/transforms/Makefile.in | 51 - tools/transforms/OffsetInference.cpp | 1121 ------ tools/transforms/OffsetInference.hpp | 55 - tools/transforms/P1Inference.cpp | 43 - tools/transforms/P1Inference.hpp | 42 - tools/transforms/PNIrdbManager.cpp | 136 - tools/transforms/PNIrdbManager.hpp | 73 - tools/transforms/PNMain.cpp | 537 --- tools/transforms/PNRange.cpp | 90 - tools/transforms/PNRange.hpp | 47 - tools/transforms/PNRegularExpressions.cpp | 213 -- tools/transforms/PNRegularExpressions.hpp | 55 - tools/transforms/PNStackLayout.cpp | 757 ---- tools/transforms/PNStackLayout.hpp | 143 - tools/transforms/PNStackLayoutInference.hpp | 40 - tools/transforms/PNTransformDriver.cpp | 3237 ----------------- tools/transforms/PNTransformDriver.hpp | 201 - .../PrecedenceBoundaryGenerator.hpp | 35 - .../PrecedenceBoundaryInference.cpp | 210 -- .../PrecedenceBoundaryInference.hpp | 40 - tools/transforms/Range.cpp | 70 - tools/transforms/Range.hpp | 43 - tools/transforms/Rewrite_Utility.cpp | 452 --- tools/transforms/Rewrite_Utility.hpp | 72 - tools/transforms/SConscript | 51 - tools/transforms/SConstruct | 7 - tools/transforms/ScaledOffsetInference.cpp | 43 - tools/transforms/ScaledOffsetInference.hpp | 38 - tools/transforms/StackLayout.cpp | 253 -- tools/transforms/StackLayout.hpp | 77 - tools/transforms/canary.h | 12 - tools/transforms/globals.h | 141 - tools/transforms/integertransformdriver.cpp | 251 -- tools/transforms/nulltransform.cpp | 57 - tools/transforms/sample_meds_int.annot | 8 - tools/transforms/tests/test_buffer_overflow.c | 19 - .../transforms/tests/test_buffer_overflow.sh | 120 - tools/transforms/tests/test_spec.sh | 235 -- tools/transforms/transformutils.cpp | 51 - tools/transforms/transformutils.h | 29 - 79 files changed, 165 insertions(+), 9722 deletions(-) delete mode 100644 tools/transforms/AnnotationBoundaryGenerator.cpp delete mode 100644 tools/transforms/AnnotationBoundaryGenerator.hpp delete mode 100644 tools/transforms/DirectOffsetInference.cpp delete mode 100644 tools/transforms/DirectOffsetInference.hpp delete mode 100644 tools/transforms/EhUpdater.cpp delete mode 100644 tools/transforms/EhUpdater.hpp delete mode 100644 tools/transforms/General_Utility.cpp delete mode 100644 tools/transforms/General_Utility.hpp delete mode 100644 tools/transforms/Makefile.in delete mode 100644 tools/transforms/OffsetInference.cpp delete mode 100644 tools/transforms/OffsetInference.hpp delete mode 100644 tools/transforms/P1Inference.cpp delete mode 100644 tools/transforms/P1Inference.hpp delete mode 100644 tools/transforms/PNIrdbManager.cpp delete mode 100644 tools/transforms/PNIrdbManager.hpp delete mode 100644 tools/transforms/PNMain.cpp delete mode 100644 tools/transforms/PNRange.cpp delete mode 100644 tools/transforms/PNRange.hpp delete mode 100644 tools/transforms/PNRegularExpressions.cpp delete mode 100644 tools/transforms/PNRegularExpressions.hpp delete mode 100644 tools/transforms/PNStackLayout.cpp delete mode 100644 tools/transforms/PNStackLayout.hpp delete mode 100644 tools/transforms/PNStackLayoutInference.hpp delete mode 100644 tools/transforms/PNTransformDriver.cpp delete mode 100644 tools/transforms/PNTransformDriver.hpp delete mode 100644 tools/transforms/PrecedenceBoundaryGenerator.hpp delete mode 100644 tools/transforms/PrecedenceBoundaryInference.cpp delete mode 100644 tools/transforms/PrecedenceBoundaryInference.hpp delete mode 100644 tools/transforms/Range.cpp delete mode 100644 tools/transforms/Range.hpp delete mode 100644 tools/transforms/Rewrite_Utility.cpp delete mode 100644 tools/transforms/Rewrite_Utility.hpp delete mode 100644 tools/transforms/SConscript delete mode 100644 tools/transforms/SConstruct delete mode 100644 tools/transforms/ScaledOffsetInference.cpp delete mode 100644 tools/transforms/ScaledOffsetInference.hpp delete mode 100644 tools/transforms/StackLayout.cpp delete mode 100644 tools/transforms/StackLayout.hpp delete mode 100644 tools/transforms/canary.h delete mode 100644 tools/transforms/globals.h delete mode 100644 tools/transforms/integertransformdriver.cpp delete mode 100644 tools/transforms/nulltransform.cpp delete mode 100644 tools/transforms/sample_meds_int.annot delete mode 100644 tools/transforms/tests/test_buffer_overflow.c delete mode 100755 tools/transforms/tests/test_buffer_overflow.sh delete mode 100755 tools/transforms/tests/test_spec.sh delete mode 100644 tools/transforms/transformutils.cpp delete mode 100644 tools/transforms/transformutils.h diff --git a/SConscript b/SConscript index b0129e4f1..e903bf206 100644 --- a/SConscript +++ b/SConscript @@ -70,11 +70,11 @@ if "CYGWIN" in sysname: Export('env') +libtransform=SConscript("libtransform/SConscript", variant_dir='scons_build/libtransform') libEXEIO=SConscript("libEXEIO/SConscript", variant_dir='scons_build/libEXEIO') libbea=SConscript("beaengine/SConscript", variant_dir='scons_build/beaengine') libMEDSannotation=SConscript("libMEDSannotation/SConscript", variant_dir='scons_build/libMEDSannotation') libxform=SConscript("xform/SConscript", variant_dir='scons_build/libxform') -libtransform=SConscript("libtransform/SConscript", variant_dir='scons_build/libtransform') libIRDB=SConscript("libIRDB/SConscript", variant_dir='scons_build/libIRDB') libStructDiv=SConscript("libStructDiv/SConscript", variant_dir='scons_build/libStructDiv') libElfDep=SConscript("libElfDep/SConscript", variant_dir='scons_build/libElfDep') diff --git a/libtransform/include/Rewrite_Utility.hpp b/libtransform/include/Rewrite_Utility.hpp index 631bfdab2..4d61958a4 100644 --- a/libtransform/include/Rewrite_Utility.hpp +++ b/libtransform/include/Rewrite_Utility.hpp @@ -39,6 +39,19 @@ enum mitigation_policy //This duplicate is returned since the user already has a pointer to first. Instruction_t* insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target); Instruction_t* insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly); +Instruction_t* insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target); +Instruction_t* insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits); + +// insert new instructions after, diff types. +Instruction_t* insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target); +Instruction_t* insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly); +Instruction_t* insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target); +Instruction_t* insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits); + +// add new instructions of diff types. +Instruction_t* addNewDatabits(FileIR_t* firp, Instruction_t *p_instr, string p_bits); +Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, string p_asm); + //Does not insert into any variant, just copies data about the instruction itself, see the copyInstruction(src,dest) to see what is copied. Instruction_t* copyInstruction(Instruction_t* instr); diff --git a/libtransform/src/Rewrite_Utility.cpp b/libtransform/src/Rewrite_Utility.cpp index e60a84e55..3b31afcc1 100644 --- a/libtransform/src/Rewrite_Utility.cpp +++ b/libtransform/src/Rewrite_Utility.cpp @@ -35,6 +35,22 @@ map<Function_t*, set<AddressID_t*> > inserted_addr; //used to undo inserted addr void setExitCode(FileIR_t* virp, Instruction_t* exit_code); + + +void setInstructionDataBits(FileIR_t* virp, Instruction_t *p_instr, string p_dataBits, Instruction_t *p_fallThrough, Instruction_t *p_target) +{ + if (p_instr == NULL) return; + + p_instr->SetDataBits(p_dataBits); + p_instr->SetComment(p_instr->getDisassembly()); + p_instr->SetFallthrough(p_fallThrough); + p_instr->SetTarget(p_target); + + virp->GetAddresses().insert(p_instr->GetAddress()); + virp->GetInstructions().insert(p_instr); +} + + //For all insertBefore functions: //The "first" instruction will have its contents replaced and a duplicate of "first" will be in the follow of first. //This duplicate is returned since the user already has a pointer to first. @@ -64,6 +80,101 @@ Instruction_t* insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string return insertAssemblyBefore(virp,first,assembly,NULL); } + +Instruction_t* insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits) +{ + return insertDataBitsBefore(virp,first,dataBits,NULL); +} + +Instruction_t* insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target) +{ + Instruction_t* next = copyInstruction(virp,first); + + //In case the fallthrough is null, generate spri has to have a + //place to jump, which is determined by the original address. + //This code is not placed in copyInstruction since this is only needed + //when inserting before + next->SetOriginalAddressID(first->GetOriginalAddressID()); + //"Null" out the original address (it should be as if the instruction was not in the database). + first->SetOriginalAddressID(BaseObj_t::NOT_IN_DATABASE); + first->GetRelocations().clear(); + + setInstructionDataBits(virp,first,dataBits,next,target); + + return next; +} + +Instruction_t* insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target) +{ + Instruction_t *new_instr = allocateNewInstruction(virp,first); + setInstructionAssembly(virp,new_instr,assembly,first->GetFallthrough(), target); + first->SetFallthrough(new_instr); + return new_instr; +} + +Instruction_t* insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly) +{ + return insertAssemblyAfter(virp,first,assembly,NULL); + +} + +Instruction_t* insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target) +{ + Instruction_t *new_instr = allocateNewInstruction(virp,first); + setInstructionDataBits(virp,new_instr,dataBits,first->GetFallthrough(), target); + first->SetFallthrough(new_instr); + + return new_instr; +} + +Instruction_t* insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits) +{ + return insertDataBitsAfter(virp,first,dataBits,NULL); +} + +Instruction_t* addNewDatabits(FileIR_t* firp, Instruction_t *p_instr, string p_bits) +{ + Instruction_t* newinstr; + if (p_instr) + newinstr = allocateNewInstruction(firp,p_instr->GetAddress()->GetFileID(), p_instr->GetFunction()); + else + newinstr = allocateNewInstruction(firp,BaseObj_t::NOT_IN_DATABASE, NULL); + + newinstr->SetDataBits(p_bits); + + if (p_instr) + { + newinstr->SetFallthrough(p_instr->GetFallthrough()); + p_instr->SetFallthrough(newinstr); + } + + return newinstr; +} + +Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, string p_asm) +{ + Instruction_t* newinstr; + if (p_instr) + newinstr = allocateNewInstruction(firp,p_instr->GetAddress()->GetFileID(), p_instr->GetFunction()); + else + newinstr = allocateNewInstruction(firp,BaseObj_t::NOT_IN_DATABASE, NULL); + + firp->RegisterAssembly(newinstr, p_asm); + + if (p_instr) + { + newinstr->SetFallthrough(p_instr->GetFallthrough()); + p_instr->SetFallthrough(newinstr); + } + + return newinstr; +} + + + + + + //Does not insert into any variant Instruction_t* copyInstruction(Instruction_t* instr) { diff --git a/tools/SConscript b/tools/SConscript index 03f4a0199..0b5759771 100644 --- a/tools/SConscript +++ b/tools/SConscript @@ -5,7 +5,6 @@ Import('env') tools=[] dirs=''' - transforms cover fix_rets meds2pdb diff --git a/tools/absolutify/SConscript b/tools/absolutify/SConscript index e20543abe..a2d648e42 100644 --- a/tools/absolutify/SConscript +++ b/tools/absolutify/SConscript @@ -17,7 +17,7 @@ cpppath=''' # $SECURITY_TRANSFORMS_HOME/libtransform/include CPPFLAGS="--std=c++11" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ "IRDB-core IRDB-cfg IRDB-util pqxx rewrite BeaEngine_s_d transform MEDSannotation") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ "IRDB-core IRDB-cfg IRDB-util pqxx BeaEngine_s_d transform MEDSannotation") myenv=myenv.Clone(CPPPATH=Split(cpppath)) myenv.Append(CPPFLAGS=CPPFLAGS) diff --git a/tools/c2e/SConscript b/tools/c2e/SConscript index 9112ce874..1aba7c556 100644 --- a/tools/c2e/SConscript +++ b/tools/c2e/SConscript @@ -24,7 +24,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="c2e.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util rewrite ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) diff --git a/tools/cgc_buffrecv/SConscript b/tools/cgc_buffrecv/SConscript index ef5b4a068..2bd4decb2 100644 --- a/tools/cgc_buffrecv/SConscript +++ b/tools/cgc_buffrecv/SConscript @@ -21,7 +21,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="buffrecv.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-syscall IRDB-util transform rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-syscall IRDB-util transform MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/cgc_hlx/SConscript b/tools/cgc_hlx/SConscript index cbdf9abec..25e348e0e 100644 --- a/tools/cgc_hlx/SConscript +++ b/tools/cgc_hlx/SConscript @@ -19,7 +19,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="cgc_hlx.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/cgc_rigrandom/SConscript b/tools/cgc_rigrandom/SConscript index 42c86a841..0f3f9e16e 100644 --- a/tools/cgc_rigrandom/SConscript +++ b/tools/cgc_rigrandom/SConscript @@ -22,7 +22,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="rigrandom.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util rewrite ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) diff --git a/tools/cgclibc/SConscript b/tools/cgclibc/SConscript index 9f51204c3..af9fc6ccf 100644 --- a/tools/cgclibc/SConscript +++ b/tools/cgclibc/SConscript @@ -25,7 +25,7 @@ files3=Split("infer_syscall_wrappers.cpp")+cgclibc LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split(env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-syscall IRDB-util rewrite ") +LIBS=Split(env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-syscall IRDB-util ") pgm=myenv.Program("cgclibc.exe", files1, LIBPATH=LIBPATH, LIBS=LIBS) install1=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/cinderella/SConscript b/tools/cinderella/SConscript index 6ac61cc85..cbbf4d4ed 100644 --- a/tools/cinderella/SConscript +++ b/tools/cinderella/SConscript @@ -21,7 +21,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="cinderella_prep.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/cookbook/SConscript b/tools/cookbook/SConscript index 23f1d8ec7..7abb296f8 100644 --- a/tools/cookbook/SConscript +++ b/tools/cookbook/SConscript @@ -42,7 +42,7 @@ myenv.Append(CPPDEFINES=CPPDEFINES) cookbook_obj = myenv.Object(Dir('.').srcnode().abspath+"/x86_64_linux/cookbook.cpp") LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=cookbook_obj + Split("xform IRDB-core IRDB-cfg IRDB-util pqxx BeaEngine_s_d rewrite transform MEDSannotation " + env.subst('$BASE_IRDB_LIBS') ) +LIBS=cookbook_obj + Split("xform IRDB-core IRDB-cfg IRDB-util pqxx BeaEngine_s_d transform MEDSannotation " + env.subst('$BASE_IRDB_LIBS') ) for pgm in pgms.keys(): ppgms.append(myenv.Program(pgm, pgms[pgm], LIBPATH=LIBPATH, LIBS=LIBS)) diff --git a/tools/cover/SConscript b/tools/cover/SConscript index 1126bab03..99b76265f 100644 --- a/tools/cover/SConscript +++ b/tools/cover/SConscript @@ -18,7 +18,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="cover" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util rewrite ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) diff --git a/tools/dump_map/SConscript b/tools/dump_map/SConscript index f63bc33c5..7fd50e3ef 100644 --- a/tools/dump_map/SConscript +++ b/tools/dump_map/SConscript @@ -22,7 +22,7 @@ myenv.Append(CPPFLAGS="-std=c++11") pgm="dump_map.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) #install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/fix_canaries/SConscript b/tools/fix_canaries/SConscript index 95cf7a2ff..b678e79b8 100644 --- a/tools/fix_canaries/SConscript +++ b/tools/fix_canaries/SConscript @@ -17,7 +17,7 @@ cpppath=''' # $SECURITY_TRANSFORMS_HOME/libtransform/include CPPFLAGS="--std=c++11" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ "IRDB-core IRDB-cfg IRDB-util pqxx rewrite BeaEngine_s_d transform MEDSannotation") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ "IRDB-core IRDB-cfg IRDB-util pqxx BeaEngine_s_d transform MEDSannotation") myenv=myenv.Clone(CPPPATH=Split(cpppath)) myenv.Append(CPPFLAGS=CPPFLAGS) diff --git a/tools/fix_rets/SConscript b/tools/fix_rets/SConscript index ee122fcaf..038d7b8a8 100644 --- a/tools/fix_rets/SConscript +++ b/tools/fix_rets/SConscript @@ -10,7 +10,7 @@ cpppath=''' $SECURITY_TRANSFORMS_HOME/include $SECURITY_TRANSFORMS_HOME/libIRDB/include $SECURITY_TRANSFORMS_HOME/libMEDSannotation/include - $SECURITY_TRANSFORMS_HOME/tools/transforms + $SECURITY_TRANSFORMS_HOME/libtransform/include ''' @@ -20,7 +20,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="fix_rets.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) #install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/hook_dynamic_call/SConscript b/tools/hook_dynamic_call/SConscript index 62f2090ff..7427e1aed 100644 --- a/tools/hook_dynamic_call/SConscript +++ b/tools/hook_dynamic_call/SConscript @@ -17,7 +17,7 @@ cpppath=''' # $SECURITY_TRANSFORMS_HOME/libtransform/include CPPFLAGS="--std=c++11" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-core IRDB-cfg IRDB-util pqxx rewrite BeaEngine_s_d transform MEDSannotation") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-core IRDB-cfg IRDB-util pqxx BeaEngine_s_d transform MEDSannotation") myenv['debug'] = 1 if 'debug' in myenv and int(myenv['debug']) == 1: diff --git a/tools/hook_start/SConscript b/tools/hook_start/SConscript index ca54cb4ae..511a837c1 100644 --- a/tools/hook_start/SConscript +++ b/tools/hook_start/SConscript @@ -9,7 +9,7 @@ cpppath=''' $SECURITY_TRANSFORMS_HOME/include $SECURITY_TRANSFORMS_HOME/libIRDB/include $SECURITY_TRANSFORMS_HOME/libEXEIO/include - $SECURITY_TRANSFORMS_HOME/tools/transforms + $SECURITY_TRANSFORMS_HOME/libtransform/include $SECURITY_TRANSFORMS_HOME/xform $SECURITY_TRANSFORMS_HOME/libMEDSannotation/include ''' @@ -17,7 +17,7 @@ cpppath=''' # $SECURITY_TRANSFORMS_HOME/libtransform/include CPPFLAGS="--std=c++11" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-core IRDB-cfg IRDB-util pqxx rewrite BeaEngine_s_d transform MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-core IRDB-cfg IRDB-util pqxx BeaEngine_s_d transform MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) myenv.Append(CPPFLAGS=CPPFLAGS) diff --git a/tools/hook_start/hook_start.cpp b/tools/hook_start/hook_start.cpp index ee4ebfc4f..573dccbac 100644 --- a/tools/hook_start/hook_start.cpp +++ b/tools/hook_start/hook_start.cpp @@ -7,6 +7,7 @@ using namespace libTransform; using namespace ELFIO; using namespace libIRDB; +using namespace IRDBUtility; HookStart::HookStart(FileIR_t *p_variantIR) : Transform(NULL, p_variantIR, NULL), diff --git a/tools/inferfn/SConscript b/tools/inferfn/SConscript index a9d424917..0de687a24 100644 --- a/tools/inferfn/SConscript +++ b/tools/inferfn/SConscript @@ -19,7 +19,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="inferfn.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/meds2pdb/SConscript b/tools/meds2pdb/SConscript index 5ae7770fc..5869a8215 100644 --- a/tools/meds2pdb/SConscript +++ b/tools/meds2pdb/SConscript @@ -12,7 +12,7 @@ cpppath=''' $SECURITY_TRANSFORMS_HOME/libEXEIO/include $SECURITY_TRANSFORMS_HOME/libIRDB/include $SECURITY_TRANSFORMS_HOME/libMEDSannotation/include - $SECURITY_TRANSFORMS_HOME/tools/transforms + $SECURITY_TRANSFORMS_HOME/libtransform/include ''' files=Glob( Dir('.').srcnode().abspath+"/*.cpp") @@ -22,7 +22,7 @@ pgm="meds2pdb" myenv.Append(CXXFLAGS = " -std=c++11 ") LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split(" IRDB-cfg IRDB-util xform rewrite MEDSannotation "+env.subst('$BASE_IRDB_LIBS')) +LIBS=Split(" IRDB-cfg IRDB-util xform transform MEDSannotation "+env.subst('$BASE_IRDB_LIBS')) myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install1=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/memcover/SConscript b/tools/memcover/SConscript index ae5c93b00..df8aa29db 100644 --- a/tools/memcover/SConscript +++ b/tools/memcover/SConscript @@ -20,7 +20,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="memcover.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/prince/SConscript b/tools/prince/SConscript index 49a38296e..97ac3ea4d 100644 --- a/tools/prince/SConscript +++ b/tools/prince/SConscript @@ -20,7 +20,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="prince_driver.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/print_cfi_stats/SConscript b/tools/print_cfi_stats/SConscript index 553c9b6e9..d6c1e1736 100644 --- a/tools/print_cfi_stats/SConscript +++ b/tools/print_cfi_stats/SConscript @@ -20,7 +20,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="print_cfi_stats_driver.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) #install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/ret_shadow_stack/SConscript b/tools/ret_shadow_stack/SConscript index 47badfe06..ce403bd82 100644 --- a/tools/ret_shadow_stack/SConscript +++ b/tools/ret_shadow_stack/SConscript @@ -19,7 +19,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="ret_shadow_stack.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/safefn/SConscript b/tools/safefn/SConscript index 94fa9aa68..48212fccd 100644 --- a/tools/safefn/SConscript +++ b/tools/safefn/SConscript @@ -20,7 +20,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="fill_in_safefn.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/safefr/SConscript b/tools/safefr/SConscript index c67dc5a0e..b8345c801 100644 --- a/tools/safefr/SConscript +++ b/tools/safefr/SConscript @@ -20,7 +20,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="fill_in_safefr.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/selective_cfi/SConscript b/tools/selective_cfi/SConscript index 52e961537..e27170815 100644 --- a/tools/selective_cfi/SConscript +++ b/tools/selective_cfi/SConscript @@ -10,7 +10,7 @@ cpppath=''' $SECURITY_TRANSFORMS_HOME/include $SECURITY_TRANSFORMS_HOME/libIRDB/include $SECURITY_TRANSFORMS_HOME/libMEDSannotation/include - $SECURITY_TRANSFORMS_HOME/tools/transforms + $SECURITY_TRANSFORMS_HOME/libtransform/include $SECURITY_TRANSFORMS_HOME/libEXEIO/include ''' @@ -22,7 +22,7 @@ myenv.Append(CXXFLAGS = " -std=c++11 -Wall ") pgm="selective_cfi.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util IRDB-core transform rewrite MEDSannotation pqxx pq") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util IRDB-core transform MEDSannotation pqxx pq") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/plugins_install/", pgm) diff --git a/tools/selective_cfi/scfi_instr.cpp b/tools/selective_cfi/scfi_instr.cpp index 198fb0b0d..950c43fd8 100644 --- a/tools/selective_cfi/scfi_instr.cpp +++ b/tools/selective_cfi/scfi_instr.cpp @@ -36,6 +36,16 @@ using namespace std; using namespace libIRDB; +using namespace IRDBUtility; + +string getRetDataBits() +{ + string dataBits; + dataBits.resize(1); + dataBits[0] = 0xc3; + return dataBits; +} + Relocation_t* SCFI_Instrument::FindRelocation(Instruction_t* insn, string type) diff --git a/tools/simple_cdi/SConscript b/tools/simple_cdi/SConscript index 0966b77a8..988e0df58 100644 --- a/tools/simple_cdi/SConscript +++ b/tools/simple_cdi/SConscript @@ -19,7 +19,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="simple_cdi.exe" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/plugins_install/", pgm) diff --git a/tools/spasm/SConscript b/tools/spasm/SConscript index 5e881b1db..505048dc1 100644 --- a/tools/spasm/SConscript +++ b/tools/spasm/SConscript @@ -20,7 +20,7 @@ files=Glob( Dir('.').srcnode().abspath+"/*.cpp") pgm="spasm" LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" -LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform rewrite MEDSannotation ") +LIBS=Split( env.subst('$BASE_IRDB_LIBS')+ " IRDB-cfg IRDB-util transform MEDSannotation ") myenv=myenv.Clone(CPPPATH=Split(cpppath)) pgm=myenv.Program(pgm, files, LIBPATH=LIBPATH, LIBS=LIBS) install=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", pgm) diff --git a/tools/transforms/AnnotationBoundaryGenerator.cpp b/tools/transforms/AnnotationBoundaryGenerator.cpp deleted file mode 100644 index 46f36ec76..000000000 --- a/tools/transforms/AnnotationBoundaryGenerator.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "AnnotationBoundaryGenerator.hpp" -#include <map> - -#include <iostream> - -using namespace std; -using namespace libIRDB; -using namespace MEDS_Annotation; -//using namespace MEDS_Annotation; - - -vector<Range> AnnotationBoundaryGenerator::GetBoundaries(libIRDB::Function_t *func) -{ - vector<Range> ranges; - -// std::multimap<VirtualOffset, MEDS_AnnotationBase> - MEDS_Annotations_t annotations = annotParser->getAnnotations(); - - for( - set<Instruction_t*>::const_iterator it=func->GetInstructions().begin(); - it!=func->GetInstructions().end(); - ++it - ) - { - Instruction_t* instr = *it; - virtual_offset_t irdb_vo = instr->GetAddress()->GetVirtualOffset(); - - if (irdb_vo == 0) continue; - - VirtualOffset vo(irdb_vo); - - //std::pair<std::multimap<VirtualOffset, MEDS_AnnotationBase>::iterator,std::multimap<VirtualOffset, MEDS_AnnotationBase>::iterator> ret; - std::pair<MEDS_Annotations_t::iterator,MEDS_Annotations_t::iterator> ret; - ret = annotations.equal_range(vo); - MEDS_InstructionCheckAnnotation annotation; - MEDS_InstructionCheckAnnotation* p_annotation; - for (MEDS_Annotations_t::iterator it = ret.first; it != ret.second; ++it) - { - p_annotation=dynamic_cast<MEDS_InstructionCheckAnnotation*>(it->second); - if(p_annotation==NULL) - continue; - annotation = *p_annotation; - if (annotation.isValid() && annotation.isMemset()) - { - //cerr<<"Memset annot found"<<endl; - - int objectSize = annotation.getObjectSize(); - int offset = annotation.getStackOffset(); - - Range cur; - cur.SetOffset(offset); - cur.SetSize(objectSize); - - if (annotation.isEbpOffset()) - { - if(offset < 0) - { - ranges.push_back(cur); - } - - } else if (annotation.isEspOffset()) - { - if(offset >= 0) - { - ranges.push_back(cur); - } - } else - { - // something went wrong - assert(0); - } - } - } - } - - return ranges; -} diff --git a/tools/transforms/AnnotationBoundaryGenerator.hpp b/tools/transforms/AnnotationBoundaryGenerator.hpp deleted file mode 100644 index 70e189f61..000000000 --- a/tools/transforms/AnnotationBoundaryGenerator.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __ANNOTBOUNDGEN -#define __ANNOTBOUNDGEN -#include "PrecedenceBoundaryGenerator.hpp" -#include "MEDS_AnnotationParser.hpp" -#include "MEDS_AnnotationBase.hpp" -#include "MEDS_InstructionCheckAnnotation.hpp" -#include "VirtualOffset.hpp" - -#include <fstream> - -class AnnotationBoundaryGenerator : public PrecedenceBoundaryGenerator -{ -protected: - MEDS_Annotation::MEDS_AnnotationParser *annotParser; -public: - AnnotationBoundaryGenerator(MEDS_Annotation::MEDS_AnnotationParser *annotParser) : annotParser(annotParser){} - virtual std::vector<Range> GetBoundaries(libIRDB::Function_t *func); -}; - -#endif diff --git a/tools/transforms/DirectOffsetInference.cpp b/tools/transforms/DirectOffsetInference.cpp deleted file mode 100644 index 8a6698e36..000000000 --- a/tools/transforms/DirectOffsetInference.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "DirectOffsetInference.hpp" - -using namespace std; -using namespace libIRDB; - -DirectOffsetInference::DirectOffsetInference(OffsetInference *offset_inference) -{ - //TODO: throw exception - assert(offset_inference != NULL); - - this->offset_inference = offset_inference; -} - -PNStackLayout* DirectOffsetInference::GetPNStackLayout(Function_t *func) -{ - return offset_inference->GetDirectAccessLayout(func); -} - -std::string DirectOffsetInference::GetInferenceName() const -{ - return "Direct Offset Inference"; -} diff --git a/tools/transforms/DirectOffsetInference.hpp b/tools/transforms/DirectOffsetInference.hpp deleted file mode 100644 index 2a00762cd..000000000 --- a/tools/transforms/DirectOffsetInference.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __DIRECTOFFSETINFERENCE -#define __DIRECTOFFSETINFERENCE - -#include "OffsetInference.hpp" -#include "PNStackLayoutInference.hpp" - -class DirectOffsetInference : public PNStackLayoutInference -{ -protected: - OffsetInference *offset_inference; -public: - DirectOffsetInference(OffsetInference *offset_inference); - virtual PNStackLayout* GetPNStackLayout(libIRDB::Function_t *func); - virtual std::string GetInferenceName() const; -}; - - -#endif diff --git a/tools/transforms/EhUpdater.cpp b/tools/transforms/EhUpdater.cpp deleted file mode 100644 index be57ca73b..000000000 --- a/tools/transforms/EhUpdater.cpp +++ /dev/null @@ -1,192 +0,0 @@ - -#include "EhUpdater.hpp" -#include <string> -#include <map> - -using namespace std; -using namespace libIRDB; - -extern map<Function_t*, set<Instruction_t*> > inserted_instr; //used to undo inserted instructions - - -// see https://en.wikipedia.org/wiki/LEB128 -static bool read_uleb128 - ( uint64_t &result, - uint32_t& position, - const uint8_t* const data, - const uint32_t max) -{ - result = 0; - auto shift = 0; - while( position < max ) - { - auto byte = data[position]; - position++; - result |= ( ( byte & 0x7f ) << shift); - if ( ( byte & 0x80) == 0) - break; - shift += 7; - } - return ( position >= max ); - -} - -static string to_uleb128 (uint64_t value) -{ - auto output_str=string(""); - do - { - auto byte = value&0x7f; // low order 7 bits of value; - value >>= 7; - if (value != 0) // more bytes to come - byte |= 0x80; // set high order bit of byte; - - output_str.push_back(byte); - - } while (value != 0); - - return output_str; -} - -/* transform any eh handling info for the FDE program*/ -bool EhUpdater_t::update_program(EhProgram_t* ehpgm) -{ - assert(ehpgm); - const auto daf=ehpgm->GetDataAlignmentFactor(); - const auto saved_reg_size=m_layout->GetSavedRegsSize(); - const auto orig_frame_size=m_layout->GetOriginalAllocSize(); - const auto altered_frame_size=m_layout->GetAlteredAllocSize(); - - /* change the offset, as needed, in a dwarf instruction. the offset is at location 'pos' */ - const auto change_offset=[&](string &dwarf_insn, const uint32_t offset_pos, const bool factored) -> void - { - /* handle */ - /* format: [(char)(opcode+reg#)] [(uleb128) offset/data_alignment_factor] */ - /* we need to adjust factored offset if it's greater than the saved reg size */ - auto factored_offset=uint64_t(0); - auto pos_to_read=(uint32_t)1; - const auto data=reinterpret_cast<const uint8_t*>(dwarf_insn.data()); - const auto res=read_uleb128(factored_offset,pos_to_read,data, dwarf_insn.size()); - assert(res); - auto offset=factored_offset; - if(factored) - offset*=daf; - if(offset>saved_reg_size) - { - const auto new_offset=offset+(altered_frame_size-orig_frame_size); - auto factored_new_offset=new_offset; - if(factored) - factored_new_offset/=daf; - - const auto encoded_factored_new_offset=to_uleb128(factored_new_offset); - auto new_dwarf_insn=string(""); - for(auto i=0U;i<offset_pos;i++) - new_dwarf_insn.push_back(dwarf_insn[i]); - new_dwarf_insn+=encoded_factored_new_offset; - dwarf_insn=new_dwarf_insn; - } - }; - - for(auto &dwarf_insn: ehpgm->GetFDEProgram()) - { - auto opcode=dwarf_insn[0]; - auto opcode_upper2=(uint8_t)(opcode >> 6); - auto opcode_lower6=(uint8_t)(opcode & (0x3f)); - switch(opcode_upper2) - { - /* case DW_CFA_offset: */ - /* reg should be restored from CFA+(offset*daf) */ - case 0x2: /* DW_CFA_offset: */ - { - change_offset(dwarf_insn,1, true); - break; - }; - case 0: - { - switch(opcode_lower6) - { - /* sanitize */ - case 0xd: /* DW_CFA_def_cfa_register: */ - { - /* [ (char)opcode ] [ (uleb)register ] */ - /* assert if register != sp (if bp not used) or bp (if bp is used) */ - /* never update this insn */ - assert(0); - } - /* handle */ - case 0xe: /* DW_CFA_def_cfa_offset: */ - { - /* [(char)opcode] [(uleb)offset] */ - /* if offset > saved reg size, new_offset=offset+(new_frame_size-old_frame_size) */ - change_offset(dwarf_insn,1,false); - break; - } - case 0x11: /*DW_CFA_def_cfa_offset_sf: */ - { - /* [(char)opcode] [(sleb)offset/data_alignment_factor] */ - /* if offset > saved reg size, new_offset=offset+(new_frame_size-old_frame_size) */ - assert(0); - } - - case 0x5: /*DW_CFA_offset_extended: */ - { - /* [ (char)opcode ] [ (uleb)reg # ] [ (uleb) offset] */ - /* we need to adjust factored offset if it's greater than the saved reg size */ - change_offset(dwarf_insn,2,true); - break; - } - - default: - break; - } - } - default: - break; - } - } - return true; -} - -/* transform any eh handling info for the instruction */ -bool EhUpdater_t::update_instructions(Instruction_t* insn) -{ - const auto ehpgm=insn->GetEhProgram(); - - /* no program == no update */ - if(ehpgm==NULL) - return true; - - const auto new_eh_pgm=new EhProgram_t(*ehpgm); - insn->SetEhProgram(new_eh_pgm); - m_firp->GetAllEhPrograms().insert(new_eh_pgm); - - return update_program(new_eh_pgm); -} - -/* transform any eh handling info for each instruction */ -bool EhUpdater_t::update_instructions() -{ - // for all instructions in the fuunction. - for(const auto& i: m_func->GetInstructions()) - update_instructions(i); - // plus any instructions we allocated for the function - for(const auto& i: inserted_instr[m_func]) - update_instructions(i); - - return true; -} - - -/* transform any eh handling info for the function */ -bool EhUpdater_t::execute() -{ - if(m_func->GetUseFramePointer()) /* no updates needed if a frame pointer is used */ - return true; - - /* can only update for p1 functions */ - if( ! m_layout->IsP1() ) - return false; - - return update_instructions(); -} - diff --git a/tools/transforms/EhUpdater.hpp b/tools/transforms/EhUpdater.hpp deleted file mode 100644 index 6f9569fdb..000000000 --- a/tools/transforms/EhUpdater.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EhUpdater -#define EhUpdater - -#include <libIRDB-core.hpp> -#include "PNStackLayout.hpp" - -class EhUpdater_t -{ - public: - - EhUpdater_t(libIRDB::FileIR_t* p_firp, libIRDB::Function_t* p_func, PNStackLayout* p_layout) - : - m_firp(p_firp), - m_func(p_func), - m_layout(p_layout) - { - } - - bool execute(); - - private: - - bool update_instructions(); - bool update_instructions(libIRDB::Instruction_t* insn); - bool update_program(libIRDB::EhProgram_t* ehpgm); - - - libIRDB::FileIR_t* m_firp; - libIRDB::Function_t* m_func; - PNStackLayout* m_layout; -}; - -#endif diff --git a/tools/transforms/General_Utility.cpp b/tools/transforms/General_Utility.cpp deleted file mode 100644 index a344f1a23..000000000 --- a/tools/transforms/General_Utility.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "General_Utility.hpp" -#include <limits.h> -#include <cstdlib> -#include <cerrno> - -using namespace std; - -STR2NUM_ERROR str2int (int &i, char const *s, int base) -{ - char *end; - long l; - errno = 0; - l = strtol(s, &end, base); - if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) { - return STR2_OVERFLOW; - } - if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) { - return STR2_UNDERFLOW; - } - if (*s == '\0' || *end != '\0') { - return STR2_INCONVERTIBLE; - } - i = l; - return STR2_SUCCESS; -} - -//TODO: what if the string represents a negative number? Currently -//the number will be translated into an unsigned int. I could make this -//and incovertible situation. -STR2NUM_ERROR str2uint (unsigned int &i, char const *s, int base) -{ - char *end; - unsigned long l; - errno = 0; - l = strtoul(s, &end, base); - if ((errno == ERANGE && l == ULONG_MAX) || l > UINT_MAX) { - return STR2_OVERFLOW; - } - if (*s == '\0' || *end != '\0') { - return STR2_INCONVERTIBLE; - } - i = l; - return STR2_SUCCESS; -} diff --git a/tools/transforms/General_Utility.hpp b/tools/transforms/General_Utility.hpp deleted file mode 100644 index d03d12f37..000000000 --- a/tools/transforms/General_Utility.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef _GENERAL_UTILITY -#define _GENERAL_UTILITY - -enum STR2NUM_ERROR { STR2_SUCCESS, STR2_OVERFLOW, STR2_UNDERFLOW, STR2_INCONVERTIBLE }; -STR2NUM_ERROR str2int (int &i, char const *s, int base = 0); -STR2NUM_ERROR str2uint (unsigned int &i, char const *s, int base = 0); - -#endif diff --git a/tools/transforms/Makefile.in b/tools/transforms/Makefile.in deleted file mode 100644 index 23f19df95..000000000 --- a/tools/transforms/Makefile.in +++ /dev/null @@ -1,51 +0,0 @@ -# -# Makefile.in - DESCRIPTION. -# -# Copyright (c) 2011 - University of Virginia -# -# This file may be used and modified for non-commercial purposes as long as -# all copyright, permission, and nonwarranty notices are preserved. -# Redistribution is prohibited without prior written consent from the University of Virginia -# -# Please contact the authors for restrictions applying to commercial use. -# -# THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF -# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -# - -PROGS=p1transform.exe nulltransform.exe integertransformdriver.exe - -CXX=@CXX@ -CXXFLAGS= -g $(TWITCHER_FLAGS) @EXTRA_CXXFLAGS@ -fPIC -INCLUDE=-I. -I../../include -I../../xform -I../../beaengine/include -I../../libIRDB/include/ -I../../libMEDSannotation/include/ -I../../libtransform/include/ -LIBS=-L../../lib -lxform -lIRDB-core -lIRDB-cfg -lBeaEngine_s_d -lpqxx -lMEDSannotation -ltransform -lpq - -OBJS=transformutils.o - -all_objs=PNTransformDriver.o PNStackLayout.o PNRange.o Range.o OffsetInference.o DirectOffsetInference.o ScaledOffsetInference.o P1Inference.o PNRegularExpressions.o PNMain.o StackLayout.o Rewrite_Utility.o General_Utility.o AnnotationBoundaryGenerator.o PrecedenceBoundaryInference.o PNIrdbManager.o - -.SUFFIXES: .o .c .exe .cpp .hpp - -all: integertransformdriver.exe p1transform.exe pntransform.exe $(OBJS) $(PROGS) - echo integertransform and pntransform build complete - -$(all_objs): *hpp - -.cpp.o: PNStackLayoutInference.hpp *.hpp - $(CXX) $(INCLUDE) $(CXXFLAGS) -g -c $< - -.cpp.exe: - $(CXX) -g $< $(INCLUDE) $(LIBS) $(OBJS) -o $@ - -clean: - rm -f *.o core $(PROGS) - -integertransformdriver.exe: integertransformdriver.o transformutils.o ../../lib/*.a - $(CXX) $(CXXFLAGS) transformutils.o integertransformdriver.o $(INCLUDE) $(LIBS) -o integertransformdriver.exe - -pntransform.exe: $(all_objs) ../../lib/*.a - $(CXX) $(CXXFLAGS) $(all_objs) $(INCLUDE) $(LIBS) -o pntransform.exe - -p1transform.exe: pntransform.exe - cp pntransform.exe p1transform.exe diff --git a/tools/transforms/OffsetInference.cpp b/tools/transforms/OffsetInference.cpp deleted file mode 100644 index b5a96df1d..000000000 --- a/tools/transforms/OffsetInference.cpp +++ /dev/null @@ -1,1121 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "OffsetInference.hpp" -#include "General_Utility.hpp" -//#include "beaengine/BeaEngine.h" -#include <cassert> -#include <iostream> -#include <cstdlib> -#include <set> -#include <fstream> -#include "globals.h" - -using namespace std; -using namespace libIRDB; - -static Relocation_t* FindRelocation(Instruction_t* insn, string type) -{ - RelocationSet_t::iterator rit; - for( rit=insn->GetRelocations().begin(); rit!=insn->GetRelocations().end(); ++rit) - { - Relocation_t& reloc=*(*rit); - if(reloc.GetType()==type) - { - return &reloc; - } - } - return NULL; -} - - -extern int get_saved_reg_size(); - -//TODO: Use cfg entry point only, then use func instructions, - -//TODO: matching reg expressions use max match constant - -//TODO: negative offsets? - -//TODO: what if func is null? - -//TODO: everying operates on regex because when I first wrote this, I didn't -//know DISASM had much of this information. We should migrate to using -//this struct more. That goes for the entire PN code base as well. - -//TODO: The inferences generated are highly conservative in what functions -//are considered transformable. Look at how the dealloc_flag and alloc_count - -OffsetInference::~OffsetInference() -{ - //It is assumed that all pointers in the maps are unique - //this is supposed to be guaranteed by the mechanisms of this - //object - //TODO: add some asserts to ensure no double delete - - map<Function_t*,PNStackLayout*>::iterator it; - - for(it=direct.begin();it !=direct.end();it++) - { - delete (*it).second; - } - - for(it=scaled.begin();it !=scaled.end();it++) - { - delete (*it).second; - } - - for(it=all_offsets.begin();it !=all_offsets.end();it++) - { - delete (*it).second; - } -} - -/* - void OffsetInference::GetInstructions(vector<Instruction_t*> &instructions,BasicBlock_t *block,set<BasicBlock_t*> &block_set) - { - instructions.insert(instructions.end(),block->GetInstructions().begin(),block->GetInstructions().end()); - block_set.insert(block); - - // cerr<<"OffsetInference: GetInstructions(): predecessors = "<<block->GetPredecessors().size()<<" successors = "<<block->GetSuccessors().size()<<endl; - - for( - set<BasicBlock_t*>::const_iterator it = block->GetSuccessors().begin(); - it != block->GetSuccessors().end(); - ++it - ) - { - if(block_set.find(*it) == block_set.end()) - GetInstructions(instructions,*it,block_set); - } - - for( - set<BasicBlock_t*>::const_iterator it = block->GetPredecessors().begin(); - it != block->GetPredecessors().end(); - ++it - ) - { - if(block_set.find(*it) == block_set.end()) - GetInstructions(instructions,*it,block_set); - } - } -*/ - -StackLayout* OffsetInference::SetupLayout(Function_t *func) -{ - unsigned int stack_frame_size = 0; - int saved_regs_size = 0; - int out_args_size = func->GetOutArgsRegionSize(); - bool push_frame_pointer = false; - bool save_frame_pointer = false; - - Instruction_t *entry = func->GetEntryPoint(); - - if(pn_regex==NULL) - pn_regex=new PNRegularExpressions; - - // bool has_frame_pointer = false; - - int max = PNRegularExpressions::MAX_MATCHES; -// regmatch_t pmatch[max]; -// regmatch_t *pmatch=(regmatch_t*)malloc(max*sizeof(regmatch_t)); - regmatch_t *pmatch=new regmatch_t[max]; - memset(pmatch, 0,sizeof(regmatch_t) * max); - - assert(out_args_size >=0); - - //TODO: find the fallthrough of the entry block, and loop to it if necessary. - -/* - for( - vector<Instruction_t*>::const_iterator it=entry->GetInstructions().begin(); - it!=entry->GetInstructions().end(); - ++it - ) -*/ - string disasm_str; - //loop through fallthroughs of the entry (entry will be update on every iteration) - //until entry is null, or entry has left the function. - while(entry != NULL && (entry->GetFunction()==func)) - { - - in_prologue[entry]=true; - string matched; - - //Instruction_t* instr=*it; - Instruction_t* instr = entry; - - //DISASM disasm; - //Disassemble(instr,disasm); - const auto disasm=DecodedInstruction_t(instr); - disasm_str = disasm.getDisassembly(); // CompleteInstr; - - if(verbose_log) - cerr << "OffsetInference: SetupLayout(): disassembled line = "<<disasm_str<< endl; - - //TODO: find push ebp, then count pushes to sub esp, stack alloc size and pushed size are fed to layout objects - //TODO: for now I assume all pushes are 32 bits, is this a correct assumption? - if(regexec(&(pn_regex->regex_push_ebp), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr << "OffsetInference: SetupLayout(): Push EBP Found"<<endl; - - push_frame_pointer = true; - - if(stack_frame_size != 0) - { - //TODO: handle this better - if(verbose_log) - cerr<<"OffsetInference: SetupLayout(): Stack Frame Already Allocated, Ignoring Push EBP"<<endl; - - entry = entry->GetFallthrough(); - continue; - } - -//TODO: ignoring this code for now, although it appears this code no longer -//makes sense anyway. Don't reset the saved regs if yous ee another push ebp -//just ignore it for now. EBP is usually pushed first, if it isn't -//it is likely not going to be used as a base pointer, in which case I really -//don't want to reset the saved regs count anyway. If it is a base pointer -//and pushed other than first, then I don't know how this func will work -//anyway. - -// else -// { -// saved_regs_size = 0; -// } - } - else if(regexec(&(pn_regex->regex_save_fp), disasm_str.c_str(), max, pmatch, 0)==0) - { - save_frame_pointer = true; - } - else if(regexec(&(pn_regex->regex_push_anything), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"OffsetInference: SetupLayout(): Push (anything) Found"<<endl; - - if(stack_frame_size != 0) - { - //TODO: handle this better - if(verbose_log) - cerr<<"OffsetInference: SetupLayout(): Stack Frame Already Allocated, Ignoring Push Instruction"<<endl; - - entry = entry->GetFallthrough(); - continue; - } - -// cerr<<"PUSH FOUND: "<<disasm.CompleteInstr<<endl; -// cerr<<"PUSH Argument1: "<<hex<<(disasm.Argument1.ArgType & 0xF0000000)<<endl; -// cerr<<"PUSH Argument2: "<<hex<<(disasm.Argument2.ArgType & 0xF0000000)<<endl; - // cerr<<"CONST_TYPE = "<<hex<<CONSTANT_TYPE<<endl; - - //if the push is a constant, then check if the next instruction - //is an unconditional jmp, if so, ignore the push, assume - //the push is part of fixed calls. - if(disasm.getOperand(0).isConstant() /* (disasm.Argument2.ArgType & 0xF0000000) == CONSTANT_TYPE */) - { - //Grab the pushed value - assert(pmatch[1].rm_so >=0 && pmatch[1].rm_eo >=0); - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - //cerr<<"DEBUG DEBUG: Disasm match: "<<disasm.CompleteInstr<<endl; - -// if((it+1) != entry->GetInstructions().end()) - if(entry->GetFallthrough() != NULL) - { -// Instruction_t* next=*(it+1); - Instruction_t* next = entry->GetFallthrough(); - //DISASM next_disasm; - //Disassemble(next,next_disasm); - const auto next_disasm=DecodedInstruction_t(next); - - //cerr<<"DEBUG DEBUG: Disasm next match: "<<next_disasm.CompleteInstr<<endl; - - if(next_disasm.isUnconditionalBranch() /*Instruction.BranchType == JmpType*/) - { - - if(verbose_log) - cerr<<"OffsetInference: SetupLayout(): Found push matching fix calls pattern, ignoring the push (i.e., not recording the bytes pushed)."<<endl; - - - //find the indirect branch target instruction, and reset entry to this instruction, then continue execution of the loop. - - int target_addr_offset; - assert(str2int(target_addr_offset, matched.c_str())==STR2_SUCCESS); - - //TODO: it is better to make a map of ind branch targets, but this efficient enough for now. - - //Setting entry to null is a primitive way of checking if the target is in the same function - //if it isn't, entry will be NULL at the end of the loop. - entry=NULL; - for( - set<Instruction_t*>::const_iterator it=func->GetInstructions().begin(); - it!=func->GetInstructions().end(); - ++it - ) - { - Instruction_t *cur = *it; - - if(cur->GetIndirectBranchTargetAddress() == NULL) - continue; - - int cur_ibta = (int)cur->GetIndirectBranchTargetAddress()->GetVirtualOffset(); - - //The target instruction is found, set entry to point to this instruction - //continue analysis from this instruction. - if(cur_ibta == target_addr_offset) - { - entry = cur; - break; - } - } - - continue; - } - } - } - //else the push value is registered - - //TODO: assuming 4 bytes here for saved regs - saved_regs_size += get_saved_reg_size(); - } - else if(regexec(&(pn_regex->regex_stack_alloc), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr << "OffsetInference: FindAllOffsets(): Found Stack Alloc"<<endl; - - //TODO: Is this the way this situation should be handled? - //The first esp sub instruction is considered the stack allocation, all other subs are ignored - //Given that I return when the first one is found, this is probably a useless check. - if(stack_frame_size != 0) - { - if(verbose_log) - cerr <<"OffsetInference: FindAllOffsets(): Stack Alloc Previously Found, Ignoring Instruction"<<endl; - - entry = entry->GetFallthrough(); - continue; - } - - //extract K from: sub esp, K - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - //extract K - //stack_frame_size = strtol(matched.c_str(),NULL,0); - if(str2uint(stack_frame_size, matched.c_str())!= STR2_SUCCESS) - { - //If this occurs, then the found stack size is not a - //constant integer, so it must be a register. - - //TODO: is this what I really want to do? - if(verbose_log) - cerr<<"OffsetInference: LayoutSetup(): Found non-integral stack allocation ("<<matched<<") before integral stack allocation, generating a null layout inference for function "<<func->GetName()<<endl; - return NULL; - } - - //else - - if(verbose_log) - cerr<<"OffsetInference: LayoutSetup(): Stack alloc Size = "<<stack_frame_size<< - " Saved Regs Size = "<<saved_regs_size<<" out args size = "<<out_args_size<<endl; - - //TODO: with the new code for determine if a frame pointer exists - //I don't consider the case where the frame poitner is pushed but - //ebp is not setup like a frame pointer. In this case, ebp acts - //like a real general purpose register. - //The hack for now is to check if ebp is pushed, but the frame pointer - //is not saved. In this case, consider ebp as another saved reg - //and add to the save of the saved regs. - //When you fix this, look at PNTransformDriver in the canary_rewrite - //subroutine. You will see a case where there is a check for the frame - //pointer, and an additional 4 bytes is added. This should be removed - //in the future to only use the size of the saved regs, but - //this changes any ebp relative offset calculations to remove 4 bytes. - //Confusing, I know. - if(push_frame_pointer&&!save_frame_pointer) - saved_regs_size +=get_saved_reg_size(); - - //There is now enough information to create the PNStackLayout objects - if((unsigned)stack_frame_size<(unsigned)out_args_size) // what? - { - cerr<<"****************************************************************"<<endl; - cerr<<"****************************************************************"<<endl; - cerr<<"**Insanity coming from STARS, out_args_size > stack_frame_size**"<<endl; - cerr<<"****************************************************************"<<endl; - cerr<<"****************************************************************"<<endl; - return NULL; - } - return new StackLayout("All Offset Layout",func->GetName(),stack_frame_size,saved_regs_size,(push_frame_pointer&&save_frame_pointer),out_args_size); - - } - } - entry = entry->GetFallthrough(); - } - - return NULL; -} - -//TODO: what about moving esp into a register? - -//TODO: Try catches for exceptions thrown by PNStackLayout, for now asserts will fail in PNStackLayout -void OffsetInference::FindAllOffsets(Function_t *func) -{ - StackLayout *pn_all_offsets = NULL; - StackLayout *pn_direct_offsets = NULL; - StackLayout *pn_scaled_offsets = NULL; - StackLayout *pn_p1_offsets = NULL; - //int out_args_size; - - int max = PNRegularExpressions::MAX_MATCHES; - //regmatch_t pmatch[max]; - regmatch_t *pmatch=new regmatch_t[max]; - assert(pmatch); - memset(pmatch, 0,sizeof(regmatch_t) * max); - unsigned int stack_frame_size = 0; - unsigned int saved_regs_size = 0; - int ret_cnt = 0; - bool lea_sanitize=false; - -/* - out_args_size = func->GetOutArgsRegionSize(); - assert(out_args_size >= 0); -*/ - - //TODO: hack for T&E to make inferences more conservative - bool dealloc_flag=false; - int alloc_count=0; - - //TODO: a hack for when ebp is used as an index. If found - //only p1 should be attempted. - bool PN_safe = true; - - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets(): Looking at Function = "<<func->GetName()<<endl; - -// ControlFlowGraph_t cfg(func); - -// BasicBlock_t *block = cfg.GetEntry(); - - //TODO: this is an addition for TNE to detect direct recursion, - //in the future the call graph should be analyzed to find all recursion. -// Instruction_t *first_instr = *(block->GetInstructions().begin()); - - Instruction_t *first_instr = func->GetEntryPoint(); - -// pn_all_offsets = SetupLayout(block,func); - pn_all_offsets = SetupLayout(func); - - int out_args_size = func->GetOutArgsRegionSize(); - if(pn_all_offsets != NULL) - { - stack_frame_size = pn_all_offsets->GetAllocSize(); - saved_regs_size = pn_all_offsets->GetSavedRegsSize(); - bool has_frame_pointer = pn_all_offsets->HasFramePointer(); - assert(out_args_size >=0); - - pn_direct_offsets = new StackLayout("Direct Offset Inference", func->GetName(),stack_frame_size,saved_regs_size,has_frame_pointer,out_args_size); - pn_scaled_offsets = new StackLayout("Scaled Offset Inference", func->GetName(),stack_frame_size,saved_regs_size,has_frame_pointer,out_args_size); - //do not consider out args for p1 - pn_p1_offsets = new StackLayout("P1 Offset Inference", func->GetName(),stack_frame_size,saved_regs_size,has_frame_pointer,0); - } - else - { - direct[func] = NULL; - scaled[func] = NULL; - all_offsets[func] = NULL; - p1[func] = NULL; - return; - } - - //Just checking that the entry point has no predecessors - //assert(block->GetPredecessors().size() !=0); -/* -//put all instructions into one vector -vector<Instruction_t*> instructions; -set<BasicBlock_t*> block_set; - -GetInstructions(instructions,block,block_set); -if(instructions.size() != func->GetInstructions().size()) -{ -cerr<<"OffsetInference: FindAllOffsets(): Number of CFG found instructions does not equal Function_t found instructions"<<endl; -} - -//Checking that GetInstructions hasn't screwed up -assert(instructions.size() != 0); -*/ - -//TODO: should I start modifying at the entry point? - for( - set<Instruction_t*>::const_iterator it=func->GetInstructions().begin(); - it!=func->GetInstructions().end(); - ++it - ) - /* - for( - vector<Instruction_t*>::const_iterator it=instructions.begin(); - it!=instructions.end(); - ++it - ) - */ - { - string matched; - - Instruction_t* instr=*it; - string disasm_str; - - //DISASM disasm; - //Disassemble(instr,disasm); - const auto disasm=DecodedInstruction_t(instr); - disasm_str = disasm.getDisassembly() /*CompleteInstr*/; - - if(verbose_log) - cerr << "OffsetInference: FindAllOffsets(): disassembled line = "<<disasm_str<< endl; - -/* -//TODO: find push ebp, then count pushes to sub esp, stack alloc size and pushed size are fed to layout objects -//TODO: for now I assume all pushes are 32 bits, is this a correct assumption? -if(regexec(&(pn_regex->regex_push_ebp), disasm_str.c_str(), max, pmatch, 0)==0) -{ -cerr << "OffsetInference: FindAllOffsets(): Push EBP Found"<<endl; - -if(stack_frame_size != 0) -{ -//TODO: handle this better -cerr<<"OffsetInference: FindAllOffsets(): Stack Frame Already Allocated, Ignoring Push EBP"<<endl; -continue; -} -else -{ -saved_regs_size = 0; -} -} -else if(regexec(&(pn_regex->regex_push_anything), disasm_str.c_str(), max, pmatch, 0)==0) -{ -cerr<<"OffsetInference: FindAllOffsets(): Push (anything) Found"<<endl; - -if(stack_frame_size != 0) -{ -//TODO: handle this better -cerr<<"OffsetInference: FindAllOffsets(): Stack Frame Already Allocated, Ignoring Push Instruction"<<endl; -continue; -} -else -{ -//TODO: assuming 4 bytes here for saved regs -saved_regs_size += get_saved_reg_size(); -} -} -else if(regexec(&(pn_regex->regex_stack_alloc), disasm_str.c_str(), max, pmatch, 0)==0) -{ -cerr << "OffsetInference: FindAllOffsets(): Found Stack Alloc"<<endl; - -//TODO: Is this the way this situation should be handled? -//The first esp sub instruction is considered the stack allocation, all other subs are ignored -if(stack_frame_size != 0) -{ -cerr <<"OffsetInference: FindAllOffsets(): Stack Alloc Previously Found, Ignoring Instruction"<<endl; -continue; -} - - -//extract K from: sub esp, K -if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) -{ -int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; -matched = disasm_str.substr(pmatch[1].rm_so,mlen); -//extract K -stack_frame_size = strtol(matched.c_str(),NULL,0); - -cerr<<"OffsetInference: FindAllOffsets(): Stack alloc Size = "<<stack_frame_size<< -" Saved Regs Size = "<<saved_regs_size<<" out args size = "<<out_args_size<<endl; - -//There is now enough information to create the PNStackLayout objects -pn_all_offsets = new PNStackLayout("All Offset Layout",func->GetName(),stack_frame_size,saved_regs_size,out_args_size); -pn_direct_offsets = new PNStackLayout("Direct Offset Layout",func->GetName(),stack_frame_size,saved_regs_size,out_args_size); -pn_scaled_offsets = new PNStackLayout("Scaled Offset Layout", func->GetName(),stack_frame_size,saved_regs_size,out_args_size); -pn_p1_offsets = new PNStackLayout("P1 Layout",func->GetName(),stack_frame_size,saved_regs_size,out_args_size); -} -} -else -*/ - - if(regexec(&(pn_regex->regex_push_anything), disasm_str.c_str(), max, pmatch, 0)==0) - { - Instruction_t* ft=instr->GetFallthrough(); - const auto reloc1=FindRelocation(instr,"32-bit"); - const auto reloc2=FindRelocation(instr,"push64"); - - if(reloc1!=NULL || reloc2!=NULL) - { - /* definite a push from a fixed calls */ - } - else if(ft && !ft->GetFallthrough() && - (ft->GetTarget()==NULL || ft->GetTarget()->GetFunction()!=instr->GetFunction())) - { - /* probably a push/jmp converted by fix calls */ - /* can ignore this push */ - } - else if(!in_prologue[instr]) - { - cerr<<"Found push instruction not in prologue, marking as not canary safe"; - cerr<<"Insn="<<disasm_str<<endl; - pn_direct_offsets->SetCanarySafe(false); - pn_scaled_offsets->SetCanarySafe(false); - pn_all_offsets->SetCanarySafe(false); - pn_p1_offsets->SetCanarySafe(false); - - } - } - - - /* check for an lea with an rsp in it -- needs to be done before other regex's */ - if(regexec(&(pn_regex->regex_lea_rsp), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"OffsetInference: lea_rsp found "<<endl; - - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - if(verbose_log) - cerr<<"OffsetInference: lea_rsp found const"<<endl; - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - // extract displacement - - int offset = disasm.getOperand(1).getMemoryDisplacement() /*Argument2.Memory.Displacement*/; - if(offset<0) /* huh? */ - { - if(verbose_log) - cerr<<"OffsetInference: lea_rsp neg offset sanitize"<<endl; - lea_sanitize=true; - } - unsigned uoffset=(unsigned)offset; - /* if this lea is pointing to saved regs -- huh? */ - if(uoffset>=stack_frame_size && uoffset<saved_regs_size+stack_frame_size) - { - if(verbose_log) - cerr<<"OffsetInference: lea_rsp found in saved regs area"<<endl; - lea_sanitize=true; - } - - } - - - } - - /* now, on to doing offset identification */ - if(regexec(&(pn_regex->regex_stack_dealloc_implicit), disasm_str.c_str(), max, pmatch, 0)==0) - { - dealloc_flag = true; - //TODO: there needs to be a check of lea esp, [ebp-<const>] to make sure const is not in the current stack frame. - } - else if(regexec(&(pn_regex->regex_ret), disasm_str.c_str(), max, pmatch, 0)==0) - { - ++ret_cnt; - } - else if(regexec(&(pn_regex->regex_and_esp), disasm_str.c_str(), max, pmatch, 0)==0) - { - //TODO: decide how to better handle this option. - //Right now I am going to enforce in PNTransformDriver that - //the alignment instruction is removed. - - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets(): Layout is not canary safe"<<endl; - - pn_direct_offsets->SetCanarySafe(false); - pn_scaled_offsets->SetCanarySafe(false); - pn_all_offsets->SetCanarySafe(false); - pn_p1_offsets->SetCanarySafe(false); - } - else if(regexec(&(pn_regex->regex_stack_alloc), disasm_str.c_str(), max, pmatch, 0)==0) - { - //check if the stack allocation uses an integral offset. - - //extract K from: sub esp, K - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - //extract K - unsigned int scheck; - if(str2uint(scheck, matched.c_str()) != STR2_SUCCESS) - { - //If this occurs, then the found stack size is not a - //constant integer, so it must be a register. - - //even though I am specifying only p1 should be performed - //I am still going to set this flag for all transforms. - pn_direct_offsets->SetStaticStack(false); - pn_scaled_offsets->SetStaticStack(false); - pn_all_offsets->SetStaticStack(false); - pn_p1_offsets->SetStaticStack(false); - PN_safe = false; - - //Consider this case not canary safe for now - //TODO: can I make this canary safe? - pn_direct_offsets->SetCanarySafe(false); - pn_scaled_offsets->SetCanarySafe(false); - pn_all_offsets->SetCanarySafe(false); - pn_p1_offsets->SetCanarySafe(false); - - if(verbose_log) - cerr<<"OffsetInferece: instruction contains a dynamic stack allocation, not pn_safe"<<endl; - - //TODO: this output should be removed after TNE - //only used to give Jason an indication that a - //non-static func has been detected. - - ofstream dynstackfile; - dynstackfile.open("dynamic_stack.log",fstream::out|fstream::app); - if(dynstackfile.is_open()) - { - //I don't think this can happen, but I really don't want - //to add a null pointer exception to TNE - if(instr == NULL || instr->GetAddress() == NULL) - { - dynstackfile<<func->GetName()<<" : "<<disasm_str<<endl; - } - else - { - dynstackfile<<func->GetName()<<" : "<<hex<<instr->GetAddress()->GetVirtualOffset()<<" : "<<disasm_str<<endl; - } - dynstackfile.close(); - } - - continue; - - } - } - - alloc_count++; - if(alloc_count >1) - { - if(verbose_log) - cerr<<"OffsetInference: integral stack allocations exceeded 1, abandon inference"<<endl; - break; - } - - } -//TODO: hack for TNE 2, if we see a jmp to an esp or ebp relative address, ignore this function entirely -//The reasion is fix calls will fix an esp/ebp relative call by adding 4 to the original address and pushing -//before the inserted jmp. This gives the false impression that there is a boundary at this location -//and also gives a false impression that the location should be modified using the wrong boundary, even if -//p1 is used only. Specifically this occurred when the frame size was 0x20, and the call was to esp+0x1c -//the fix call because a jmp esp+0x20 which was outside the frame, and PN corrected by changing the offset -//to reflect the padding. - else if(disasm.isUnconditionalBranch() /*Instruction.BranchType == JmpType*/) - { - if(regexec(&(pn_regex->regex_esp_scaled), disasm_str.c_str(), max, pmatch, 0)==0 || - regexec(&(pn_regex->regex_esp_direct), disasm_str.c_str(), max, pmatch, 0)==0 || - regexec(&(pn_regex->regex_ebp_scaled), disasm_str.c_str(), max, pmatch, 0)==0 || - regexec(&(pn_regex->regex_ebp_direct), disasm_str.c_str(), max, pmatch, 0)==0) - { - cerr<<"OffsetInference: FindAllOffsets(): Layout contains a jmp relative to esp or ebp, ignore function for now"<<endl; - - direct[func] = NULL; - scaled[func] = NULL; - all_offsets[func] = NULL; - p1[func] = NULL; - - //TODO: cleanup memory, since this is all so ugly at the moment, I'm inclined to leak memory than - //to risk a segfault deleting a pointer. - return; - } - - - } - else if(regexec(&(pn_regex->regex_esp_scaled), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets(): Found ESP Scaled Instruction"<<endl; -/* - if(stack_frame_size <=0) - { - cerr<<"OffsetInference: FindAllOffsets(): Frame Alloc Not Found, Aborting Offset Search"<<endl; - break; - } -*/ - - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - if(pn_all_offsets != NULL) - { - pn_all_offsets->InsertESPOffset(offset); - } - if(pn_scaled_offsets != NULL) - { - pn_scaled_offsets->InsertESPOffset(offset); - } - - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets(): ESP Offset = "<<offset<<endl; - } - } - else if(regexec(&(pn_regex->regex_esp_direct), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: Found ESP Direct Instruction"<<endl; -/* - if(stack_frame_size <=0) - { - cerr<<"OffsetInference: FindAllOffsets(): Frame Alloc Not Found, Aborting Offset Search"<<endl; - break; - } -*/ - - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - // extract displacement - - int offset = strtol(matched.c_str(),NULL,0); - - if(pn_all_offsets != NULL) - { - pn_all_offsets->InsertESPOffset(offset); - } - if(pn_direct_offsets != NULL) - { - pn_direct_offsets->InsertESPOffset(offset); - } - - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets(): ESP Offset = "<<offset<<endl; - } - } - else if(regexec(&(pn_regex->regex_ebp_scaled), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets(): Found EBP Scaled Instruction"<<endl; -/* - if(stack_frame_size <=0) - { - cerr<<"OffsetInference: FindAllOffsets(): Frame Alloc Not Found, Aborting Offset Search"<<endl; - break; - } -*/ - - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - -/* - if(stack_frame_size - offset < 0) - { - cerr<<"OffsetInference: FindAllOffsets: Detected Negative ESP Offset, Aborting Offset Search"<<endl; - - pn_all_offsets = NULL; - pn_scaled_offsets = NULL; - pn_direct_offsets = NULL; - break; - } -*/ - - if(pn_all_offsets != NULL) - { - pn_all_offsets->InsertEBPOffset(offset); - } - if(pn_scaled_offsets != NULL) - { - pn_scaled_offsets->InsertEBPOffset(offset); - } - } - } - else if(regexec(&(pn_regex->regex_ebp_direct), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets(): Found EBP Direct Instruction"<<endl; -/* - if(stack_frame_size <=0) - { - cerr<<"OffsetInference: FindAllOffsets(): Frame Alloc Not Found, Aborting Offset Search"<<endl; - break; - } -*/ - - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - -/* - if(stack_frame_size - offset < 0) - { - cerr<<"OffsetInference: FindAllOffsets: Detected Negative ESP Offset, Aborting Offset Search"<<endl; - - pn_all_offsets = NULL; - pn_scaled_offsets = NULL; - pn_direct_offsets = NULL; - break; - } -*/ - if(verbose_log) - cerr<<"OffsetInference: FinadAllOffsets(): Extracted EBP offset = "<<offset<<endl; - - if(pn_all_offsets != NULL) - { - pn_all_offsets->InsertEBPOffset(offset); - } - if(pn_direct_offsets != NULL) - { - pn_direct_offsets->InsertEBPOffset(offset); - } - } - } - else if(regexec(&(pn_regex->regex_stack_dealloc), disasm_str.c_str(), max, pmatch, 0)==0) - { - //if we find a dealloc, set a flag indicating as such - dealloc_flag = true; - - //TODO: if the amount to dealloc is not equal to the stack frame size - //exit inference - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - //NOTE: I have seen cases where there is an add esp, 0x0000000 - //in unoptimized code. In this case, the compiler must have - //restored the stack already, ignore the instruction. - - //TODO: casting stack_frame_size, make sure it isn't larger than - //max int, I don't know what to do if I see this. - if(offset != (int)stack_frame_size && offset != 0) - { - if(verbose_log) - cerr<<"OffsetInference: stack deallocation detected with different size of allocation, abandon inference"<<endl; - //dealloc_flag = false; - - //TODO: hacked in for TNE, rewrite. - direct[func] = NULL; - scaled[func] = NULL; - all_offsets[func] = NULL; - p1[func] = NULL; - return; -// break; - } - - } - - //TODO: this is a hack for cases when ebp is used as an index, - //in these cases, only attempt P1 for now, but in the future - //dynamic checks can be used to dermine what object is referred to. - else if(regexec(&(pn_regex->regex_scaled_ebp_index), disasm_str.c_str(), 5, pmatch, 0)==0) - { - PN_safe = false; - if(verbose_log) - cerr<<"OffsetInference: instruction contains an ebp index, not pn_safe"<<endl; - //TODO: at this point I could probably break the loop, - } - //TODO: a hack for TNE to check for direct recursion to dial down padding - else if(regexec(&(pn_regex->regex_call), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(instr->GetTarget() != NULL && instr->GetTarget()->GetAddress() != NULL) - { - if(instr->GetTarget()->GetAddress()->GetVirtualOffset() == first_instr->GetAddress()->GetVirtualOffset()) - { - if(verbose_log) - cerr<<"OffsetInference: function contains a direct recursive call"<<endl; - - pn_direct_offsets->SetRecursive(true); - pn_scaled_offsets->SetRecursive(true); - pn_all_offsets->SetRecursive(true); - pn_p1_offsets->SetRecursive(true); - } - } - } - - else - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: No Pattern Match"<<endl; - } - } - -//TODO: everything is horribly hacked and messy, redo this function. - - //if no dealloc is found, set all inferences to null - //TODO: this was hacked together quickly, one flag is preferable. - //TODO: there might be a memory leak here, see the objects deleted - //at the end of this function. - if(alloc_count>1 || lea_sanitize) - { - if(lea_sanitize) - cerr<<"OffsetInference: FindAllOffsets: lea_rsp that points to saved regs found "<<endl; - else if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: Multiple integral stack allocations found, returning null inferences"<<endl; - - - direct[func] = NULL; - scaled[func] = NULL; - all_offsets[func] = NULL; - p1[func] = NULL; - return; - - } - else - { - - if(!dealloc_flag && ret_cnt == 0) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: Function is missing stack deallocaiton, but does not return, assuming transformable"<<endl; - dealloc_flag = true; - } - //TODO: I need to revist this such that you can pass a pointer to PNStackLayout, - //and handle NULL accordingly. - - //TODO: this has become to hacky, redo. - if(!dealloc_flag) - { - pn_direct_offsets->SetPaddingSafe(false); - pn_scaled_offsets->SetPaddingSafe(false); - pn_all_offsets->SetPaddingSafe(false); - pn_p1_offsets->SetPaddingSafe(false); - } - - unsigned int aoi_size = pn_all_offsets->GetRanges().size(); - //TODO: causes a memory leak since I may reset to NULL, redo - - //if the size of aoi is the same as any other inference - //assume they are the same (insert a null layout entry) - if(pn_direct_offsets->GetRanges().size() != aoi_size) - direct[func] = new PNStackLayout(*pn_direct_offsets, func); - else - direct[func] = NULL; - - if(pn_scaled_offsets->GetRanges().size() != aoi_size) - scaled[func] = new PNStackLayout(*pn_scaled_offsets, func); - else - scaled[func] = NULL; - - //TODO: BIG TODO: There is quite a delema here. If p1 is the same as - //AOI, I don't want to generate it to save time, but what if a function - //has no coverage, so p1 is used, if I set it null here because the - //layouts are the same, I wont have any modification for that function. - p1[func] = new PNStackLayout(*pn_p1_offsets, func); - - all_offsets[func] = new PNStackLayout(*pn_all_offsets, func); - - if(!dealloc_flag) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: No Stack Deallocation Found"<<endl; - if(direct[func] != NULL && !direct[func]->IsShuffleSafe()) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: direct offset inference cannot be shuffled, generating null inference"<<endl; - direct[func] = NULL; - } - - if(scaled[func] != NULL && !scaled[func]->IsShuffleSafe()) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: scaled offset inference cannot be shuffled, generating null inference"<<endl; - scaled[func] = NULL; - } - - if(all_offsets[func] != NULL && !all_offsets[func]->IsShuffleSafe()) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: all offset inference cannot be shuffled, generating null inference"<<endl; - all_offsets[func] = NULL; - } - - p1[func] = NULL; - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: p1 inference by default cannot be shuffled, generating null inference"<<endl; - } - - if(!PN_safe) - { - if(verbose_log) - cerr<<"OffsetInference: FindAllOffsets: Function not pn_safe, using only p1 (p1 may have been previously disabled)"<<endl; - direct[func] = NULL; - scaled[func] = NULL; - all_offsets[func] = NULL; - } - } - - //memory clean up - delete pn_direct_offsets; - delete pn_scaled_offsets; - delete pn_all_offsets; - delete pn_p1_offsets; -} - -//If map entry exists, return it, else perform boundary detection -//If no layout can be made, NULL is returned. -PNStackLayout* OffsetInference::GetPNStackLayout(Function_t *func) -{ - return GetLayout(all_offsets,func); -} - -PNStackLayout* OffsetInference::GetDirectAccessLayout(Function_t *func) -{ - return GetLayout(direct,func); -} - -PNStackLayout* OffsetInference::GetScaledAccessLayout(Function_t *func) -{ - return GetLayout(scaled,func); -} - -PNStackLayout* OffsetInference::GetP1AccessLayout(Function_t *func) -{ - return GetLayout(p1,func); -} - - -PNStackLayout* OffsetInference::GetLayout(map<Function_t*,PNStackLayout*> &mymap,Function_t *func) -{ - //No layout found, find all offset boundaries - if(mymap.find(func) == mymap.end()) - { - FindAllOffsets(func); - } - - //At this point an entry should be made for the function - assert(mymap.find(func) != mymap.end()); - - return mymap.find(func)->second; -} - -string OffsetInference::GetInferenceName() const -{ - return "All Offsets Inference"; -} diff --git a/tools/transforms/OffsetInference.hpp b/tools/transforms/OffsetInference.hpp deleted file mode 100644 index 3cc4742cf..000000000 --- a/tools/transforms/OffsetInference.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __OFFSETSTACKLAYOUTINFERENCE -#define __OFFSETSTACKLAYOUTINFERENCE -#include "PNStackLayoutInference.hpp" -#include "PNRegularExpressions.hpp" -#include <map> -#include <string> - -class OffsetInference : public PNStackLayoutInference -{ - -protected: - std::map<libIRDB::Instruction_t*, bool> in_prologue; - std::map<libIRDB::Function_t*,PNStackLayout*> direct; - std::map<libIRDB::Function_t*,PNStackLayout*> scaled; - std::map<libIRDB::Function_t*,PNStackLayout*> all_offsets; - std::map<libIRDB::Function_t*,PNStackLayout*> p1; - - PNRegularExpressions *pn_regex; - - virtual void FindAllOffsets(libIRDB::Function_t *func); - virtual PNStackLayout* GetLayout(std::map<libIRDB::Function_t*,PNStackLayout*> &mymap, libIRDB::Function_t *func); - // virtual void GetInstructions(std::vector<libIRDB::Instruction_t*> &instructions,libIRDB::BasicBlock_t *block,std::set<libIRDB::BasicBlock_t*> &block_set); - virtual StackLayout* SetupLayout(libIRDB::Function_t *func); -public: - OffsetInference() : pn_regex(NULL) {} - virtual ~OffsetInference(); - virtual PNStackLayout* GetPNStackLayout(libIRDB::Function_t *func); - virtual PNStackLayout* GetDirectAccessLayout(libIRDB::Function_t *func); - virtual PNStackLayout* GetScaledAccessLayout(libIRDB::Function_t *func); - virtual PNStackLayout* GetP1AccessLayout(libIRDB::Function_t *func); - virtual std::string GetInferenceName() const; -}; - -#endif diff --git a/tools/transforms/P1Inference.cpp b/tools/transforms/P1Inference.cpp deleted file mode 100644 index ade63d48f..000000000 --- a/tools/transforms/P1Inference.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "P1Inference.hpp" -#include <cstdlib> - -using namespace std; -using namespace libIRDB; - -P1Inference::P1Inference(OffsetInference *offset_inference) -{ - this->offset_inference = offset_inference; -} - - -PNStackLayout* P1Inference::GetPNStackLayout(Function_t *func) -{ - return offset_inference->GetP1AccessLayout(func); -} - - -std::string P1Inference::GetInferenceName() const -{ - return "P1 Inference"; -} diff --git a/tools/transforms/P1Inference.hpp b/tools/transforms/P1Inference.hpp deleted file mode 100644 index e39dbbe02..000000000 --- a/tools/transforms/P1Inference.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -//TODO: for now we can't trust the DB for the frame size, -//in the future the constructor should be passed the size as found -//by the database - -#ifndef __P1INFERENCE -#define __P1INFERENCE - -#include "PNStackLayoutInference.hpp" -#include "OffsetInference.hpp" - -class P1Inference : public PNStackLayoutInference -{ -protected: - OffsetInference *offset_inference; -public: - P1Inference(OffsetInference *offset_inference); - virtual PNStackLayout* GetPNStackLayout(libIRDB::Function_t *func); - virtual std::string GetInferenceName() const; -}; - -#endif diff --git a/tools/transforms/PNIrdbManager.cpp b/tools/transforms/PNIrdbManager.cpp deleted file mode 100644 index 1cb32c988..000000000 --- a/tools/transforms/PNIrdbManager.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "PNIrdbManager.hpp" - -#include <stdlib.h> -#include <set> -#include <algorithm> - -PNIrdbManager::PNIrdbManager(libIRDB::db_id_t variant_db_id) -{ - // look up this variant ID - m_variant_id = new libIRDB::VariantID_t(variant_db_id); - assert(m_variant_id != NULL); - - // maintain a mapping of function name to Function_t object - m_file_ir = new libIRDB::FileIR_t(*m_variant_id); - std::set<libIRDB::Function_t*> function_set = m_file_ir->GetFunctions(); - for (std::set<libIRDB::Function_t*>::const_iterator it = function_set.begin(); - it != function_set.end(); it++) - { - m_function_map[(*it)->GetName()] = *it; - } - - // create new table name (lowercase) - assert(!m_variant_id->GetName().empty()); - m_table_name = m_variant_id->GetName() + "_stack"; - std::transform(m_table_name.begin(), - m_table_name.end(), - m_table_name.begin(), - ::tolower); -} - -PNIrdbManager::~PNIrdbManager() -{ - delete m_file_ir; - delete m_variant_id; -} - -void -PNIrdbManager::CreateTable() -{ - std::stringstream query; - query << "CREATE TABLE " << m_table_name << " (" - << "stack_id SERIAL PRIMARY KEY, " - << "source_id INTEGER, " - << "esp_offset INTEGER, " - << "size INTEGER, " - << "function_id INTEGER, " - << "instruction_id INTEGER DEFAULT (-1), " - << "range_start_address_id INTEGER DEFAULT (-1)," - << "range_end_address_id INTEGER DEFAULT (-1)," - << "doip INTEGER DEFAULT (-1)" - << ");"; - - libIRDB::pqxxDB_t transaction; - transaction.IssueQuery(query); - transaction.Commit(); -} - -bool -PNIrdbManager::TableExists() -{ - // using pg_tables is Postgresql-specific - std::stringstream query; - query << "SELECT COUNT(tablename) FROM pg_tables WHERE " - << "tablename='" << m_table_name << "';"; - - libIRDB::pqxxDB_t transaction; - transaction.IssueQuery(query); - assert(!transaction.IsDone()); - int table_count = atoi(transaction.GetResultColumn("count").c_str()); - return table_count > 0; -} - - -void -PNIrdbManager::ClearTable() -{ - std::stringstream query; - query << "TRUNCATE TABLE " << m_table_name << " CASCADE;"; - - libIRDB::pqxxDB_t transaction; - transaction.IssueQuery(query); - transaction.Commit(); -} - -void PNIrdbManager::DeleteSource(IRSource source) -{ - std::stringstream query; - query << "DELETE FROM " << m_table_name << " WHERE source_id=" << source - << ";"; - - libIRDB::pqxxDB_t transaction; - transaction.IssueQuery(query); - transaction.Commit(); -} - -libIRDB::db_id_t PNIrdbManager::InsertStackObject( - std::string function_name, - int offset, - unsigned int size, - IRSource source) -{ - assert(m_function_map.find(function_name) != m_function_map.end()); - libIRDB::Function_t * func = m_function_map[function_name]; -std::cout << "IRDB: function name: " << function_name << ", ID: " << func->GetBaseID(); - libIRDB::pqxxDB_t transaction; - std::stringstream query; - query << "INSERT INTO " << m_table_name - << " (esp_offset, size, function_id, source_id) VALUES (" - << offset << "," << size << "," << func->GetBaseID() << "," << source - << ") RETURNING stack_id; "; - - transaction.IssueQuery(query); - transaction.Commit(); - - return atoi(transaction.GetResultColumn("stack_id").c_str()); -} diff --git a/tools/transforms/PNIrdbManager.hpp b/tools/transforms/PNIrdbManager.hpp deleted file mode 100644 index 98f9e905f..000000000 --- a/tools/transforms/PNIrdbManager.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __PN_IRDB_MANAGER_HPP__ -#define __PN_IRDB_MANAGER_HPP__ - -#include <libIRDB-core.hpp> -#include <map> - -class PNIrdbManager -{ -public: - - enum IRSource { - IRS_PEASOUP, - IRS_DWARF - }; - - PNIrdbManager(libIRDB::db_id_t variant_db_id); - virtual ~PNIrdbManager(); - - // Create the IRDB table managed by this class - virtual void CreateTable(); - - // Check the existence of the IRDB table managed by this class - virtual bool TableExists(); - - // Delete the contents of the IRDB table managed by this class - virtual void ClearTable(); - - // Delete all stack objects from a given source - virtual void DeleteSource(IRSource source); - - // Add a stack object - virtual libIRDB::db_id_t InsertStackObject( - std::string function_name, - int offset, - unsigned int size, - IRSource source); - -protected: - - /// @brief Variant ID associated with this table manager - libIRDB::VariantID_t * m_variant_id; - - /// @brief File associated with this table manager - libIRDB::FileIR_t * m_file_ir; - - /// @brief Functions identified in this variant - std::map<std::string, libIRDB::Function_t*> m_function_map; - - /// @brief Name of the table managed by this class - std::string m_table_name; -}; - -#endif // __PN_IRDB_MANAGER_HPP__ diff --git a/tools/transforms/PNMain.cpp b/tools/transforms/PNMain.cpp deleted file mode 100644 index 556dac2b4..000000000 --- a/tools/transforms/PNMain.cpp +++ /dev/null @@ -1,537 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - - -#include <iostream> -#include <limits.h> -//#include <unistd.h> -#include <getopt.h> -#include "PNStackLayoutInference.hpp" -#include "P1Inference.hpp" -#include "OffsetInference.hpp" -#include "ScaledOffsetInference.hpp" -#include "DirectOffsetInference.hpp" -#include "PNTransformDriver.hpp" - -#include "PrecedenceBoundaryInference.hpp" -#include "AnnotationBoundaryGenerator.hpp" -#include "MEDS_AnnotationParser.hpp" - -#include <iostream> -#include <fstream> -#include <string> -#include <set> -#include <cstdlib> -#include <sstream> - -#include "globals.h" - -using namespace std; -using namespace libIRDB; -using namespace MEDS_Annotation; - -bool verbose_log = false; - -PNOptions *pn_options; - -enum -{ - VARIANT_ID_OPTION = CHAR_MAX+1, - BED_SCRIPT_OPTION, - BLACKLIST_OPTION, - COVERAGE_FILE_OPTION, - PN_THRESHOLD_OPTION, - CANARIES_OPTION, - ONLY_VALIDATE_OPTION, - NO_P1_VALIDATE_OPTION, - ALIGN_STACK_OPTION, - APRIORI_OPTION, - GROUND_TRUTH_OPTION, - SHARED_OBJECT_PROTECTION_OPTION, - MIN_STACK_PAD_OPTION, - MAX_STACK_PAD_OPTION, - RECURSIVE_MIN_STACK_PAD_OPTION, - RECURSIVE_MAX_STACK_PAD_OPTION, - SHOULD_DOUBLE_FRAME_SIZE_OPTION, - DOUBLE_THRESHOLD_OPTION, - SELECTIVE_CANARIES_OPTION, - SET_RANDOM_SEED, - SET_CANARY_VALUE, - SET_FLOATING_CANARY_OPTION, - SET_DETECTION_POLICY_OPTION, - SET_DETECTION_EXIT_CODE_OPTION -}; - - - -static struct option const long_options[] = -{ - {"variant_id",required_argument, NULL, VARIANT_ID_OPTION}, - {"bed_script",required_argument, NULL, BED_SCRIPT_OPTION}, - {"blacklist",required_argument, NULL, BLACKLIST_OPTION}, - {"coverage_file",required_argument, NULL, COVERAGE_FILE_OPTION}, - {"pn_threshold",required_argument, NULL, PN_THRESHOLD_OPTION}, - {"canaries", required_argument, NULL, CANARIES_OPTION}, - {"only_validate",required_argument, NULL, ONLY_VALIDATE_OPTION}, - {"no_p1_validate",no_argument,NULL,NO_P1_VALIDATE_OPTION}, - {"apriori_layout_file",required_argument, NULL, APRIORI_OPTION}, - {"align_stack",no_argument,NULL,ALIGN_STACK_OPTION}, - {"ground_truth",no_argument,NULL,GROUND_TRUTH_OPTION}, - {"shared_object_protection",no_argument,NULL,SHARED_OBJECT_PROTECTION_OPTION}, - {"min_stack_padding",required_argument, NULL, MIN_STACK_PAD_OPTION}, - {"max_stack_padding",required_argument, NULL, MAX_STACK_PAD_OPTION}, - {"recursive_min_stack_padding",required_argument, NULL, RECURSIVE_MIN_STACK_PAD_OPTION}, - {"recursive_max_stack_padding",required_argument, NULL, RECURSIVE_MAX_STACK_PAD_OPTION}, - {"should_double_frame_size",required_argument, NULL, SHOULD_DOUBLE_FRAME_SIZE_OPTION}, - {"double_threshold_size",required_argument, NULL, DOUBLE_THRESHOLD_OPTION,}, - {"selective_canaries",required_argument, NULL, SELECTIVE_CANARIES_OPTION}, - {"random_seed",required_argument, NULL, SET_RANDOM_SEED}, - {"canary_value",required_argument, NULL, SET_CANARY_VALUE}, - {"floating_canary",no_argument, NULL, SET_FLOATING_CANARY_OPTION}, - {"detection_policy",required_argument, NULL, SET_DETECTION_POLICY_OPTION}, - {"detection_exit_code",required_argument, NULL, SET_DETECTION_EXIT_CODE_OPTION}, - {NULL, 0, NULL, 0} -}; - - -//TODO: PN will now p1 if no coverage is available, -//this is not desired for black box testing. -//Find a solution. - - -set<string> getFunctionList(char *p_filename) -{ - set<string> functionList; - - if(p_filename == NULL) - return functionList; - - ifstream candidateFile; - candidateFile.open(p_filename); - - if(candidateFile.is_open()) - { - while(!candidateFile.eof()) - { - string functionName; - getline(candidateFile, functionName); - - functionList.insert(functionName); - } - - candidateFile.close(); - } - - return functionList; -} - - -//TODO: the coverage map should not use the function name since -//it is possible this will repeat when analyzing shared objects. -map<string, map<string,double> > getCoverageMap(char *filename,double cov_threshold) -{ - map<string, map<string,double> > coverage_map; - - int acceptable_cov = 0; - int total_funcs=0; - - if(filename == NULL) - return coverage_map; - - ifstream coverage_file; - coverage_file.open(filename); - - if(coverage_file.is_open()) - { - while(!coverage_file.eof()) - { - //TODO: there is no sanity checking of this file - - string line; - getline(coverage_file, line); - - stringstream ss_line; - ss_line.str(line); - - string func_id,file,func_name; - ss_line>>func_id; - istringstream iss_fid(func_id); - getline(iss_fid,file,'+'); - getline(iss_fid,func_name,'+'); - - string scoverage; - ss_line>>scoverage; - - double coverage = strtod(scoverage.c_str(),NULL); - - if(func_name.length() > 0 && func_name[0] != '.') - { - if(coverage > cov_threshold) - { - if(func_name.length() > 0 && func_name[0] != '.') - acceptable_cov++; - } - total_funcs++; - } - coverage_map[file][func_name]=coverage; - - cout<<"file: "<<file<<" func: "<<func_name<<" coverage: "<<coverage<<endl; - } - cout<<"Summary:"<<endl; - cout<<"\tTotal non-plt functions = "<<total_funcs<<endl; - cout<<"\tTotal non-plt functions exceeding "<<cov_threshold<<" threshold = "<<acceptable_cov<<" ("<<(double)acceptable_cov/total_funcs<<")"<<endl; - coverage_file.close(); - } - return coverage_map; -} - -void usage() -{ - printf("Usage TBD, exiting\n"); - exit(-1); -} - -int main(int argc, char **argv) -{ - - //Set the verbose flag - char *verbose = getenv("VERBOSE"); - if(verbose == NULL) - verbose = getenv("PN_VERBOSE"); - - verbose_log = (verbose != NULL); - - VariantID_t *pidp=NULL; - - int c; - int progid=0; - char *BED_script=NULL; - char *blacklist_file=NULL; - char *coverage_file=NULL; - char *only_validate=NULL; - bool validate_p1=true; - bool align_stack=false; - bool floating_canary=false; - bool shared_object_protection=false; - double p1threshold=0.0; - bool do_ground_truth=false; - - // global class to store options to Pn - pn_options = new PNOptions(); - - while((c = getopt_long(argc, argv, "", long_options, NULL)) != -1) - { - switch(c) - { - case VARIANT_ID_OPTION: - { - progid = atoi(optarg); - break; - } - case BED_SCRIPT_OPTION: - { - BED_script = optarg; - break; - } - case BLACKLIST_OPTION: - { - blacklist_file = optarg; - break; - } - case COVERAGE_FILE_OPTION: - { - coverage_file = optarg; - break; - } - case PN_THRESHOLD_OPTION: - { - p1threshold = strtod(optarg,NULL); - // valid values are -1, and 0-1, inclusive. - // -1 means disabled. - if(p1threshold != -1 && (p1threshold <0 || p1threshold >1)) - { - //TODO: print a message call usage - usage(); - } - break; - } - case CANARIES_OPTION: - { - if(strcasecmp("on",optarg)==0) - { - pn_options->setDoCanaries(true); - } - else if(strcasecmp("off",optarg)==0) - { - pn_options->setDoCanaries(false); - } - else - { - //TODO: print error message and usage - usage(); - } - break; - } - case ONLY_VALIDATE_OPTION: - { - only_validate=optarg; - break; - } - case NO_P1_VALIDATE_OPTION: - { - validate_p1 = false; - break; - } - case ALIGN_STACK_OPTION: - { - align_stack = true; - break; - } - case SHARED_OBJECT_PROTECTION_OPTION: - { - shared_object_protection=true; - break; - } - case GROUND_TRUTH_OPTION: - { - do_ground_truth=true; - break; - } - case MIN_STACK_PAD_OPTION: - { - int min_stack_padding = atoi(optarg); - if (min_stack_padding >= 0) - pn_options->setMinStackPadding(min_stack_padding); - break; - } - case MAX_STACK_PAD_OPTION: - { - int max_stack_padding = atoi(optarg); - if (max_stack_padding >= 0) - pn_options->setMaxStackPadding(max_stack_padding); - break; - } - case RECURSIVE_MIN_STACK_PAD_OPTION: - { - int recursive_min_stack_padding = atoi(optarg); - if (recursive_min_stack_padding >= 0) - pn_options->setRecursiveMinStackPadding(recursive_min_stack_padding); - break; - } - case RECURSIVE_MAX_STACK_PAD_OPTION: - { - int recursive_max_stack_padding = atoi(optarg); - if (recursive_max_stack_padding >= 0) - pn_options->setRecursiveMaxStackPadding(recursive_max_stack_padding); - break; - } - case DOUBLE_THRESHOLD_OPTION: - { - const auto double_threshold = atoi(optarg); - pn_options->setDoubleThreshold(double_threshold); - break; - } - - case SHOULD_DOUBLE_FRAME_SIZE_OPTION: - { - if(strcasecmp("true",optarg)==0) - pn_options->setShouldDoubleFrameSize(true); - else if(strcasecmp("false",optarg)==0) - pn_options->setShouldDoubleFrameSize(false); - else - { - cout<<"Error: should_double_frame_size option needs to be 'true' or 'false': found "<<optarg<<endl; - usage(); - exit(1); - } - break; - } - case SELECTIVE_CANARIES_OPTION: - { - string file=optarg; - ifstream in(file.c_str()); - string word; - - if(!in) - { - cout << "Cannot open input file: "<<file<<endl;; - usage(); - exit(1); - } - - while(in>>word) - pn_options->addSelectiveCanaryFunction(word); - - break; - } - case SET_RANDOM_SEED: - { - int the_seed=atoi(optarg); - cout<<"Setting random seed to: "<<dec<<the_seed<<endl; - pn_options->setRandomSeed(the_seed); - break; - } - case SET_CANARY_VALUE: - { - int the_val=strtoul(optarg, NULL, 0); - cout<<"Setting canary value to: 0x"<<hex<<the_val<<endl; - pn_options->setCanaryValue(the_val); - break; - } - case SET_FLOATING_CANARY_OPTION: - { - floating_canary = true; - break; - } - case SET_DETECTION_POLICY_OPTION: - { - if(strcasecmp("exit",optarg)==0) - pn_options->setDetectionPolicy(P_CONTROLLED_EXIT); - else if(strcasecmp("halt",optarg)==0) - pn_options->setDetectionPolicy(P_HARD_EXIT); - else - pn_options->setDetectionPolicy(P_CONTROLLED_EXIT); - break; - } - case SET_DETECTION_EXIT_CODE_OPTION: - { - auto exit_code=(unsigned)atoi(optarg); - assert(exit_code >= 0 && exit_code <= 255); - pn_options->setDetectionExitCode(exit_code); - break; - } - - case '?': - { - //error message already printed by getopt_long - //TODO: exit? - usage(); - break; - } - default: - { - //TODO: invalid argument, and print usage - usage(); - } - } - } - - // sanity check padding - assert(pn_options->getMaxStackPadding() >= pn_options->getMinStackPadding()); - assert(pn_options->getRecursiveMaxStackPadding() >= pn_options->getRecursiveMinStackPadding()); - - cout << "min_stack_padding: " << pn_options->getMinStackPadding() << endl; - cout << "max_stack_padding: " << pn_options->getMaxStackPadding() << endl; - cout << "recursive_min_stack_padding: " << pn_options->getRecursiveMinStackPadding() << endl; - cout << "recursive_max_stack_padding: " << pn_options->getRecursiveMaxStackPadding() << endl; - cout << "canaries: " << pn_options->getDoCanaries() << endl; - - //setup the interface to the sql server - pqxxDB_t pqxx_interface; - BaseObj_t::SetInterface(&pqxx_interface); - - try - { - // read the variant ID using variant id number = atoi(argv[1]) - pidp=new VariantID_t(progid); - - // verify that we read it correctly. - assert(pidp->IsRegistered()==true); - } - catch (DatabaseError_t pnide) - { - cout<<"Unexpected database error: "<<pnide<<endl; - exit(-1); - } - - set<std::string> blackListOfFunctions; - blackListOfFunctions = getFunctionList(blacklist_file); - set<std::string> onlyValidateFunctions; - onlyValidateFunctions = getFunctionList(only_validate); - map<string, map<string,double> > coverage_map = getCoverageMap(coverage_file,p1threshold); - - cout<<"P1threshold parsed = "<<p1threshold<<endl; - - try - { - PNTransformDriver transform_driver(pidp,BED_script, &pqxx_interface); - - cout << " detection_policy: " << pn_options->getDetectionPolicy() << endl; - cout << "detection_exit_code: " << pn_options->getDetectionExitCode() << " only active if controlled exit specified" << endl; - - transform_driver.SetMitigationPolicy(pn_options->getDetectionPolicy()); - transform_driver.SetDetectionExitCode(pn_options->getDetectionExitCode()); - - OffsetInference *offset_inference = new OffsetInference(); - - //TODO: hard coding the file in for now. - ifstream annotationFile("a.ncexe.infoannot", ifstream::in); - assert(annotationFile.is_open()); - - AnnotationBoundaryGenerator *abgen = new AnnotationBoundaryGenerator(new MEDS_AnnotationParser(annotationFile)); - - PrecedenceBoundaryInference *aggressive_memset_inference = new PrecedenceBoundaryInference(offset_inference,abgen); - - DirectOffsetInference *direct_offset_inference = new DirectOffsetInference(offset_inference); - ScaledOffsetInference *scaled_offset_inference = new ScaledOffsetInference(offset_inference); - P1Inference *p1 = new P1Inference(offset_inference); - PrecedenceBoundaryInference *conservative_memset_inference = new PrecedenceBoundaryInference(p1, abgen); - - //Add new boundary inferences here - - //TODO: in addition to a hierarchy there should be equivalence classes, a failure in one member, is a failure for all. - - transform_driver.AddInference(aggressive_memset_inference); - transform_driver.AddInference(offset_inference,1); - transform_driver.AddInference(direct_offset_inference,1); - transform_driver.AddInference(scaled_offset_inference,1); - transform_driver.AddInference(conservative_memset_inference,1); - transform_driver.AddInference(p1,2); - - transform_driver.AddBlacklist(blackListOfFunctions); - transform_driver.AddOnlyValidateList(onlyValidateFunctions); - transform_driver.SetDoCanaries(pn_options->getDoCanaries()); - transform_driver.SetDoFloatingCanary(floating_canary); - transform_driver.SetDoAlignStack(align_stack); - transform_driver.SetCoverageMap(coverage_map); - transform_driver.SetCoverageThreshold(p1threshold); - transform_driver.SetProtectSharedObjects(shared_object_protection); - transform_driver.SetWriteStackIrToDb(do_ground_truth); - - //The passed in level must match a level that exists - if(! validate_p1) - transform_driver.SetNoValidationLevel(2); - - //Produce SLX transformation - transform_driver.GenerateTransforms(); - - pqxx_interface.Commit(); - } - catch (DatabaseError_t pnide) - { - cout<<"Unexpected database error: "<<pnide<<endl; - exit(-1); - } - -//TODO: Catch all other exceptions? - - return 0; -} diff --git a/tools/transforms/PNRange.cpp b/tools/transforms/PNRange.cpp deleted file mode 100644 index e94ec9ed3..000000000 --- a/tools/transforms/PNRange.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "PNRange.hpp" -#include <sstream> - -using namespace std; - -/* - PNRange::PNRange(int displacement_offset, unsigned int padding_size, const Range &range) : Range(range) - { - this->displacement_offset = displacement_offset; - this->padding_size = padding_size; - - new_size = size + padding_size; - } -*/ - -PNRange::PNRange(const PNRange &range) : Range(range) -{ - padding_size = range.padding_size; - displacement = range.displacement; -} - -PNRange::PNRange(const Range &range) : Range(range) -{ - padding_size = 0; - displacement = 0; -} - - -PNRange::PNRange() : Range() -{ - displacement = 0; - padding_size = 0; -} -unsigned int PNRange::GetPaddingSize() const -{ - return padding_size; -} - -int PNRange::GetDisplacement() const -{ - return displacement; -} - -void PNRange::SetDisplacement(int offset) -{ - displacement = offset; -} - -void PNRange::SetPaddingSize(unsigned int pad_size) -{ - padding_size = pad_size; -} - -void PNRange::Reset() -{ - padding_size = 0; - displacement = 0; -} - -string PNRange::ToString() const -{ - stringstream ss; - - ss<<Range::ToString()<<" Padding = "<<padding_size<<" Displacement = "<<displacement; - - return ss.str(); -} - - diff --git a/tools/transforms/PNRange.hpp b/tools/transforms/PNRange.hpp deleted file mode 100644 index 1665d051a..000000000 --- a/tools/transforms/PNRange.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __PNRANGE -#define __PNRANGE - -#include "Range.hpp" -#include <string> - -class PNRange : public Range -{ -protected: - int displacement; //add displacement to offset to get displaced base - unsigned int padding_size; -public: - PNRange(const PNRange &range); - PNRange(const Range &range); - PNRange(); - virtual ~PNRange() {} - virtual unsigned int GetPaddingSize() const; - virtual int GetDisplacement() const; - virtual void SetDisplacement(int offset); - virtual void SetPaddingSize(unsigned int pad_size); - virtual std::string ToString() const; - virtual void Reset(); - -}; - -#endif diff --git a/tools/transforms/PNRegularExpressions.cpp b/tools/transforms/PNRegularExpressions.cpp deleted file mode 100644 index f3be50c52..000000000 --- a/tools/transforms/PNRegularExpressions.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "PNRegularExpressions.hpp" -#include <cstdio> -#include <cstdlib> -#include <string.h> -#include <assert.h> -#include "libIRDB-core.hpp" - -using namespace std; - -#define FIRN(s) fill_in_reg_name((s)) -#define HEXNUM "([0][xX][0123456789abcdefABCDEF]+)|([01234356789]+)" -#define REGSTRING "[[:blank:]]*[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]+[[:blank:]]*" -#define SCALE "[[:blank:]]*[*][[:blank:]]*[1248][[:blank:]]*" -#define WS "[[:blank:]]*" - -static char* fill_in_reg_name(const char *instring) -{ - - int width=libIRDB::FileIR_t::GetArchitectureBitWidth(); - static char outstring[200]; - - assert(strlen(instring)<sizeof(outstring)); - - strcpy(outstring,instring); - - char* p=outstring; - while((p=strstr(p,"%"))!=NULL) - { - assert(*p=='%'); - assert(*(p+1)=='b' || *(p+1)=='s'); // sanity check that it's %sp or %bp - assert(*(p+2)=='p'); - if(width==32) - *p='e'; - else if(width==64) - *p='r'; - else - assert(0),abort(); - } - return outstring; -} - -//TODO: for now the constructor exits the program in compilation of the regex fails -//Is throwing an exception a better option? -PNRegularExpressions::PNRegularExpressions() -{ - int errcode; - - // match "and esp, *" - if (regcomp(®ex_and_esp, FIRN("[[:blank:]]*and[[:blank:]]+%sp[[:blank:]]*,[[:blank:]]*(.+)[[:blank:]]*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for and esp to compile\n"); - exit(1); - } - // match "ret" - if (regcomp(®ex_ret, FIRN("^ret[[:blank:]]*$"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for ret failed to compile\n"); - exit(1); - } - - /* match lea <anything> dword [<stuff>]*/ - if (regcomp(®ex_lea_hack, FIRN("(.*lea.*,.*)dword(.*)"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for lea hack failed to compile\n"); - exit(1); - } - - // match "[esp]" - if(regcomp(®ex_esp_only, FIRN(".*\\[(%sp)\\].*"),REG_EXTENDED | REG_ICASE) !=0) - { - fprintf(stderr,"Error: regular expression for esp scaled addresses failed\n"); - exit(1); - } - - // match "[esp+reg*scale+disp]" - if(regcomp(®ex_esp_scaled, FIRN(".*\\[%sp" WS "[+].*[+](.+)\\].*"),REG_EXTENDED | REG_ICASE) !=0) - { - fprintf(stderr,"Error: regular expression for esp scaled addresses failed\n"); - exit(1); - } - if((errcode=regcomp(®ex_lea_rsp, FIRN(".*lea.*\\[.*%sp.*(" HEXNUM ").*\\].*"),REG_EXTENDED | REG_ICASE)) !=0) - { - char buf[1000]; - regerror(errcode,®ex_lea_rsp,buf,sizeof(buf)); - fprintf(stderr,"Error: regular expression for regex_lea_rsp failed, code: %s\n", buf); - exit(1); - } - if((errcode=regcomp(®ex_esp_scaled_nodisp, FIRN(".*\\[%sp" WS "[+]" WS "" REGSTRING SCALE "(\\]).*"),REG_EXTENDED | REG_ICASE)) !=0) - { - char buf[1000]; - regerror(errcode,®ex_esp_scaled_nodisp,buf,sizeof(buf)); - fprintf(stderr,"Error: regular expression for esp scaled w/o displacement failed, code: %s\n", buf); - exit(1); - } - - if(regcomp(®ex_ebp_scaled,FIRN(".*\\[%bp" WS "[+]" WS ".*[-](.+)\\].*"),REG_EXTENDED | REG_ICASE) !=0) - { - fprintf(stderr,"Error: regular expression for ebp scaled addresses failed\n"); - exit(1); - } - - if((errcode=regcomp(®ex_esp_direct, FIRN(".*\\[%sp" WS "[+]" WS "(" HEXNUM ")\\].*"),REG_EXTENDED | REG_ICASE)) !=0) - { - char buf[1000]; - regerror(errcode,®ex_esp_direct,buf,sizeof(buf)); - fprintf(stderr,"Error: regular expression for esp direct addresses failed, code: %s\n",buf); - exit(1); - } - - if((errcode=regcomp(®ex_esp_direct_negoffset,FIRN(".*\\[%sp" WS "[-]" WS "(" HEXNUM ")\\].*"),REG_EXTENDED | REG_ICASE)) !=0) - { - char buf[1000]; - regerror(errcode,®ex_esp_direct_negoffset,buf,sizeof(buf)); - fprintf(stderr,"Error: regular expression for esp direct addresses failed, code: %s\n",buf); - exit(1); - } - - - if(regcomp(®ex_ebp_direct,FIRN(".*\\[%bp" WS "[-]" WS "(" HEXNUM ")\\].*"),REG_EXTENDED | REG_ICASE) !=0) - { - fprintf(stderr,"Error: regular expression for esp direct addresses failed\n"); - exit(1); - } - - // stack allocation: match sub esp , K - if (regcomp(®ex_stack_alloc, FIRN("[[:blank:]]*sub[[:blank:]]+%sp[[:blank:]]*,[[:blank:]]*(.+)[[:blank:]]*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for <sub esp, K> failed to compile\n"); - exit(1); - } - - // stack deallocation: match add esp , K - if (regcomp(®ex_stack_dealloc, FIRN("[[:blank:]]*add[[:blank:]]+%sp[[:blank:]]*,[[:blank:]]*(.+)[[:blank:]]*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for <add esp, K> failed to compile\n"); - exit(1); - } - - // stack deallocation that does not use an offset - if (regcomp(®ex_stack_dealloc_implicit, FIRN("([[:blank:]]*mov[[:blank:]]+%sp[[:blank:]]*,[[:blank:]]*%bp[[:blank:]]*)|([[:blank:]]*leave[[:blank:]]*)|([[:blank:]]*lea[[:blank:]]*%sp[[:blank:]]*,[[:blank:]]*\\[%bp[-].*\\][[:blank:]]*)"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for stack_dealloc_implicit failed to compile\n"); - exit(1); - } - - if (regcomp(®ex_push_ebp, FIRN(".*push[[:blank:]]+(%bp).*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for push ebp failed to compile\n"); - exit(1); - } - - if (regcomp(®ex_save_fp, FIRN(".*mov[[:blank:]]+(%bp)[[:blank:]]*,[[:blank:]]*(%sp).*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for save fp failed to compile\n"); - exit(1); - } - - if (regcomp(®ex_push_anything, FIRN(".*push[[:blank:]]+(.*)"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for push (anything) failed to compile\n"); - exit(1); - } - - //looking for scaled accesses using ebp as the index - //eg. [ecx + ebp*1 - 0x21] - //Unlike other expressions, there are two pattern matches here - //the first is the scaling factor (if one exists), the second is the - //offset. - if (regcomp(®ex_scaled_ebp_index, FIRN(".*\\[.*[+]" WS "%bp[*]?(.*)[-](.+)\\].*"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for scaled ebp index failed to compile\n"); - exit(1); - } - - if (regcomp(®ex_call, FIRN("^call (.*)$"), REG_EXTENDED | REG_ICASE) != 0) - { - fprintf(stderr,"Error: regular expression for call failed to compile\n"); - exit(1); - } - - - if((errcode=regcomp(®ex_add_rbp,FIRN("add (" REGSTRING "), *%bp *"),REG_EXTENDED | REG_ICASE)) !=0) - { - char buf[1000]; - regerror(errcode,®ex_add_rbp,buf,sizeof(buf)); - fprintf(stderr,"Error: regular expression for regex_add_rbp failed, code: %s\n",buf); - exit(1); - } - - - -} diff --git a/tools/transforms/PNRegularExpressions.hpp b/tools/transforms/PNRegularExpressions.hpp deleted file mode 100644 index 91439a72e..000000000 --- a/tools/transforms/PNRegularExpressions.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __PNREGULAREXPRESSIONS -#define __PNREGULAREXPRESSIONS -#include <regex.h> - -class PNRegularExpressions -{ -public: - PNRegularExpressions(); - - regex_t regex_save_fp; - regex_t regex_ret; - regex_t regex_esp_scaled; - regex_t regex_esp_scaled_nodisp; - regex_t regex_ebp_scaled; - regex_t regex_esp_direct; - regex_t regex_esp_direct_negoffset; - regex_t regex_ebp_direct; - regex_t regex_stack_alloc; - regex_t regex_stack_dealloc; - regex_t regex_stack_dealloc_implicit; - regex_t regex_lea_hack; - regex_t regex_lea_rsp; - regex_t regex_esp_only; - regex_t regex_push_ebp; - regex_t regex_push_anything; - regex_t regex_and_esp; - regex_t regex_scaled_ebp_index; - regex_t regex_call; - regex_t regex_add_rbp; - - static const int MAX_MATCHES = 10; -}; - -#endif diff --git a/tools/transforms/PNStackLayout.cpp b/tools/transforms/PNStackLayout.cpp deleted file mode 100644 index 33b76205c..000000000 --- a/tools/transforms/PNStackLayout.cpp +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "PNStackLayout.hpp" -#include <cstdlib> -#include <algorithm> -#include <cassert> -#include <sstream> -#include <ctime> -#include "globals.h" -#include <libIRDB-core.hpp> - -//TODO: debug use only -#include <iostream> - -using namespace std; - -//TODO: so far it has been assumed that you insert then padd and shuffle -//but if a new element is added after shuffling or padding, what should I do? - -//TODO: we do not handle negative offsets relative to esp. These offsets will not be inserted -//into the layout, however if this case is encountered, offsets are changed here to avoid -//complications. This is primarily a problem with EBP offsets extending beyond the stack -//pointer. I have not observed this so far, but if this does happen, upon requesting a new -//offset the amount passed the stack pointer is calculated, and added to the new frame -//size to give a new EBP relative offset. ESP relative offsets require to adjustments - -static bool CompareRangeBaseOffset(PNRange *a, PNRange *b) -{ - return (a->GetOffset() < b->GetOffset()); -} - -static bool CompareRangeDisplacedOffset(PNRange *a, PNRange *b) -{ - return ((a->GetOffset()+a->GetDisplacement()) < (b->GetOffset()+b->GetDisplacement())); -} - - -unsigned int PNStackLayout::GetRandomPadding(unsigned int obj_size) -{ - int min,max; - - min = pn_options->getMinStackPadding(); - max = pn_options->getMaxStackPadding(); - - if(stack_layout.is_recursive) - { - min = pn_options->getRecursiveMinStackPadding(); - max = pn_options->getRecursiveMaxStackPadding(); - } - - - int pad = (rand() % (max+1-min)) + min; - if(isaligned) - { -//TODO: if previously padded, and not aligned, this will not gurantee alignment, so -//I should probably pass the memory object itself, so I can use all that information. - pad = pad + obj_size; - pad = pad - (pad % ALIGNMENT_BYTE_SIZE); - pad = pad - obj_size; - } - - //Finally, add padding equivalent to the original stack frame size - //this helps protect against very large overflows/underflows. - //align the original stack frame if not aligned, adding more bytes if necessary - //TODO: should this be scaled down if the func is recursive? - - - - if(pn_options->getShouldDoubleFrameSize() && obj_size < (uintptr_t)pn_options->getDoubleThreshold()) - { - //if the original frame size is not aligned, then add as many bytes as necessary to align it - //for example, if 3 bytes over alignment, and the alignment stride is 8, then add 8 - 3, or 5 bytes. - pad += (ALIGNMENT_BYTE_SIZE - (stack_layout.frame_alloc_size % ALIGNMENT_BYTE_SIZE)); - pad += stack_layout.frame_alloc_size; - } - - return pad; -} - -//TODO: a ToString function - -//TODO: return value if insert in out args region? - -//TODO: use of unsigned ints?? While making it easier here, it is prone to type errors by the user - -//TODO: negative offsets? - - -PNStackLayout::PNStackLayout(StackLayout stack_layout, libIRDB::Function_t* func) : stack_layout(stack_layout) - -{ - ALIGNMENT_BYTE_SIZE=libIRDB::FileIR_t::GetArchitectureBitWidth()/sizeof(int); - //PNTransformDriver sets up the seed, I need a better way of handling this - //but for now assume it has been properly seeded. - //srand(time(NULL)); - - this->stack_layout = stack_layout; - isPadded = false; - isShuffled = false; - altered_alloc_size = stack_layout.frame_alloc_size; - - for(unsigned int i=0;i<stack_layout.mem_objects.size();i++) - { - PNRange *pn_obj = new PNRange(stack_layout.mem_objects[i]); - mem_objects.push_back(pn_obj); - } - - assert(func); - base_id = func->GetBaseID(); - entry_id = 0; - if(func->GetEntryPoint()!=NULL) - entry_id=func->GetEntryPoint()->GetBaseID(); - - m_func = func; -} - -PNStackLayout::PNStackLayout(const PNStackLayout &stack_layout): stack_layout(stack_layout.stack_layout) -{ - ALIGNMENT_BYTE_SIZE=libIRDB::FileIR_t::GetArchitectureBitWidth()/sizeof(int); - pn_layout_name = stack_layout.pn_layout_name; - isPadded = stack_layout.isPadded; - isShuffled = stack_layout.isShuffled; - isaligned = stack_layout.isaligned; - this->stack_layout = stack_layout.stack_layout; - altered_alloc_size = stack_layout.altered_alloc_size; - - for(unsigned int i=0;i<stack_layout.mem_objects.size();i++) - { - PNRange *pn_obj = new PNRange(*stack_layout.mem_objects[i]); - mem_objects.push_back(pn_obj); - } - - base_id = 0; - entry_id = 0; - m_func = NULL; -} - -PNStackLayout::~PNStackLayout() -{ - for(unsigned int i=0;i<mem_objects.size();i++) - { - delete mem_objects[i]; - } -} - -//Shuffle generates new displacement_offset values for each PNRange which represents -//a logical shuffling, it does not change the ordering of the mem_objects data structure. -void PNStackLayout::Shuffle() -{ - if(!IsShuffleSafe()) - return; - - //TODO: this function can be optimized to not randomize the mem_objects vector then resort - - int lowest_address = mem_objects[0]->GetDisplacement() + mem_objects[0]->GetOffset(); - - //Find the lowest displacement offset - //This is in case the layout has been padded before shuffling. - //In this case, the element randomly selected to be the first element - //will be placed at the lowest displaced offset, rather than at 0. If 0 - //were used this would effectively remove any padding between 0 and the - //first memory object. - for(unsigned int i=1;i<mem_objects.size();i++) - { - int next_offset = mem_objects[i]->GetDisplacement() + mem_objects[i]->GetOffset(); - if(lowest_address > next_offset) - lowest_address = next_offset; - } - - int random_index; - int start_index = 0; - - //if there are out args, the first element of the passed in vector - //is considered the out args and will not be shuffled - if(stack_layout.has_out_args) - { - start_index = 1; - } - - //Shuffle all regions except the lowest region if there are out args - for(int i=start_index;i<((int)mem_objects.size())-1;i++) - { - //TODO: There may be a bias here - random_index = i + (rand() % (mem_objects.size() - i)); - - assert(random_index>=i && random_index<(int)mem_objects.size()); - - PNRange *swap = mem_objects[i]; - mem_objects[i] = mem_objects[random_index]; - mem_objects[random_index] = swap; - } - - //If there aren't any out args, then the element at the lowest displaced - //address (displacement + offset) is considered the base address, - //if not previously padded this should be zero, in which case the - //new displacment will be 0. - //No check is needed for out args since the lowest_address should be 0 - //if there are out args - mem_objects[0]->SetDisplacement(lowest_address-mem_objects[0]->GetOffset()); - - //generate new base addresses for each region - for(unsigned int i=1;i<mem_objects.size();i++) - { - //Displacement = New Location - original location - //Displacement + offset = new address - mem_objects[i]->SetDisplacement((mem_objects[i-1]->GetDisplacement()+mem_objects[i-1]->GetOffset() + - mem_objects[i-1]->GetSize() + mem_objects[i-1]->GetPaddingSize()) - - mem_objects[i]->GetOffset()); - } - - //At this bound the mem_objects data structure has been randomized, sort by original base offset - sort(mem_objects.begin(),mem_objects.end(), CompareRangeBaseOffset); - - isShuffled = true; - - if(verbose_log) - { - cerr<<"PNStackLayout: Shuffle(): "<<ToString()<<endl; - for(unsigned int i=0;i<mem_objects.size();i++) - { - cerr<<"\tOffset = "<<mem_objects[i]->GetOffset()<<" Size = "<<mem_objects[i]->GetSize()<< - " Padding = "<<mem_objects[i]->GetPaddingSize()<<" displ = "<<mem_objects[i]->GetDisplacement()<<endl; - } - } -} - -PNStackLayout PNStackLayout::GetCanaryLayout() const -{ - PNStackLayout new_layout = *(this); - - new_layout.AddCanaryPadding(); - - return new_layout; -} - -//Adds padding for canaries between objects, or if padding -//exists, does nothing. -void PNStackLayout::AddCanaryPadding() -{ - // if(!IsPaddingSafe()) - // return; -//TODO: I should throw an exception, but for now I will just assert false if -//the layout is not padding safe but canary padding is requested. - if(!IsPaddingSafe()) - assert(false); - - -//TODO: I need to check the padding for each variable, but for now, I will assume -//if the layout is padded, it is padded enough for canaries - if(IsPadded()) - return; - - unsigned int size = 8; - -// Twitcher adds another guard -#ifdef TWITCHER_GUARD - size += 8; -#endif - - sort(mem_objects.begin(),mem_objects.end(),CompareRangeDisplacedOffset); - //counts the additional padding added, does not take into consideration previous padding - unsigned int total_padding =0; - - - unsigned int curpad = size; - total_padding += curpad; - mem_objects[0]->SetPaddingSize(curpad+mem_objects[0]->GetPaddingSize()); - - for(unsigned int i=1;i<mem_objects.size();i++) - { - mem_objects[i]->SetDisplacement(total_padding+mem_objects[i]->GetDisplacement()); - curpad = size; - total_padding += curpad; - mem_objects[i]->SetPaddingSize(curpad+mem_objects[i]->GetPaddingSize()); - } - - sort(mem_objects.begin(),mem_objects.end(),CompareRangeBaseOffset); - - //the altered frame size is the size of the old altered frame size plus the additional - //padding added. - altered_alloc_size += total_padding; - - isPadded = true; - - if(verbose_log) - { - cerr<<"PNStackLayout: AddPadding(): "<<ToString()<<endl; - for(unsigned int i=0;i<mem_objects.size();i++) - { - cerr<<"\tOffset = "<<mem_objects[i]->GetOffset()<<" Size = "<<mem_objects[i]->GetSize()<< - " Padding = "<<mem_objects[i]->GetPaddingSize()<<" displ = "<<mem_objects[i]->GetDisplacement()<<endl; - } - } -} - - -/* - * roundUp - round number up to the nearest multiple . multiple must be power of 2. - */ -int roundUp(int numToRound, int multiple) -{ - assert((multiple & (multiple-1))==0); - return (numToRound + multiple - 1) & ~(multiple - 1); -} - -/* - Add padding between variables in the stack frame. If there are no out args, - padding is added below the lowest variable, but only if the stack frame - is not a p1 reduction. Hypotheses of the out args region are sometimes - incorrect. If the out args region is not identified, adding padding - below the lowest variable will result in all transforms incorrectly - transforming the stack. To avoid this, if the most conservative layout is found - (p1), no padding is added below the lowest variable. This way at least p1 - can transform these stack frames. - - Previous padding is added to, not removed. Padding may be added before or after - shuffling. -*/ -void PNStackLayout::AddRandomPadding(bool isaligned) -{ - if(!IsPaddingSafe()) - return; - - this->isaligned = isaligned; - - if(verbose_log) - cerr<<"ALIGNMENT IS "<<isaligned<<endl; - - sort(mem_objects.begin(),mem_objects.end(),CompareRangeDisplacedOffset); - //counts the additional padding added, does not take into consideration previous padding - unsigned int total_padding = GetRandomPadding(0); - - //if there is no out args region, add padding below the memory object at esp - // if(!has_out_args) - //Only add padding from below the memory object at esp if there are no out args and - //the layout does not reduce to p1. The reasonf or including the check for a reduction - //to p1 was added because some times the out args is not found, causing all transforms - //to fail. For p1, padding from below doesn't add much anyway, so removing this - //diversification allows for a transform even if the out args have been incorrectly - //identified. - if(!stack_layout.has_out_args && mem_objects.size() != 1) - mem_objects[0]->SetDisplacement((int)total_padding+mem_objects[0]->GetDisplacement()); - else - { - mem_objects[0]->SetDisplacement(0); - total_padding = 0; - } - - unsigned int curpad = GetRandomPadding(mem_objects[0]->GetSize()); - total_padding += curpad; - mem_objects[0]->SetPaddingSize(curpad+mem_objects[0]->GetPaddingSize()); - - for(unsigned int i=1;i<mem_objects.size();i++) - { - mem_objects[i]->SetDisplacement(total_padding+mem_objects[i]->GetDisplacement()); - curpad = GetRandomPadding(mem_objects[i]->GetSize()); - total_padding += curpad; - mem_objects[i]->SetPaddingSize(curpad+mem_objects[i]->GetPaddingSize()); - } - - - sort(mem_objects.begin(),mem_objects.end(),CompareRangeBaseOffset); - - int last=mem_objects.size()-1; - int last_pad=mem_objects[last]->GetPaddingSize(); - if(verbose_log) - { - cerr<<"Last object size=0x"<<hex<<last_pad<<endl; - cerr<<"altered_aloc_size=0x"<<hex<<altered_alloc_size<<endl; - cerr<<"total_padding=0x"<<hex<<total_padding<<endl; - } - - int new_total_padding_size=roundUp(total_padding,ALIGNMENT_BYTE_SIZE); - mem_objects[last]->SetPaddingSize(mem_objects[last]->GetPaddingSize()+new_total_padding_size-total_padding); - total_padding=new_total_padding_size; - - //the altered frame size is the size of the old altered frame size plus the additional - //padding added. - altered_alloc_size += total_padding; - - isPadded = true; - - if(verbose_log) - { - cerr<<"PNStackLayout: AddPadding(): "<<ToString()<<endl; - for(unsigned int i=0;i<mem_objects.size();i++) - { - cerr<<"\tOffset = "<<mem_objects[i]->GetOffset()<<" Size = "<<mem_objects[i]->GetSize()<< - " Padding = "<<mem_objects[i]->GetPaddingSize()<<" displ = "<<mem_objects[i]->GetDisplacement()<<endl; - } - } -} - -//Basically this is the same proces as the random padding function, but the padding -//is determined by not by random, but by the location of each variable. -void PNStackLayout::AddDMZPadding() -{ - sort(mem_objects.begin(),mem_objects.end(),CompareRangeDisplacedOffset); - //counts the additional padding added, does not take into consideration previous padding - unsigned int total_padding = stack_layout.frame_alloc_size; - - //if there is no out args region, add padding below the memory object at esp - // if(!has_out_args) - //Only add padding from below the memory object at esp if there are no out args and - //the layout does not reduce to p1. The reasonf or including the check for a reduction - //to p1 was added because some times the out args is not found, causing all transforms - //to fail. For p1, padding from below doesn't add much anyway, so removing this - //diversification allows for a transform even if the out args have been incorrectly - //identified. - if(!stack_layout.has_out_args && mem_objects.size() == 1) - mem_objects[0]->SetDisplacement((int)total_padding+mem_objects[0]->GetDisplacement()); - else - { - mem_objects[0]->SetDisplacement(0); - total_padding = 0; - } - - unsigned int curpad = (stack_layout.frame_alloc_size-mem_objects[0]->GetOffset())-mem_objects[0]->GetSize(); - total_padding += curpad; - mem_objects[0]->SetPaddingSize(curpad+mem_objects[0]->GetPaddingSize()); - - for(unsigned int i=1;i<mem_objects.size();i++) - { - mem_objects[i]->SetDisplacement(total_padding+mem_objects[i]->GetDisplacement()); - curpad = (stack_layout.frame_alloc_size-mem_objects[i]->GetOffset())-mem_objects[i]->GetSize(); - total_padding += curpad; - mem_objects[i]->SetPaddingSize(curpad+mem_objects[i]->GetPaddingSize()); - } - - sort(mem_objects.begin(),mem_objects.end(),CompareRangeBaseOffset); - - //the altered frame size is the size of the old altered frame size plus the additional - //padding added. - altered_alloc_size += total_padding; - - isPadded = true; - - - if(verbose_log) - { - cerr<<"PNStackLayout: AddDMZPadding(): "<<ToString()<<endl; - for(unsigned int i=0;i<mem_objects.size();i++) - { - cerr<<"\tOffset = "<<mem_objects[i]->GetOffset()<<" Size = "<<mem_objects[i]->GetSize()<< - " Padding = "<<mem_objects[i]->GetPaddingSize()<<" displ = "<<mem_objects[i]->GetDisplacement()<<endl; - } - } -} - - -bool PNStackLayout::IsPadded() const -{ - return isPadded; -} - -bool PNStackLayout::IsShuffled() const -{ - return isShuffled; -} - - -unsigned int PNStackLayout::GetOriginalAllocSize() const -{ - return stack_layout.frame_alloc_size; -} - -unsigned int PNStackLayout::GetAlteredAllocSize() const -{ - return altered_alloc_size; -} - -unsigned int PNStackLayout::GetSavedRegsSize() const -{ - return stack_layout.saved_regs_size; -} - -PNRange* PNStackLayout::GetClosestRangeEBP(int loc) const -{ - //The size of the saved regs must be taken into consideration when transforming - //the EBP offset to an esp relative offset - return GetClosestRangeESP(((int)stack_layout.frame_alloc_size+(int)stack_layout.saved_regs_size) - loc); -} - -//Finds the range whose base_offset is the closest to -//loc without going over. -//If no match can be found a negative offset may have been -//passed, the algorithm failed, or the number of mem_objects -//is 0. In this case a null pointer is returned; -PNRange* PNStackLayout::GetClosestRangeESP(int loc) const -{ - if(verbose_log) - cerr<<"PNstackLayout: GetClosestRangeESP(): Seaching for ESP Offset "<<loc<<endl; - - if(loc >= (int)stack_layout.frame_alloc_size) - { - if(verbose_log) - { - //For now don't do anything if the loc is greater than the frame size - cerr<<"PNStackLayout: GetClosestRangeESP(): loc >= frame_alloc_size, Returning NULL"<<endl; - } - return NULL; - } - - if(loc < 0) - { - if(verbose_log) - cerr<<"PNStackLayout: GetClosestRangeESP(): loc < 0 ("<<loc<<"), Returning NULL"<<endl; - return NULL; - } - - int index = stack_layout.GetClosestIndex(loc); - - if(index < 0) - { - if(verbose_log) - cerr<<"PNStackLayout: GetClosestRangeESP(): Could Not Find Range, Returning NULL"<<endl; - return NULL; - } - - if(verbose_log) - cerr<<"PNStackLayout: GetClosestRangeESP(): Found range "<<mem_objects[index]->ToString()<<endl; - - return mem_objects[index]; -} - -unsigned int PNStackLayout::GetNumberOfMemoryObjects() const -{ - return mem_objects.size(); -} - -string PNStackLayout::ToString() const -{ - stringstream ss; - - ss<<"Layout = "<<stack_layout.layout_name + "; Function = "<< - stack_layout.function_name <<"; Frame Alloc Size = "<<stack_layout.frame_alloc_size<<" Altered Frame Size ="<< - altered_alloc_size<<" Saved Regs Size = "<<stack_layout.saved_regs_size<<"; Out Args Size = "<< - stack_layout.out_args_size<<"; Number of Memory Objects = "<< mem_objects.size()<<"; Padded = "; - - if(isPadded) - ss<<"true"; - else - ss<<"false"; - - ss<<"; Shuffled = "; - - if(isShuffled) - ss<< "true"; - else - ss<<"false"; - - ss<<"; canary_safe = "; - if(this->IsCanarySafe()) - ss<<"true"; - else - ss<<"false"; - - return ss.str(); -} - - -string PNStackLayout::GetLayoutName() const -{ - return stack_layout.layout_name; -} - -string PNStackLayout::GetFunctionName() const -{ - return stack_layout.function_name; -} - - -//A frame can be shuffled if there are two or more variables, not including -//the out arguments region. -bool PNStackLayout::IsShuffleSafe() const -{ - return (mem_objects.size() > 2) || (mem_objects.size() == 2 && !stack_layout.has_out_args); -} - -bool PNStackLayout::IsP1() const -{ - //for now this is actually identical (although negated) to the logic used in IsShuffleSafe() - //however, this might chagne in the future, so I am copying the logic - //from IsShuffleSafe - //For example, I would like to detect if an offset is inferred or actually - //encountered. Padding between the out args and the first variable - //can give the false impression of boundaries. - return !((mem_objects.size() > 2) || (mem_objects.size() == 2 && !stack_layout.has_out_args)); -} - - -unsigned int PNStackLayout::GetOutArgsSize() const -{ - return stack_layout.out_args_size; -} - - -int PNStackLayout::GetNewOffsetESP(int esp_offset) const -{ - int new_offset = esp_offset; - - //If the esp relative address goes above or equal to the frame pointer, esp - //could be accessing incoming args or the saved registers - //(such as fomit-frame-pointer). In this case we simply add - //to the offset the size of the altered frame. - - //TODO: converting stack_layout.frame_alloc_size to int - //check if the size is greater than max int. This should - //never occur though. - if(esp_offset >= (int)stack_layout.frame_alloc_size) - { - if(verbose_log) - cerr<<"PNStackLayout: GetNewOffsetESP: Offset greater than or equal to frame size, adjusting based on new frame size"<<endl; - //Get the number of bytes beyond the stack frame - new_offset = esp_offset-stack_layout.frame_alloc_size; - //add those bytes to the altered stack size - new_offset += altered_alloc_size; - } - else - { - PNRange *closest = GetClosestRangeESP(esp_offset); - - //TODO: I assume no negative ESP offsets, at this point if the esp offset is not found - //then we have an issue in the program, so assert(false) to uncover the problem. - if(closest == NULL) - { - assert(false); - } - if(verbose_log) - cerr<<"PNStackLayout: GetNewOffsetESP: closest displacement = "<<closest->GetDisplacement()<<endl; - - new_offset = closest->GetDisplacement() + esp_offset; - } - - return new_offset; -} - -int PNStackLayout::GetNewOffsetEBP(int ebp_offset) const -{ - - //If the function doesn't use a frame pointer, then do not alter any ebp relative instructions. - if(!HasFramePointer()) - { - return ebp_offset; - } - - //In the event that an ebp relative offset extends beyond the stack pointer - //determine the distance beyond the stack pointer, and return - //the sum of this distance with the new frame size and saved register region size - if(ebp_offset > (int)GetOriginalAllocSize()+(int)GetSavedRegsSize()) - { - if(verbose_log) - cerr<<"PNStackLayout: GetNewOffsetEBP: ebp offset extends passed stack pointer, maintaining relative position to esp"<<endl; - return ebp_offset-(int)GetOriginalAllocSize()+(int)altered_alloc_size; - } - - PNRange *closest = GetClosestRangeEBP(ebp_offset); - - //If no range can be found, since the above check finds - //offsets passed the stack pointer, it is assumed the ebp offset - //refers to a saved register (the space between the frame pointer - //and where local variables start). - //Often ebp relative addresses access saved registeres, if this - //happens, there is no need to do a conversion, as no padding - //is added between EBP and saved registers. The untouched offset - //is returned. - if(closest == NULL) - { - return ebp_offset; - } - - if(verbose_log) - cerr<<"PNStackLayout: GetNewOffsetEBP: closest displacement = "<<closest->GetDisplacement()<<endl; - - int new_offset = ((int)GetOriginalAllocSize() + (int)GetSavedRegsSize() - ebp_offset); - new_offset += closest->GetDisplacement(); - new_offset = ((int)altered_alloc_size + (int)GetSavedRegsSize()) - new_offset; - - return new_offset; -} - -void PNStackLayout::ResetLayout() -{ - isPadded = false; - isShuffled = false; - for(unsigned int i=0;i<mem_objects.size();i++) - { - mem_objects[i]->Reset(); - } -} - -string PNStackLayout::ToMapEntry() const -{ - stringstream ss; - - ss << "" << stack_layout.layout_name << ";" << stack_layout.function_name << ";" << stack_layout.frame_alloc_size << ";" << - altered_alloc_size << ";" << stack_layout.saved_regs_size << ";" << stack_layout.out_args_size << ";" << mem_objects.size() << ";"; - - if(isPadded) - ss << "true"; - else - ss << "false"; - - ss << ";"; - - if(isShuffled) - ss << "true"; - else - ss << "false"; - - ss << ";"; - if(this->IsCanarySafe()) - ss << "true"; - else - ss << "false"; - - ss << ";"; - - if(canaries.size() > 0) - ss << std::hex << canaries[0].canary_val; - else - ss << 0; - - ss << ";"; - /*asj5b - add func id*/ - ss << std::hex << base_id; - ss << ";"; - ss << std::hex << entry_id; - - /* add canary offset */ - ss << ";"; - if(canaries.size() > 0) - ss << std::dec << canaries[0].floating_offset; - else - ss << 0; - - return ss.str(); -} diff --git a/tools/transforms/PNStackLayout.hpp b/tools/transforms/PNStackLayout.hpp deleted file mode 100644 index 1eadcbcf9..000000000 --- a/tools/transforms/PNStackLayout.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __PNSTACKLAYOUT -#define __PNSTACKLAYOUT -#include "PNRange.hpp" -#include "StackLayout.hpp" -#include <string> -#include <vector> -#include <exception> -#include <assert.h> -#include "globals.h" -#include "canary.h" -#include <libIRDB-core.hpp> - -//NOTE: padding adds a value between max and min, plus the frame size -//I believe this was done to protect against a very large buffer -//overflow, but I'm not sure I have the example to demonstrate the -//effectiveness. If I had to guess, I think the example is if the -//attacker is trying to exceed the frame size, and the vulnerable buffer -//is at the bottom of the stack, but moved by us to the top, the -//overflow might exceed our padding and corrupt other stack frames. -//const int MIN_PADDING = 64; -//const int MAX_PADDING = 64; -//const int MAX_PADDING = MIN_PADDING*2; -//const int RECURSIVE_MIN_PADDING = 32; -//const int RECURSIVE_MAX_PADDING = RECURSIVE_MAX_PADDING*2; - - -class PNStackLayout -{ -protected: - int ALIGNMENT_BYTE_SIZE; - std::string pn_layout_name; - bool isPadded; - bool isShuffled; - bool isaligned;//should only be used internally, since I don't know if the raw stack is aligned. - //TODO: Storing pointers here but I did away with pointers in StackLayout since I was worried about - //possible memory leaks. I need pointers to return null, but I can achieve this functionality - //through aliasing. Consider removing the pointers for consistency. - std::vector<PNRange*> mem_objects; - - //NOTE: I chose composition over inheritence here, as I wanted to make it impossible to change the - //layout after a PNStackLayout has been created. The issue was if a new boundary was added - //after the layout had been padded/shuffled/etc, it would cause problems. This is avoided by - //this structure, but it is important to make a deap copy of the passed in stack_layout, which - //is achieved through the copy constructor for StackLayout. - StackLayout stack_layout; - unsigned int altered_alloc_size; - - std::vector<canary> canaries; - libIRDB::db_id_t base_id; - libIRDB::db_id_t entry_id; - - libIRDB::Function_t *m_func; - - virtual void AddCanaryPadding(); - -public: - PNStackLayout(StackLayout stack_layout, libIRDB::Function_t* func); - PNStackLayout(const PNStackLayout &stack_layout); - - virtual ~PNStackLayout(); - - virtual void Shuffle(); - //TODO: the max min and alignment size should also be optionally specified. - virtual void AddRandomPadding(bool isaligned=false); - //Adds on to previous padding and does not change any previous displacement - //changes. If you wish to only add DMZ padding, you must clear any previous - //padding. - //TODO: should I worry about alignment here? - - //DMZ padding is defined as the space between the original variable location - //and the end of the local variable region. The theory is, if the variable - //boundaries are correct, then this region should be untouched from any - //memory access. - virtual void AddDMZPadding(); - virtual bool IsPadded() const; - virtual bool IsShuffled() const; - //Remove any transformations, leaves the PNStackLayout as if the object had just been constructed. - virtual void ResetLayout(); - virtual unsigned int GetNumberOfMemoryObjects() const; - virtual PNRange* GetClosestRangeEBP(int loc) const; - virtual PNRange* GetClosestRangeESP(int loc) const; - virtual libIRDB::Function_t* GetFunction() const { return m_func; } - virtual unsigned int GetOriginalAllocSize() const; - virtual unsigned int GetAlteredAllocSize() const; - virtual unsigned int GetSavedRegsSize() const; - virtual std::string ToString() const; - virtual std::string ToMapEntry() const; - virtual std::string GetLayoutName() const; - virtual std::string GetFunctionName() const; - virtual unsigned int GetOutArgsSize() const; - virtual int GetNewOffsetESP(int ebp_offset) const; - virtual int GetNewOffsetEBP(int ebp_offset) const; - virtual PNStackLayout GetCanaryLayout() const; - virtual std::vector<PNRange*> GetRanges() const {return mem_objects;} - virtual bool IsCanarySafe() const - { - assert(pn_options); - return - stack_layout.is_canary_safe && // detected as safe. - pn_options->getDoCanaries() && // and we're allowed to do canaries. - pn_options->shouldCanaryFunction(stack_layout.GetFunctionName()); // and we're allowed to do canaries on this function - } - virtual bool IsPaddingSafe()const {return stack_layout.is_padding_safe;} - virtual bool IsShuffleSafe() const ; - virtual bool IsP1() const; - virtual bool IsStaticStack()const {return stack_layout.is_static_stack;} - virtual bool HasFramePointer()const{return stack_layout.has_frame_pointer;} - virtual bool DoShuffleValidate()const {return !IsCanarySafe() && IsShuffleSafe();} - //memory leak? - //virtual StackLayout* GetStackLayout() { return new StackLayout(stack_layout); } - - virtual StackLayout GetStackLayout() { return StackLayout(stack_layout); } - - //This previously was a protected func, moved out for TNE, - //to support dynamic array padding, the name is a bit confusing. - virtual unsigned int GetRandomPadding(unsigned int obj_size=0); - - virtual void SetCanaries(std::vector<canary> can_vec) { canaries = can_vec; } - virtual void SetBaseID(int new_id) { base_id = new_id; } - virtual void SetEntryID(int new_id) { entry_id = new_id; } -}; - -#endif diff --git a/tools/transforms/PNStackLayoutInference.hpp b/tools/transforms/PNStackLayoutInference.hpp deleted file mode 100644 index fe16c3eff..000000000 --- a/tools/transforms/PNStackLayoutInference.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __PNSTACKLAYOUTINFERENCE -#define __PNSTACKLAYOUTINFERENCE -#include <libIRDB-core.hpp> -#include <libIRDB-cfg.hpp> -#include "StackLayout.hpp" -#include "PNStackLayout.hpp" -#include <string> -#include <map> - -class PNStackLayoutInference -{ - -public: - virtual ~PNStackLayoutInference(){} - virtual PNStackLayout* GetPNStackLayout(libIRDB::Function_t *func)=0; - virtual std::string GetInferenceName()const=0; -}; - -#endif diff --git a/tools/transforms/PNTransformDriver.cpp b/tools/transforms/PNTransformDriver.cpp deleted file mode 100644 index b4080d143..000000000 --- a/tools/transforms/PNTransformDriver.cpp +++ /dev/null @@ -1,3237 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "PNTransformDriver.hpp" -#include <cassert> -#include <algorithm> -#include <unistd.h> -#include <fstream> -#include <iomanip> -// #include "beaengine/BeaEngine.h" -#include "General_Utility.hpp" -#include "PNIrdbManager.hpp" -#include <cmath> -#include "globals.h" -#include <libIRDB-cfg.hpp> -#include "EhUpdater.hpp" - -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <libgen.h> -#include <sys/types.h> -#include <sys/wait.h> - - -void ignore_result(int /* res */ ) { } - -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - - - -#define MAX_JUMPS_TO_FOLLOW 100000 - -#define ALLOF(s) begin(s), end(s) - -using namespace std; -using namespace libIRDB; - -char* get_current_dir_name(void) -{ - char* pwd = getenv("PWD"); - char tmp[PATH_MAX]; - struct stat a,b; - if (pwd && !stat(".",&a) && !stat(pwd,&b) && - a.st_dev==b.st_dev && a.st_ino==b.st_ino) - return strdup(pwd); - if (getcwd(tmp,sizeof(tmp))) - return strdup(tmp); - return 0; -} - -//TODO: this var is a hack for TNE -extern map<Function_t*, set<Instruction_t*> > inserted_instr; -extern map<Function_t*, set<AddressID_t*> > inserted_addr; - -void sigusr1Handler(int signum); -bool PNTransformDriver::timeExpired = false; - -static Instruction_t* GetNextInstruction(Instruction_t *prev, Instruction_t* insn, Function_t* func); - - -int get_saved_reg_size() -{ - return FileIR_t::GetArchitectureBitWidth()/(sizeof(char)*8); -} - -//TODO: Error message functions? - -//TODO: use of pointers? - -//TODO: Use CFG class for all instruction looping -//TODO: if stack access instruction are encountered before stack allocation, ignore them, after using CFG - -//Used for sorting layotus by number of memory objects in descending order -//TODO: change name to reflect descending order -static bool CompareBoundaryNumbersDescending(PNStackLayout *a, PNStackLayout *b) -{ - return (a->GetNumberOfMemoryObjects() > b->GetNumberOfMemoryObjects()); -} - -static bool CompareValidationRecordAscending(validation_record a, validation_record b) -{ - return (a.layouts[a.layout_index]->GetNumberOfMemoryObjects() < b.layouts[b.layout_index]->GetNumberOfMemoryObjects()); -} - - -PNTransformDriver::PNTransformDriver(VariantID_t *pidp,string BED_script, pqxxDB_t *pqxx_if) : - pn_regex(NULL), pqxx_interface(pqxx_if) -{ - //TODO: throw exception? - assert(pidp != NULL); - - srand(pn_options->getRandomSeed()); - - //TODO: throw exception? - this->pidp = pidp; - orig_progid = pidp->GetOriginalVariantID(); - orig_virp = NULL; - this->BED_script = BED_script; - do_canaries = true; - do_floating_canary = false; - do_align = false; - no_validation_level = -1; - coverage_threshold = -1; - do_shared_object_protection = false; - m_mitigation_policy = P_CONTROLLED_EXIT; - m_exit_code = DEFAULT_DETECTION_EXIT_CODE; -} - -PNTransformDriver::~PNTransformDriver() -{ - //NOTE: because I now handle shared objects, I clean up orig_virp - //as I create use it, deleting here caused errors, I had to - //ensure orig_virp is NULL, which I could do, but it is just as - //easy to destroy it myself when I am finished with it. -// if(orig_virp != NULL) -// delete orig_virp; -} - -//TODO: redesign the way inferences are added -void PNTransformDriver::AddInference(PNStackLayoutInference *inference, int level) -{ -//TODO: throw exceptions - if(level < 0) - assert(false); - if(inference == NULL) - assert(false); - - //if the level does not already exist, add empty vectors in transform_hierarchy - //until it does - while((int)transform_hierarchy.size()-1 < level) - { - vector<PNStackLayoutInference*> tmp; - transform_hierarchy.push_back(tmp); - } - - transform_hierarchy[level].push_back(inference); -} - -void PNTransformDriver::SetDoCanaries(bool do_canaries) -{ - this->do_canaries = do_canaries; - -#if 0 - //TODO: For the optimized TNE version I had to remove - //optional canaries. This would've been done by - //the finalize_transformation step, but for some reason - //I can't get the registration functionality to work - //assert false for now if the canaries are turned off - //to remind me to fix this. - assert(do_canaries); -#endif - if(!do_canaries) - { - cerr<<"************************************************************"<<endl; - cerr<<"************************************************************"<<endl; - cerr<<"** not doing canaries is not entirely supported. **"<<endl; - cerr<<"** This flag turns says that error amplification with **"<<endl; - cerr<<"** caranries is turnedoff , instead of just turning off **"<<endl; - cerr<<"** in the final layout. **"<<endl; - cerr<<"** TODO: this could be \"easily\" fixed by Ben, but no one**"<<endl; - cerr<<"** knows how and he is too busy. **"<<endl; - cerr<<"************************************************************"<<endl; - cerr<<"************************************************************"<<endl; - } -} - -void PNTransformDriver::SetDoFloatingCanary(bool do_floating_canary) -{ - this->do_floating_canary = do_floating_canary; -} - -void PNTransformDriver::SetDoAlignStack(bool align_stack) -{ - this->do_align = align_stack; -} - -void PNTransformDriver::AddBlacklist(set<string> &blacklist) -{ - this->blacklist.insert(blacklist.begin(),blacklist.end()); - -/* - set<string>::iterator it; - for(it = blacklist.begin();it != blacklist.end();it++) - { - this->blacklist.insert(*it); - } -*/ -} - -void PNTransformDriver::AddBlacklistFunction(string func_name) -{ - blacklist.insert(func_name); -} - - -//This function was experimental, and I never did anything with it -void PNTransformDriver::AddOnlyValidateList(std::set<std::string> &only_validate_list) -{ - set<string>::iterator it; - for(it = only_validate_list.begin();it != only_validate_list.end();it++) - { - this->only_validate_list.insert(*it); - } -} - -void PNTransformDriver::SetCoverageMap(std::map<std::string,map<string,double> > coverage_map) -{ - this->coverage_map = coverage_map; -} - -void PNTransformDriver::SetNoValidationLevel(unsigned int no_validation_level) -{ - this->no_validation_level = no_validation_level; -} - -void PNTransformDriver::SetCoverageThreshold(double threshold) -{ - coverage_threshold = threshold; -} - -void PNTransformDriver::SetProtectSharedObjects(bool do_protection) -{ - do_shared_object_protection = do_protection; -} - - -bool PNTransformDriver::PaddingTransformHandler(PNStackLayout *layout, Function_t *func, bool validate) -{ - bool success = false; - - if(!validate) - cerr<<"PNTransformDriver: Function "<<func->GetName()<<" is flagged to be transformed without validation"<<endl; - - cerr<<"PNTransformDriver: Function "<<func->GetName()<<" is not canary safe, attempting shuffle validation"<<endl; - - if(validate && !ShuffleValidation(2,layout,func)) - { - cerr<<"PNTransformDriver: Shuffle Validation Failure"<<endl; - return success; - } - - layout->Shuffle();//one final shuffle - layout->AddRandomPadding(do_align); - - if(!Sans_Canary_Rewrite(layout,func)) - { - undo(func); - cerr<<"PNTransformDriver: Rewrite Failure: "<<layout->GetLayoutName()<<" Failed to Rewrite "<<func->GetName()<<endl; - } - else if(validate && !Validate(orig_virp, func->GetName())) - { - undo(func); - cerr<<"PNTransformDriver: Validation Failure: "<<layout->GetLayoutName()<<" Failed to Validate "<<func->GetName()<<endl; - } - else - { - cerr<<"PNTransformDriver: Final Transformation Success: "<<layout->ToString()<<endl; -// transformed_history[layout->GetLayoutName()].push_back(layout); - // finalize_record fr; - // fr.layout = layout; - // fr.func = func; - // fr.firp = orig_virp; - // finalization_registry.push_back(fr); - // undo(func); - success = true; - //undo_list.clear(); - //reset_undo(func->GetName()); - } - - //orig_virp->WriteToDB(); - - return success; -} - -bool PNTransformDriver::LayoutRandTransformHandler(PNStackLayout *layout, Function_t *func,bool validate) -{ - if(!validate) - cerr<<"PNTransformDriver: Function "<<func->GetName()<<" is flagged to be transformed without validation"<<endl; - - bool success = false; - cerr<<"PNTransformDriver: Function "<<func->GetName()<<" is not padding safe, attempting layout randomization only"<<endl; - - if(validate && !ShuffleValidation(2,layout,func)) - { - cerr<<"PNTransformDriver: Validation Failure: "<<layout->GetLayoutName()<<" Failed to Validate "<<func->GetName()<<endl; - } - else - { - layout->Shuffle(); - //TODO: do I need to check for success at this point? - Sans_Canary_Rewrite(layout,func); - cerr<<"PNTransformDriver: Final Transformation Success: "<<layout->ToString()<<endl; -// transformed_history[layout->GetLayoutName()].push_back(layout); - // finalize_record fr; - // fr.layout = layout; - // fr.func = func; - // fr.firp = orig_virp; - // finalization_registry.push_back(fr); - // undo(func); - success = true; - //undo_list.clear(); - //reset_undo(func->GetName()); - } - - //orig_virp->WriteToDB(); - return success; -} - -bool PNTransformDriver::IsBlacklisted(Function_t *func) -{ - if(sanitized.find(func) != sanitized.end()) - { - cerr<<"PNTransformDriver:: Sanitized Function "<<func->GetName()<<endl; - sanitized_funcs++; - return true; - } - - // @todo: specify regex patterns in black list file instead - // of special-casing here - - // filter out _L_lock_* - // filter out _L_unlock_* - - if (func->GetName().find("_L_lock_") == 0 || - func->GetName().find("_L_unlock_") == 0 || - func->GetName().find("__gnu_") != string::npos || - func->GetName().find("cxx_") != string::npos|| - func->GetName().find("_cxx") != string::npos || - func->GetName().find("_GLOBAL_") != string::npos || - func->GetName().find("_Unwind") != string::npos || - func->GetName().find("__timepunct") != string::npos || - func->GetName().find("__timepunct") != string::npos || - func->GetName().find("__numpunct") != string::npos|| - func->GetName().find("__moneypunct") != string::npos || - func->GetName().find("__PRETTY_FUNCTION__") != string::npos || - func->GetName().find("__cxa") != string::npos || - blacklist.find(func->GetName()) != blacklist.end()) -// if(blacklist.find(func->GetName()) != blacklist.end()) - { - cerr<<"PNTransformDriver: Blacklisted Function "<<func->GetName()<<endl; - blacklist_funcs++; - return true; - } - - return false; -} - - -void PNTransformDriver::GenerateTransformsInit() -{ - //TODO: have a thread safe timeExpired - timeExpired = false; - signal(SIGUSR1, sigusr1Handler); - total_funcs = 0; - blacklist_funcs = 0; - sanitized_funcs = 0; - push_pop_sanitized_funcs = 0; - cond_frame_sanitized_funcs = 0; - jump_table_sanitized = 0; - bad_variadic_func_sanitized = 0; - pic_jump_table_sanitized = 0; - eh_sanitized = 0; - dynamic_frames = 0; - high_coverage_count = low_coverage_count = no_coverage_count = validation_count = 0; - not_transformable.clear(); - failed.clear(); -} - - -void PNTransformDriver::InitNewFileIR(File_t* this_file) -{ - //Always modify a.ncexe first. This is assumed to be what the constructor of FileIR_t will return if - //the variant ID is used alone as the parameter to the constructor. - orig_virp = new FileIR_t(*pidp, this_file); - assert(orig_virp && pidp); - - int elfoid=orig_virp->GetFile()->GetELFOID(); - pqxx::largeobject lo(elfoid); - lo.to_file(pqxx_interface->GetTransaction(),"readeh_tmp_file.exe"); - - elfiop=new EXEIO::exeio; - elfiop->load((char*)"readeh_tmp_file.exe"); - - EXEIO::dump::header(cout,*elfiop); - EXEIO::dump::section_headers(cout,*elfiop); - - //Calc preds is used for sanity checks. - //I believe it determines the predecessors of instructions - calc_preds(); -} - - -template <class T> struct file_less : binary_function <T,T,bool> { - bool operator() (const T& x, const T& y) const {return x->GetURL() < y->GetURL() ;} -}; - -void PNTransformDriver::GenerateTransforms() -{ - if(transform_hierarchy.size() == 0) - { - cerr<<"PNTransformDriver: No Transforms have been registered, aborting GenerateTransforms"<<endl; - return; - } - GenerateTransformsInit(); - - //sanity check of no_validation_level - if(no_validation_level >= (int)transform_hierarchy.size()) - { - cerr<<"PNTransformDriver ERROR: no_validation_level greater than highest level in the hierarchy, exiting."<<endl; - exit(1); - } - - - //TODO: I refactored PN, but to keep the refactoring simple, I did not change the use of the class field "orig_virp" - //now that I am protecting shared objects, it might be better to pass this variable around, or at least change the - //name, something to consider - - //--------------------a.ncexe protection----------------------- - InitNewFileIR(NULL); - - - // now that we've loaded the FileIR, we can init the reg expressions needed for this object. - pn_regex=new PNRegularExpressions; - - - //Sanity check: make sure that this file is actually a.ncexe, if not assert false for now - string url = orig_virp->GetFile()->GetURL(); - //TODO: basename is only used as a hack - //because of the way the url is stored in the db. - //The url should be fixed to be the absolute path. - if(url.find("a.ncexe")==string::npos) - { - assert(false); - } - - cout<<"PNTransformDriver: Protecting File: "<<url<<endl; - GenerateTransformsHidden(coverage_map["a.ncexe"]); - - - //-----------------------shared object protection---------------------------- - - //Transform any shared objects if shared object protection is on - //This will loop through all files stored in pidp and skip a.ncexe - if(do_shared_object_protection) - { - cout<<"PNTransformDriver: Shared Object Protection ON"<<endl; - set<File_t*,file_less<File_t*> > sorted_files; - - for(set<File_t*>::iterator it=pidp->GetFiles().begin(); - it!=pidp->GetFiles().end(); - ++it - ) - { - File_t* this_file=*it; - sorted_files.insert(this_file); - } - - - for(set<File_t*,file_less<File_t*> >::iterator it=sorted_files.begin(); - it!=sorted_files.end()&&!timeExpired; - ++it - ) - { - File_t* this_file=*it; - assert(this_file); - - string url = this_file->GetURL(); - //if the file is a.ncexe skip it (it has been transformed already) - if(url.find("a.ncexe")!=string::npos) - continue; - - // read the db - InitNewFileIR(this_file); - - map<string,double> file_coverage_map; - - string key; - //find the appropriate coverage map for the given file - //TODO: in theory this should be a simple map look up, but because - //the complete path is not currently in the DB for a shared object - //I have to loop through the map for now. - for(map<string, map<string, double> >::iterator it=coverage_map.begin(); - it!=coverage_map.end()&&!timeExpired; ++it) - { - key = it->first; - - //TODO: basename is only used as a hack - //because of the way the url is stored in the db. - //The url should be fixed to be the absolute path. - key=string(basename((char*)key.c_str())); - - if(key.empty()) - continue; - - if(url.find(key)!=string::npos) - { - file_coverage_map=it->second; - break; - } - } - - - cerr<<"######PreFile Report: Accumulated results prior to processing file: "<<url<<"######"<<endl; - //Print_Report(); - - cout<<"PNTransformDriver: Protecting File: "<<url<<endl; - GenerateTransformsHidden(file_coverage_map); - } - } - - if (write_stack_ir_to_db) - { - WriteStackIRToDB(); - } - - if(timeExpired) - cerr<<"Time Expired: Commit Changes So Far"<<endl; - - Update_FrameSize(); // call before finalizing transformations - - //finalize transformation, commit to database - Finalize_Transformation(); - - //TODO: clean up malloced (new'ed) FileIR_t - - cerr<<"############################Final Report############################"<<endl; - Print_Report(); - Print_Map(); -} - -// count_prologue_pushes - -// start at the entry point of a function, and count all push instructions -static pair<int,int> get_prologue_data(Function_t *func) -{ - int count=0; - int subs=0; - Instruction_t* insn=NULL, *prev=NULL; - - // note: GetNextInstruction will return NULL if it tries to leave the function - // or encounters conditional control flow (it will follow past unconditional control flow - // it also stops at indirect branches (which may leave the function, or may generating - // multiple successors) - int i; - for(i=0,insn=func->GetEntryPoint(); insn!=NULL && i<MAX_JUMPS_TO_FOLLOW; ++i,insn=GetNextInstruction(prev,insn, func)) - { - //DISASM d; - //Disassemble(insn,d); - const auto d=DecodedInstruction_t(insn); - if(d.getMnemonic()/*Instruction.Mnemonic*/ == "sub" && d.getOperand(0).isRegister() && d.getOperand(0).getRegNumber()==4 /*Argument1.ArgType==REGISTER_TYPE+GENERAL_REG+REG4*/) - { - subs++; - } - else if(d.getMnemonic() /*string(d.Instruction.Mnemonic)*/ == "push") - { - if( d.getOperand(0).isConstant() /*d.Argument2.ArgType&CONSTANT_TYPE)==CONSTANT_TYPE */ //&& -// insn->GetFallthrough()!=NULL && -// insn->GetFallthrough()->GetTarget()!=NULL && -// func->GetInstructions().find(insn->GetFallthrough()->GetTarget())!=func->GetInstructions().end() - ) - { - // push imm followed by a jump outside the function. - // this is a call, don't count it as a push. - } - else - count++; - } - - prev=insn; - } - return pair<int,int>(count,subs); -} - - -static bool is_exit_insn(Instruction_t* prev) -{ - if(prev->GetFallthrough()!=NULL && prev->GetTarget()!=NULL) - return false; // cond branch - - // check for fixed_call - const auto reloc_it=find_if(ALLOF(prev->GetRelocations()), [&](const Relocation_t* r) - { return r->GetType()=="fix_call_fallthrough"; } ); - if(reloc_it!=end(prev->GetRelocations())) - return false; - - - if(prev->GetFallthrough()==NULL && prev->GetTarget()==NULL) - { - //DISASM d; - //Disassemble(prev,d); - const auto d=DecodedInstruction_t(prev); - if(d.isReturn() /*string(d.CompleteInstr) == "ret "*/) - return true; - - const auto ib_targets=prev->GetIBTargets(); - if(ib_targets) - { - const auto out_of_function_it=find_if(ALLOF(*ib_targets), [&](const Instruction_t* i) - { - return i->GetFunction() != prev->GetFunction(); - } ) ; - - if(out_of_function_it!=end(*ib_targets)) - return true; // detected this as an exit node. - } - - return NULL; // indirect branch of some unknown type? - } - - // target or fallthrough is null, but exactly 1 is non-null - - const auto next_insn = prev->GetTarget() ? prev->GetTarget() : prev->GetFallthrough(); - assert(next_insn); - - return (next_insn->GetFunction() != prev->GetFunction()); -} - -Instruction_t* find_exit_insn(Instruction_t *insn, Function_t *func) -{ - Instruction_t *prev=NULL; - for(int i=0; insn!=NULL && i<MAX_JUMPS_TO_FOLLOW; ++i, insn=GetNextInstruction(prev,insn, func)) - { - prev=insn; - } - - return is_exit_insn(prev) ? prev : NULL; - -} - - -// check for a conditional frame -- that is, a cond branch before the sub resp -static bool check_for_cond_frame(Function_t *func, ControlFlowGraph_t* cfg) -{ - assert(func && cfg); - const auto b=cfg->GetEntry(); - - - const auto is_rsp_sub= [](const DecodedInstruction_t &d) -> bool - { - return - (d.getMnemonic() == /*string(d.Instruction.Mnemonic)==*/"sub" && /* is sub */ - d.getOperand(0).isRegister() /* ((d.Argument1.ArgType&0xFFFF0000)==REGISTER_TYPE+GENERAL_REG )*/ && /* and arg1 is a register */ - d.getOperand(0).getRegNumber()==4 /*(d.Argument1.ArgType&0x0000FFFF)==REG4*/); /* and is the stack pointer. */ - }; - - const auto is_rsp_sub_insn= [&](const Instruction_t* i) -> bool - { - //DISASM d; - //Disassemble(i,d); - const auto d=DecodedInstruction_t(i); - return is_rsp_sub(d); - }; - - if(!b) - return true; - - const auto has_rsp_sub_it= find_if(ALLOF(func->GetInstructions()), is_rsp_sub_insn); - - if(has_rsp_sub_it == func->GetInstructions().end()) - return true; - - for(const auto &i : b->GetInstructions()) - { - if(is_rsp_sub_insn(i)) - { - return true; /* found the sub first. */ - } - if(i->GetTarget() && i->GetFallthrough()) /* is cond branch */ - { - cout<<"Found cond-frame in "<<func->GetName()<<" because "<<i->getDisassembly()<<endl; - return false; - } - - } - return true; -} - -// check_for_push_pop_coherence - -// we are trying to check whether the function's prologue uses -// the same number of push as each exit to the function does. -// odd things happen if we can't match pushes and pops. -// but, we are actively trying to ignore pushes/pops related to calling another function. -// return true if push/pop coherence is OK. -// false otherwise. -static bool check_for_push_pop_coherence(Function_t *func) -{ - - // count pushes in the prologue - const pair<int,int> p=get_prologue_data(func); - const int prologue_pushes=p.first; - const int prologue_subrsps=p.second; - - - -//cerr<<"Found "<<prologue_pushes<<" pushes in "<<func->GetName()<<endl; - - // keep a map that keeps the count of pops for each function exit. - map<Instruction_t*, int> pop_count_per_exit; - map<Instruction_t*, int> found_leave_per_exit; - map<Instruction_t*, int> found_addrsp_per_exit; - - // now, look for pops, and fill in that map. - for( - set<Instruction_t*>::const_iterator it=func->GetInstructions().begin(); - it!=func->GetInstructions().end(); - ++it - ) - { - Instruction_t* insn=*it; - //DISASM d; - //Disassemble(insn,d); - const auto d=DecodedInstruction_t(insn); - //if((string(d.Instruction.Mnemonic) == "add " || string(d.Instruction.Mnemonic) == "lea ") && d.Argument1.ArgType==REGISTER_TYPE+GENERAL_REG+REG4) - if((d.getMnemonic()== "add" || d.getMnemonic() == "lea") && d.getOperand(0).isRegister() && d.getOperand(0).getRegNumber()==4) - { - Instruction_t *exit_insn=find_exit_insn(insn,func); - if(exit_insn) - found_addrsp_per_exit[exit_insn]++; - } - //else if(string(d.Instruction.Mnemonic) == "leave ") - else if(d.getMnemonic() == "leave") - { - Instruction_t *exit_insn=find_exit_insn(insn,func); - if(exit_insn) - found_leave_per_exit[exit_insn]++; - } - //else if(string(d.Instruction.Mnemonic)=="pop ") - else if(d.getMnemonic() == "pop") - { - Instruction_t *exit_insn=find_exit_insn(insn,func); - - if(exit_insn) - { - //DISASM d2; - //Disassemble(exit_insn,d2); - //const auto d2=DecodedInstruction_t(exit_insn); -//cerr<<"Found exit insn ("<< d2.CompleteInstr << ") for pop ("<< d.CompleteInstr << ")"<<endl; - map<Instruction_t*, int>::iterator mit; - mit=pop_count_per_exit.find(exit_insn); - if(mit == pop_count_per_exit.end()) // not found - pop_count_per_exit[exit_insn]=0; // init - - pop_count_per_exit[exit_insn]++; - } - else - { -// -// some pops dont match exit points because they follow a call instruction where arguments were pushed. -// so, we don't immediately error if the pop doesn't match to an exit point. -// -// cerr<<"Could not find exit insn for pop ("<< hex << insn->GetBaseID() <<":"<< d.CompleteInstr << " at " << insn->GetAddress()->GetVirtualOffset() << ")"<<endl; -// return false; - } - } - } - - // now, look at each exit with pops, and verify the count matches the push count. - // we always allow an exit point from the function to have 0 pops, as things like - // calls to non-return functions (e.g., exit, abort, assert_fail) don't clean up the - // stack first. Also handy as this allows "fixed" calls to be ignored. - // but, since exits with 0 pops aren't in the map, we don't need an explicit check for them. - for( - map<Instruction_t* ,int>::iterator it=pop_count_per_exit.begin(); - it!=pop_count_per_exit.end(); - ++it - ) - { - pair<Instruction_t*const,int> map_pair=*it; - Instruction_t* insn=map_pair.first; - assert(insn); - //DISASM d; - //Disassemble(insn,d); - //const auto d=DecodedInstruction_t(insn); - -//cerr<<"Found "<<map_pair.second<<" pops in exit: \""<< d.CompleteInstr <<"\" func:"<<func->GetName()<<endl; - - // do the check - if(prologue_pushes != map_pair.second && found_leave_per_exit[insn]==0) - { - cerr<<"Sanitizing function "<<func->GetName()<<" because pushes don't match pops for an exit"<<endl; - return false; - } - } - - - for(const auto insn : func->GetInstructions()) - { - if(!is_exit_insn(insn)) - continue; - if ( prologue_subrsps == 0) - { - if(found_leave_per_exit[insn]!=0 || found_addrsp_per_exit[insn]!=0) - { - cerr<<"Sanitizing function "<<func->GetName()<<" because prologue subrsps=0 and leave=" - <<dec<<found_leave_per_exit[insn]<<", addrsps!="<<found_addrsp_per_exit[insn]<<" for an exit at " - <<hex<<"0x"<<insn->GetAddress()->GetVirtualOffset()<<endl; - return false; - } - } - else if ( prologue_subrsps == 1 ) - { - if(found_leave_per_exit[insn]==1 && found_addrsp_per_exit[insn]==0) - { - // this case is OK, there's a leave that matches the prologue - } - else if(found_leave_per_exit[insn]==0 && found_addrsp_per_exit[insn]==1) - { - // this case is OK, there's an addrsp that matches the prologue - } - else - { - cerr<<"Sanitizing function "<<func->GetName()<<" because prologue subrsps=1 and leave=" - <<dec<<found_leave_per_exit[insn]<<", addrsps!="<<found_addrsp_per_exit[insn]<<" for an exit at " - <<hex<<"0x"<<insn->GetAddress()->GetVirtualOffset()<<endl; - return false; - } - - } - else - { - cerr<<"Sanitizing function "<<func->GetName()<<" because prologue has more than 1 subrsp? "<<endl; - return false; - } - - } - - return true; -} - -/* - * check_for_bad_variadic_funcs -- Look for functions of this form: - 0x0000000000418108 <+0>: push rbp - 0x0000000000418109 <+1>: mov rbp,rsp - 0x000000000041810c <+4>: sub rsp,0x100 - 0x0000000000418113 <+11>: mov DWORD PTR [rbp-0xd4],edi - 0x0000000000418119 <+17>: mov QWORD PTR [rbp-0xe0],rsi - 0x0000000000418120 <+24>: mov QWORD PTR [rbp-0x98],rcx - 0x0000000000418127 <+31>: mov QWORD PTR [rbp-0x90],r8 - 0x000000000041812e <+38>: mov QWORD PTR [rbp-0x88],r9 - 0x0000000000418135 <+45>: movzx eax,al - 0x0000000000418138 <+48>: mov QWORD PTR [rbp-0xf8],rax - 0x000000000041813f <+55>: mov rcx,QWORD PTR [rbp-0xf8] - 0x0000000000418146 <+62>: lea rax,[rcx*4+0x0] - 0x000000000041814e <+70>: mov QWORD PTR [rbp-0xf8],0x41818d - 0x0000000000418159 <+81>: sub QWORD PTR [rbp-0xf8],rax - 0x0000000000418160 <+88>: lea rax,[rbp-0x1] - 0x0000000000418164 <+92>: mov rcx,QWORD PTR [rbp-0xf8] - 0x000000000041816b <+99>: jmp rcx - <leaves function> - -This is a common IDApro failure, as the computed jump is strange for IDA. - -We check for this case by looking for the movzx before EAX is/used otherwise . - -Return value: true if function is OK to transform, false if we find the pattern. - -*/ -bool check_for_bad_variadic_funcs(Function_t *func, const ControlFlowGraph_t* cfg) -{ - BasicBlock_t *b=cfg->GetEntry(); - - - /* sanity check that there's an entry block */ - if(!b) - return true; - - /* sanity check for ending in an indirect branch */ - if(!b->EndsInIndirectBranch()) - return true; - - const std::vector<Instruction_t*>& insns=b->GetInstructions(); - - for(vector<Instruction_t*>::const_iterator it=insns.begin(); it!=insns.end(); ++it) - { - Instruction_t* insn=*it; - //DISASM d; - //Disassemble(insn,d); - const auto d=DecodedInstruction_t(insn); - - /* found the suspicious move insn first */ - const auto disassembly=d.getDisassembly(); - const auto c_str=disassembly.c_str(); - if(strcmp(c_str /*.CompleteInstr*/,"movzx eax, al")==0) - return false; - - - /* else, check for a use or def of rax in any of it's forms */ - if(strstr(c_str /*d.CompleteInstr*/,"eax")!=0) - return true; - if(strstr(c_str/*d.CompleteInstr*/,"rax")!=0) - return true; - if(strstr(c_str/*d.CompleteInstr*/,"ax")!=0) - return true; - if(strstr(c_str/*d.CompleteInstr*/,"ah")!=0) - return true; - if(strstr(c_str/*d.CompleteInstr*/,"al")!=0) - return true; - } - - return true; -} - - -static EXEIO::section* find_section(virtual_offset_t addr, EXEIO::exeio *elfiop) -{ - for ( int i = 0; i < elfiop->sections.size(); ++i ) - { - EXEIO::section* pSec = elfiop->sections[i]; - assert(pSec); - if(pSec->get_address() > addr) - continue; - if(addr >= pSec->get_address()+pSec->get_size()) - continue; - - return pSec; - } - return NULL; -} - -/* - * PNTransformDriver::check_jump_tables - - * - * look for jmp [reg*8+table_base] - */ -bool PNTransformDriver::check_jump_tables(Instruction_t* insn) -{ - /* quick check to skip most instructions */ - if(insn->GetTarget() || insn->GetFallthrough()) - return true; - - //DISASM d; - //Disassemble(insn,d); - const auto d=DecodedInstruction_t(insn); - - /* only look at jumps */ - //int branch_type = d.Instruction.BranchType; - if(!d.isUnconditionalBranch() /*branch_type!=JmpType*/) - return true; - - /* make sure this is an indirect branch */ - if(!d.getOperand(0).isMemory() /*(d.Argument1.ArgType&MEMORY_TYPE)==0*/) - return true; - - if(d.getOperand(0).getScaleValue() /*d.Argument1.Memory.Scale*/<4) - return true; - - int displacement=d.getOperand(0).getMemoryDisplacement() /*d.Argument1.Memory.Displacement*/; - - EXEIO::section* pSec=find_section(displacement,elfiop); - - if(!pSec) - return true; - - const char *secdata=pSec->get_data(); - - if(!secdata) - return true; - - int offset=displacement-pSec->get_address(); - - set<int> jump_tab_entries; - for(int i=0;jump_tab_entries.size()<5;i++) - { - if((int)(offset+i*4+sizeof(int)) > (int) pSec->get_size()) - break; - - const int *table_entry_ptr=(const int*)&(secdata[offset+i*4]); - int table_entry=*table_entry_ptr; - - if(table_entry!=0) - { -// cout << "found possible table entry "<<hex<<table_entry<<" from func "<<insn->GetFunction()->GetName()<<endl; - jump_tab_entries.insert(table_entry); - } - - } - - return check_jump_table_entries(jump_tab_entries,insn->GetFunction()); - -} - -bool PNTransformDriver::check_jump_table_entries(set<int> jump_tab_entries,Function_t* func) -{ - for( - set<Instruction_t*>::const_iterator it=orig_virp->GetInstructions().begin(); - it!=orig_virp->GetInstructions().end(); - ++it - ) - { - Instruction_t* ftinsn=*it;; - AddressID_t* addr=ftinsn->GetAddress(); - int voff=addr->GetVirtualOffset(); - - // check to see if this instruction is in my table - if(jump_tab_entries.find(voff)!=jump_tab_entries.end()) - { - // it is! - - // now, check to see if the instruction is in my function - if(func !=ftinsn->GetFunction()) - { - cout<<"Sanitizing function "<< func->GetName()<< "due to jump-table to diff-func detected."<<endl; - return false; - } - else - { - // cout<<"Verified that the instruction is in my function, yay!"<<endl; - } - } - } - return true; - -} - -bool PNTransformDriver::backup_until(const char* insn_type, Instruction_t *& prev, Instruction_t* orig) -{ - prev=orig; - while(preds[prev].size()==1) - { - // get the only item in the list. - prev=*(preds[prev].begin()); - - // get I7's disassembly - //DISASM disasm; - //Disassemble(prev,disasm); - const auto disasm=DecodedInstruction_t(prev); - - // check it's the requested type - if(strstr((disasm.getMnemonic()+" ").c_str() /*disasm.Instruction.Mnemonic*/, insn_type)!=NULL) - return true; - - // otherwise, try backing up again. - - } - return false; -} - -void PNTransformDriver::calc_preds() -{ - preds.clear(); - for( - set<Instruction_t*>::const_iterator it=orig_virp->GetInstructions().begin(); - it!=orig_virp->GetInstructions().end(); - ++it - ) - { - Instruction_t* insn=*it; - if(insn->GetTarget()); - preds[insn->GetTarget()].insert(insn); - if(insn->GetFallthrough()); - preds[insn->GetFallthrough()].insert(insn); - } -} - - - - -/* check if this instruction is an indirect jump via a register, - * if so, see if the jump location is in the same function. Return false if not in the same function. - */ -bool PNTransformDriver::check_for_PIC_switch_table64(Instruction_t* insn, DecodedInstruction_t disasm) -{ - - /* here's the pattern we're looking for */ -#if 0 -I1: 0x000000000044425a <+218>: cmp DWORD PTR [rax+0x8],0xd // bounds checking code, 0xd cases. -I2: 0x000000000044425e <+222>: jbe 0x444320 <_gedit_tab_get_icon+416> - -<snip> -I3: 0x0000000000444264 <+228>: mov rdi,rbp // default case, also jumped to via indirect branch below -<snip> -I4: 0x0000000000444320 <+416>: mov edx,DWORD PTR [rax+0x8] -I5: 0x0000000000444323 <+419>: lea rax,[rip+0x3e1b6] # 0x4824e0 -I6: 0x000000000044432a <+426>: movsxd rdx,DWORD PTR [rax+rdx*4] -I7: 0x000000000044432e <+430>: add rax,rdx -I8: 0x0000000000444331 <+433>: jmp rax // relatively standard switch dispatch code - - -D1: 0x4824e0: .long 0x4824e0-L1 // L1-LN are labels in the code where case statements start. -D2: 0x4824e0: .long 0x4824e0-L2 -.. -DN: 0x4824e0: .long 0x4824e0-LN -#endif - - - // for now, only trying to find I4-I8. ideally finding I1 would let us know the size of the - // jump table. We'll figure out N by trying targets until they fail to produce something valid. - - Instruction_t* I8=insn; - Instruction_t* I7=NULL; - Instruction_t* I6=NULL; - Instruction_t* I5=NULL; - // check if I8 is a jump - //if(strstr(disasm.Instruction.Mnemonic, "jmp")==NULL) - if(disasm.getMnemonic() != "jmp") - return true; - - // return if it's a jump to a constant address, these are common - //if(disasm.Argument1.ArgType&CONSTANT_TYPE) - if(disasm.getOperand(0).isConstant()) - return true; - // return if it's a jump to a memory address - //if(disasm.Argument1.ArgType&MEMORY_TYPE) - if(disasm.getOperand(0).isMemory()) - return true; - - // has to be a jump to a register now - - // backup and find the instruction that's an add before I8 - if(!backup_until("add", I7, I8)) - return true; - - // backup and find the instruction that's an movsxd before I7 - if(!backup_until("movsxd", I6, I7)) - return true; - - // backup and find the instruction that's an lea before I6 - if(!backup_until("lea", I5, I6)) - return true; - - disasm=DecodedInstruction_t(I5); // Disassemble(I5,disasm); - - //if(!(disasm.Argument2.ArgType&MEMORY_TYPE)) - if(!disasm.getOperand(1).isMemory()) - return true; - //if(!(disasm.Argument2.ArgType&RELATIVE_)) - if(!disasm.getOperand(1).isPcrel()) - return true; - - // note that we'd normally have to add the displacement to the - // instruction address (and include the instruction's size, etc. - // but, fix_calls has already removed this oddity so we can relocate - // the instruction. - int D1=strtol(disasm.getOperand(1).getString().c_str()/*Argument2.ArgMnemonic*/, NULL, 16); - - // find the section with the data table - EXEIO::section *pSec=find_section(D1,elfiop); - - // sanity check there's a section - if(!pSec) - return true; - - const char* secdata=pSec->get_data(); - - // if the section has no data, abort - if(!secdata) - return true; - - set<int> table_entries; - int offset=D1-pSec->get_address(); - int entry=0; - for(int i=0;table_entries.size()<5;i++) - { - // check that we can still grab a word from this section - if((int)(offset+sizeof(int)) > (int)pSec->get_size()) - break; - - const int *table_entry_ptr=(const int*)&(secdata[offset]); - int table_entry=*table_entry_ptr; - - //put in set -> d1+table_entry - table_entries.insert(D1+table_entry); - - offset+=sizeof(int); - entry++; - - } - - return check_jump_table_entries(table_entries,insn->GetFunction()); -} - -void PNTransformDriver::SanitizeFunctions() -{ - - //TODO: for now, the sanitized list is only created for an individual IR file - sanitized.clear(); - - for( - set<Function_t*>::const_iterator func_it=orig_virp->GetFunctions().begin(); - func_it!=orig_virp->GetFunctions().end(); - ++func_it - ) - { - Function_t *func = *func_it; - assert(func); - ControlFlowGraph_t cfg(func); - - for( - set<Instruction_t*>::const_iterator it=func->GetInstructions().begin(); - it!=func->GetInstructions().end(); - ++it - ) - { - //DISASM disasm; - Instruction_t* instr = *it; - - if(instr == NULL) - continue; - - //Disassemble(instr,disasm); - const auto disasm=DecodedInstruction_t(instr); - string disasm_str = disasm.getDisassembly()/*CompleteInstr*/; - -/* - if(disasm_str.find("nop")!=string::npos && instr->GetFunction() == NULL) - continue; -*/ - - // check if there is a fallthrough from this function - // into another function. if so, sanitize both. - if(FallthroughFunctionCheck(instr,instr->GetFallthrough())) - { - //check if instruciton is a call, unconditional jump, or ret - //all other instructions should have targets within the same function - //if not, filter the functions - //int branch_type = disasm.Instruction.BranchType; - if(!disasm.isReturn() && !disasm.isUnconditionalBranch() && !disasm.isCall() /*branch_type!=RetType && branch_type!=JmpType && branch_type!=CallType*/) - // check if instr->GetTarget() (for cond branches) - // exits the function. If so, sanitize both funcs. - TargetFunctionCheck(instr,instr->GetTarget()); - - - } - - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - // check for push/pop coherence. - if(!check_jump_tables(instr)) - { - jump_table_sanitized++; - sanitized.insert(func); - continue; - } - } - - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - if(!check_for_PIC_switch_table64(instr,disasm)) - { - pic_jump_table_sanitized++; - sanitized.insert(func); - continue; - } - } - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - if(instr->GetEhCallSite() && - instr->GetEhCallSite()->GetLandingPad() && - instr->GetEhCallSite()->GetLandingPad()->GetFunction()!=func) - { - eh_sanitized++; - sanitized.insert(func); - continue; - } - } - } - - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - // check for push/pop coherence. - if(!check_for_push_pop_coherence(func)) - { - push_pop_sanitized_funcs++; - sanitized.insert(func); - continue; - } - } - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - // check for push/pop coherence. - if(!check_for_cond_frame(func, &cfg)) - { - cond_frame_sanitized_funcs++; - sanitized.insert(func); - continue; - } - } - // if it's not already sanitized - if(sanitized.find(func)==sanitized.end()) - { - // check for push/pop coherence. - if(!check_for_bad_variadic_funcs(func,&cfg)) - { - bad_variadic_func_sanitized++; - sanitized.insert(func); - continue; - } - } - } - //TODO: print sanitized list. - - cerr<<"Sanitization Report:"<<"\nThe following "<<sanitized.size()<< - " functions were sanitized from this file:"<<endl; - for( - set<Function_t*>::const_iterator it=sanitized.begin(); - it!=sanitized.end(); - ++it - ) - { - Function_t *func=*it; - if(func != NULL) - cerr<<"\t"<<func->GetName()<<endl; - } -} - -inline bool PNTransformDriver::FallthroughFunctionCheck(Instruction_t* a, Instruction_t* b) -{ - if(a == NULL || b == NULL) - return true; - - if(a->GetFunction() == NULL || b->GetFunction() == NULL) - return true; - - return FunctionCheck(a->GetFunction(),b->GetFunction()); - -} - -inline bool PNTransformDriver::FunctionCheck(Function_t* a,Function_t* b) -{ - if(a != b) - { - //To avoid null pointer exceptions I am not going to sanitize the - //null function - if(a != NULL) - sanitized.insert(a); - if(b != NULL) - sanitized.insert(b); - return false; - } - return true; -} - - -inline bool PNTransformDriver::TargetFunctionCheck(Instruction_t* a, Instruction_t* b) -{ - if(a == NULL || b == NULL) - return true; - - return FunctionCheck(a->GetFunction(),b->GetFunction()); -} - - -template <class T> struct func_less : binary_function <T,T,bool> { - bool operator() (const T& x, const T& y) const {return x->GetName() < y->GetName() ;} -}; -//Speculation note: - -//Speculation note: -//Hypothesis generation assessment and refinement prior to modification. -//hypothesis assessment and refinement after modification is performed by the recursive validation subroutine. -void PNTransformDriver::GenerateTransformsHidden(map<string,double> &file_coverage_map) -{ - SanitizeFunctions(); - - vector<validation_record> high_covered_funcs, low_covered_funcs, not_covered_funcs,shuffle_validate_funcs; - - static int funcs_attempted=-1; - - set<Function_t*, func_less<Function_t*> > sorted_funcs; - for( - set<Function_t*>::const_iterator it=orig_virp->GetFunctions().begin(); - it!=orig_virp->GetFunctions().end(); - ++it - ) - { - Function_t* func=*it; - sorted_funcs.insert(func); - } - - //For each function - //Loop through each level, find boundaries for each, sort based on - //the number of boundaries, attempt transform in order until successful - //or until all inferences have been exhausted - for( - set<Function_t*, func_less<Function_t*> >::const_iterator it=sorted_funcs.begin(); - it!=sorted_funcs.end()&&!timeExpired; - ++it - ) - - { - Function_t *func = *it; - - /* skip before the increment, so we don't emit the message more than once */ - if(getenv("PN_NUMFUNCSTOTRY") && funcs_attempted>=atoi(getenv("PN_NUMFUNCSTOTRY"))) - { - cerr<<dec<<"Aborting transforms after func number "<<funcs_attempted<<", which is: "<< - func->GetName()<<endl; - break; - } - - if(getenv("PN_ONLYTRANSFORM") && funcs_attempted!=atoi(getenv("PN_ONLYTRANSFORM"))) - { - cout<<"Skipping function "<<dec<<funcs_attempted<<", named: "<<func->GetName()<<endl; - funcs_attempted++; - continue; - } - - - //TODO: remove this at some point when I understand if this can happen or not - assert(func != NULL); - - cerr<<"PNTransformDriver: Function #"<<std::dec<<funcs_attempted<<": "<<orig_virp->GetFile()->GetURL()<<" "<<func->GetName()<<endl; - funcs_attempted++; - - //Check if in blacklist - if(IsBlacklisted(func)) - { - cout<<"Detected function is blacklisted: "<<func->GetName()<<endl; - continue; - } - - total_funcs++; - - //Level in the hierarchy to start at - int level=0; - double func_coverage = 0; - - //see if the function is in the coverage map - if(file_coverage_map.find(func->GetName()) != file_coverage_map.end()) - { - //if coverage exists, if it is above or equal to the threshold - //do nothing, otherwise set hierachy to start at the level - //passed. - func_coverage = file_coverage_map[func->GetName()]; - } - - //Function coverage must be strictly greater than the threshold - if(func_coverage <= coverage_threshold) - { - if(no_validation_level < 0) - { - cout<<"PNTransformDriver: Function "<<func->GetName()<< - " has insufficient coverage, aborting transformation"<<endl; - continue; - } - else - { - level = no_validation_level; - - cout<<"PNTransformDriver: Function "<<func->GetName()<< - " has insufficient coverage, starting at hierarchy at " - " level "<<level<<endl; - } - } - - - //Get a layout inference for each level of the hierarchy. Sort these layouts based on - //on the number of memory objects detected (in descending order). Then try each layout - //as a basis for transformation until one succeeds or all layouts in each level of the - //hierarchy have been exhausted. - - //TODO: need to properly handle not_transformable and functions failing all transforms. - vector<PNStackLayout*> layouts; - for(;level<(int)transform_hierarchy.size() && layouts.size()==0;level++) - { - layouts = GenerateInferences(func, level); - } - - - //If the number of null inferences encountered equals the number of inferences - //that are possible (based on the starting level which may not be 0), then - //the function is not transformable. -// if((int)transform_hierarchy.size()-starting_level == null_inf_count) -// not_transformable.push_back(func->GetName()); - //TODO: is there a better way of checking this? -// else - - if(layouts.size() == 0) - { - not_transformable.push_back(func->GetName()); - continue; - } - - - sort(layouts.begin(),layouts.end(),CompareBoundaryNumbersDescending); - - validation_record vr; - vr.hierarchy_index=level; - vr.layout_index=0; - vr.layouts=layouts; - vr.func=func; - - //For logging purposes I want to know if the layout for with the - //PN stack layout is a static stack frame. Since all inferences - //based the same stack frame should record the same result, taking - //the result from the first inference is okay. - if(!layouts[0]->IsStaticStack()) - dynamic_frames++; - - //Handle covered Shuffle Validate functions separately. - //I only suspect to see one function needing shuffle validation (main). - //Don't shuffle here. - if(layouts[0]->DoShuffleValidate() && func_coverage != 0) - { - //Note: Do not transform these functions, handled that elsewhere. - shuffle_validate_funcs.push_back(vr); - - if(func_coverage > coverage_threshold) - high_coverage_count++; - else - low_coverage_count++; - } - else - { - //Else go ahead and transform the layout. - layouts[0]->Shuffle(); - layouts[0]->AddRandomPadding(do_align); - - if(func_coverage == 0) - not_covered_funcs.push_back(vr); - else if(func_coverage <= coverage_threshold) - low_covered_funcs.push_back(vr); - else - high_covered_funcs.push_back(vr); - } - - } - - //TODO: I have seen some functions not require any modifications. In this case we should remove them from the - //vector. Not sure the best way to do this yet. For now ignore, because I have only seen it happen once (function start) - - //sort the validation records by the number of variables detected, - //to optimize validation time. - sort(high_covered_funcs.begin(),high_covered_funcs.end(),CompareValidationRecordAscending); - sort(low_covered_funcs.begin(),low_covered_funcs.end(),CompareValidationRecordAscending); - - //TODO: maybe validate those layouts with 3 or fewer variables first? - //the sorting approach I now do might sufficiently optimize that this - //isn't necessary. - Validate_Recursive(high_covered_funcs,0,high_covered_funcs.size()); - - - //In theory, functions with no coverage will not have any benefit from validation - //but coverage can sometimes be wrong. For example, if PIN failed, perhaps - //the coverage reflects functions that were executed only if the test - //run fails. Go ahead and attempt binary validation on non-covered functions. - //As an optimization I will validate non-covered funcs with functions with low coverage - //but in case a validation failure does occur, functions with no coverage - //are append to the low_covered_funcs vector. Appending to the end, as opposed to - //using one data structure for both should optimize binary search in the - //even of a validation failure, since all functions without coverage are clustered, - //and it is assumed functions with no coverage _SHOULD_ validate all the time. - low_covered_funcs.insert(low_covered_funcs.end(),not_covered_funcs.begin(),not_covered_funcs.end()); - Validate_Recursive(low_covered_funcs,0,low_covered_funcs.size()); - - //NOTE: if you decide to handle not_covered_funcs separately, - //make sure you either use Validate_Recursive, or rewrite - //the instructions yourself. - - cerr<<"Functions to shuffle validate: "<<shuffle_validate_funcs.size()<<endl; - ShuffleValidation(shuffle_validate_funcs); - - if(!Validate(NULL,string(basename((char*)orig_virp->GetFile()->GetURL().c_str()))+"_accum")) - { - cerr<<"TEST ERROR: File: "<<orig_virp->GetFile()->GetURL()<<" does not pass accumulation validation, ignoring the file for now."<<endl; - - //TODO: carefully undo all finalization for this file, for now, - //just remove the FileIR_t from the registered_firps - registered_firps.erase(orig_virp); - - return; - } - else - { - cerr<<"File Accumulation Validation Success"<<endl; - } - - high_coverage_count +=high_covered_funcs.size(); - low_coverage_count +=low_covered_funcs.size(); - no_coverage_count +=not_covered_funcs.size(); - - //TODO: print file report -} - -//returns true if all validate vrs validate without any failures. -void PNTransformDriver::ShuffleValidation(vector<validation_record> &vrs) -{ -// bool success = true; - for(unsigned int i=0;i<vrs.size()&&!timeExpired;i++) - { - PNStackLayout *layout = vrs[i].layouts[vrs[i].layout_index]; - - while(layout != NULL&&!timeExpired) - { - //using padding transform handler since I now - //have PNStackLayout objects preven padding or shuffling - //if it is not appropriate. In theory I could just use - //one handler now, but since I know a canary should not - //be used here, I will explicitly use a function that - //does not even attempt it. - if(!PaddingTransformHandler(layout,vrs[i].func,true)) - { -// success = false; - //we will assume all subsequent layouts require shuffle validation. - //if it doesn't, the padding transform handler will add - //padding and shuffle without shuffle validation. - //Really this means if we have a P1 layout, we wont - //shuffle it because it can't be, so padding will be - //added and validated once. I make the assumption a layout - //never can switch to suddenly being canary safe. - layout = Get_Next_Layout(vrs[i]); - } - else - { - //else transformation was success, register the validation record - Register_Finalized(vrs,i,1); - break; - } - } - - if(layout == NULL) - { - failed.push_back(vrs[i].func); - cout<<"Shuffle Validation: Function: "<<vrs[i].func->GetName()<<" has no additional inferences."<<endl; - } - } - -// return success; -} - -//Alters the passed in validation record to record the layout information, and -//for simplicity returns the next layout object (PNStackLayout*) -//returns NULL if no layout is next. -PNStackLayout* PNTransformDriver::Get_Next_Layout(validation_record &vr) -{ - //if the layout is not the last in the vector of layouts for the hierarchy, set the layout to the next layout - if(vr.layout_index != vr.layouts.size()-1) - { - vr.layout_index++; - } - //otherwise, continue looping through the hierarchy until inferences are generated. - else - { - vector<PNStackLayout*> layouts; - unsigned int level=vr.hierarchy_index; - for(;level<(unsigned int)transform_hierarchy.size()&&layouts.size()==0;level++) - { - layouts = GenerateInferences(vr.func, level); - } - - //If no layouts are found, then this function fails all validation attempts - if(layouts.size() == 0) - { - return NULL; - } - else - { - sort(layouts.begin(),layouts.end(),CompareBoundaryNumbersDescending); - - //update info in the validation record. - vr.layout_index=0; - vr.layouts=layouts; - vr.hierarchy_index=level; - } - } - - return vr.layouts[vr.layout_index]; -} - -int intermediate_report_count=0; -void PNTransformDriver::Register_Finalized(vector<validation_record> &vrs,unsigned int start, int length) -{ - if(length == 0) - return; - - cout<<"Register Finalized: Registering "<<length<<" functions"<<endl; - - for(int i=0;i<length;i++) - { - unsigned int index=i+start; - finalize_record fr; - fr.layout = vrs[index].layouts[vrs[index].layout_index]; - fr.func = vrs[index].func; - fr.firp = orig_virp; - registered_firps.insert(orig_virp); - finalization_registry.push_back(fr); - //placing layout in the history here, although the information - //could change when the modification is finalized. - transformed_history[fr.layout->GetLayoutName()].push_back(fr.layout); - -//DEBUG: turning off undo to accumulate for now. A bug in modifying zsh -//seems to indicate this functionality (registration) is broken. -// undo(vrs[index].func); //make sure this function is registered only (undo any prior mods) - cout<<"registering "<<fr.func->GetName()<<" layout "<<fr.layout->GetLayoutName()<<endl; - } - - intermediate_report_count += length; - - //print out intermedaite report every if the report count exceeds or equals 50 registered funcs - //since the last report. - if(intermediate_report_count >= 50) - { - cerr<<"############################INTERMEDIATE SUMMARY############################"<<endl; - //Print_Report(); - intermediate_report_count=0; - } -} - -//Assumed that passed in layouts have been transformed and are ready for validation. -bool PNTransformDriver::Validate_Recursive(vector<validation_record> &vrs, unsigned int start, int length) -{ - if(timeExpired || length <= 0 || vrs.size()==0) - return false; - - assert(start+length-1 != vrs.size()); - - cout<<"Validate Recursive: validating "<<length<<" funcs of "<<vrs.size()<<endl; - - //Rewrite all funcs - for(int i=0;i<length;i++) - { - unsigned int index=i+start; - PNStackLayout *layout = vrs[index].layouts[vrs[index].layout_index]; - - //make sure the fucntions isn't already modified - undo(vrs[index].func); - - //Canary rewrite will determine if layout can be canaried. - //finalization will remove canaries if appropriate. - Canary_Rewrite(layout,vrs[index].func); - } - - validation_count++; - stringstream ss; - ss<<"validation"<<validation_count; - - if(Validate(orig_virp,ss.str())) - { - Register_Finalized(vrs,start,length); - return true; - } - else - { - //TODO: optimize here - for(int i=0;i<length;i++) - { - unsigned int index = i+start; - undo(vrs[index].func); - } - - if(length == 1) - { - cout<<"Validate Recursive: Found problem function: "<<vrs[start].func->GetName()<<" validating linearly"<<endl; - - if(Get_Next_Layout(vrs[start])==NULL) - { - failed.push_back(vrs[start].func); - cout<<"Validate Recursive: Function: "<<vrs[start].func->GetName()<<" has no additional inferences."<<endl; - return false; - } - - vrs[start].layouts[vrs[start].layout_index]->Shuffle(); - vrs[start].layouts[vrs[start].layout_index]->AddRandomPadding(do_align); - - Validate_Recursive(vrs,start,length); - return false; - } - else - { - //Algorithm Idea: undo modifications half at a time, until the side of the vector of mods - //containing the error is found. If found, send to Validate_Recursive. - //Finalize all remaining. - - bool left_val, right_val; - left_val = Validate_Recursive(vrs,start,length/2); - right_val = Validate_Recursive(vrs,start+length/2,(length-(length/2))); - - if(left_val && right_val) - cerr<<"TESTING ERROR: TESTING THE WHOLE REPORTED FAILURE, TESTING THE HALVES REPORTS SUCCESS"<<endl; - - return false; - } - - } -} - - - - - -// //NOTE: this only_validate_list functionality may not be needed any more, consider removing -// //TODO: for now, only validate if the only_validate_list doesn't have any contents and -// //the level does not equal the never_validate level. I may want to allow the only validate -// //list to be empty, in which case a pointer is better, to check for NULL. -// bool do_validate = true; -// if(only_validate_list.size() != 0) -// { -// if(only_validate_list.find(func->GetName()) == only_validate_list.end()) -// do_validate = false; -// } - -// do_validate = do_validate && (level != no_validation_level); - - -// //Go through each layout in the level of the hierarchy in order. -// for(unsigned int i=0;i<layouts.size()&&!timeExpired;i++) -// { -// //TODO: I need to have the ability to make transformations optional -// if(layouts[i]->IsCanarySafe()) -// success = CanaryTransformHandler(layouts[i],func,do_validate); -// else if(layouts[i]->IsPaddingSafe()) -// success = PaddingTransformHandler(layouts[i],func,do_validate); -// //if not canary or padding safe, the layout can only be randomized -// else -// success = LayoutRandTransformHandler(layouts[i],func,do_validate); - -// if(!success && (int)transform_hierarchy.size()-1 == level && i == layouts.size()-1) -// failed.push_back(func); -// else if(success) -// break; -// } -// } -// } -// } - -void PNTransformDriver::Finalize_Transformation() -{ - cout<<"Finalizing Transformation: Committing all previously validated transformations ("<<finalization_registry.size()<<" functions)"<<endl; - - //TODO: one more validation? - cerr<<"Sanity validation check....."<<endl; - - if( !Validate(NULL,"validation_final")) - { - cerr<<"TEST ERROR: Sanity validation failed!! Backing off all transformations (PN disabled for this program)."<<endl; - return; - } - else - cerr<<"Sanity validation passed."<<endl; - - //Commit changes for each file. - //TODO: is this necessary, can I do one write? - for(set<FileIR_t*>::iterator it=registered_firps.begin(); - it!=registered_firps.end(); - ++it - ) - { - FileIR_t *firp = *it; - cout<<"Writing to DB: "<<firp->GetFile()->GetURL()<<endl; - firp->WriteToDB(); - } -} - -void PNTransformDriver::Update_FrameSize() -{ - map<string,vector<PNStackLayout*> >::const_iterator it; - for(it = transformed_history.begin(); it != transformed_history.end(); it++) - { - //TODO: how do we know which layout we want??? - for(unsigned int i=0;i<it->second.size();i++) - { - auto func = it->second[i]->GetFunction(); - if (!func) continue; - - const auto alteredAllocSize = it->second[i]->GetAlteredAllocSize(); - if (alteredAllocSize > 0) - { - cout << "DEBUG: function: " << func->GetName() << " orig size: " << func->GetStackFrameSize() << " altered size: " << alteredAllocSize << endl; - func->SetStackFrameSize(alteredAllocSize); - } - } - } -} - -void PNTransformDriver::Print_Report() -{ - cerr<<dec<<endl; - cerr<<"############################SUMMARY############################"<<endl; - - cerr<<"Functions Transformed"<<endl; - - map<string,vector<PNStackLayout*> >::const_iterator it; - int total_transformed = 0; - - - vector<string> history_keys; - for(it = transformed_history.begin(); it != transformed_history.end(); it++) - { - total_transformed += it->second.size(); - - //TODO: sort by layout type then print - for(unsigned int i=0;i<it->second.size();i++) - { - cerr<<"\t"<<it->second[i]->ToString()<<endl; - } - - history_keys.push_back(it->first); - } - - cerr<<"-----------------------------------------------"<<endl; - cerr<<"Non-Transformable Functions"<<endl; - - for(unsigned int i=0;i<not_transformable.size();++i) - { - cerr<<"\t"<<not_transformable[i]<<endl; - } - - cerr<<"-----------------------------------------------"<<endl; - cerr<<"Functions Failing All Validation"<<endl; - - for(unsigned int i=0;i<failed.size();++i) - { - cerr<<"\t"<<failed[i]->GetName()<<endl; - } - - cerr<<"----------------------------------------------"<<endl; - cerr<<"Statistics by Transform"<<endl; - - for(unsigned int i=0;i<history_keys.size();++i) - { - cerr<<"\tLayout: "<<history_keys[i]<<endl; - cerr<<"# ATTRIBUTE Layout="<<history_keys[i]<<endl; - vector<PNStackLayout*> layouts = transformed_history[history_keys[i]]; - - map<int,int> obj_histogram; - - cerr<<"\t\tTotal Transformed: "<<layouts.size()<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Total_Transformed="<<layouts.size()<<endl; - - int p1reductions = 0; - double mem_obj_avg = 0.0; - double mem_obj_dev = 0.0; - for(unsigned int laynum=0;laynum<layouts.size();++laynum) - { - if(layouts[laynum]->IsP1()) - p1reductions++; - - unsigned int num_objects = layouts[laynum]->GetNumberOfMemoryObjects(); - - if(obj_histogram.find(num_objects) == obj_histogram.end()) - obj_histogram[num_objects] = 1; - else - obj_histogram[num_objects] = obj_histogram[num_objects]+1; - - mem_obj_avg += num_objects; - } - mem_obj_avg = mem_obj_avg/(double)layouts.size(); - - for(unsigned int laynum=0;laynum<layouts.size();++laynum) - { - mem_obj_dev += pow((((double)layouts[laynum]->GetNumberOfMemoryObjects())-mem_obj_avg),2); - } - - mem_obj_dev = sqrt(mem_obj_dev/(double)layouts.size()); - - cerr<<"\t\tMemory Object Average: "<<mem_obj_avg<<endl; - cerr<<"\t\tMemory Object Deviation: "<<mem_obj_dev<<endl; - cerr<<"\t\tObject Histogram:"<<endl; - - map<int,int>::const_iterator hist_it; - for(hist_it = obj_histogram.begin();hist_it != obj_histogram.end();hist_it++) - { - cerr<<"\t\t\tMemory Objects: "<<hist_it->first<<" Instances: "<<hist_it->second<<endl; - } - - cerr<<"\t\tP1 Reductions: "<<p1reductions<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::P1_Reductions="<<p1reductions<<endl; - } - - cerr<<"----------------------------------------------"<<endl; - cerr<<"Functions validated exceeding threshold: "<<high_coverage_count<<endl; - cerr<<"Functions validated with non-zero coverage below or equal to threshold: "<<low_coverage_count<<endl; - cerr<<"Functions modified with no coverage: "<<no_coverage_count<<endl; - cerr<<"Total recursive validations performed: "<<validation_count<<endl; - cerr<<"----------------------------------------------"<<endl; - cerr<<"Total dynamic stack frames: "<<dynamic_frames<<endl; - - cerr<<"----------------------------------------------"<<endl; - cerr<<"Non-Blacklisted Functions \t"<<total_funcs<<endl; - cerr<<"Blacklisted Functions \t\t"<<blacklist_funcs<<endl; - cerr<<"Sanitized Functions \t\t"<<sanitized_funcs<<endl; - cerr<<"Push/Pop Sanitized Functions \t\t"<<push_pop_sanitized_funcs<<endl; - cerr<<"Cond Frame Sanitized Functions \t\t"<<cond_frame_sanitized_funcs<<endl; - cerr<<"EH-land-pad-not-in-func Sanitized Functions \t\t"<<eh_sanitized<<endl; - cerr<<"Bad Variadic Sanitized Functions \t\t"<<bad_variadic_func_sanitized<<endl; - cerr<<"Jump table Sanitized Functions \t\t"<<jump_table_sanitized<<endl; - cerr<<"PIC Jump table Sanitized Functions \t\t"<<jump_table_sanitized<<endl; - cerr<<"Transformable Functions \t"<<(total_funcs-not_transformable.size())<<endl; - cerr<<"Transformed \t\t\t"<<total_transformed<<endl; - - cerr<<"# ATTRIBUTE Stack_Transformation::Functions_validated_exceeding_threshold="<<high_coverage_count<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Functions_validated_with_nonZero_coverage_below_or_equal_to_threshold="<<low_coverage_count<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Functions_modified_with_no_coverage="<<no_coverage_count<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Total_recursive_validations_performed="<<validation_count<<endl; - - cerr<<"# ATTRIBUTE Stack_Transformation::NonBlacklisted_Functions="<<total_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Blacklisted_Functions="<<blacklist_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::Sanitized_Functions="<<sanitized_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::PushPop_Sanitized_Functions="<<push_pop_sanitized_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::CondFrameSanitized_Functions="<<cond_frame_sanitized_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::EH_land_pad_not_in_FuncSanitizedFunctions="<<eh_sanitized<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::BadVariadicSanitizedFunctions="<<push_pop_sanitized_funcs<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::JumpTableSanitized_Functions="<<jump_table_sanitized<<endl; - cerr<<"# ATTRIBUTE Stack_Transformation::PICJumpTableSanitized_Functions="<<jump_table_sanitized<<endl; - cerr<<"# ATTRIBUTE ASSURANCE_Stack_Transformation::Total_Number_of_Functions="<<total_funcs<<endl; - cerr<<"# ATTRIBUTE ASSURANCE_Stack_Transformation::Transformable_Functions="<<(total_funcs-not_transformable.size())<<endl; - cerr<<"# ATTRIBUTE ASSURANCE_Stack_Transformation::Percent_of_Functions_that_are_Transformable="<<std::fixed <<std::setprecision(1)<<((double)(total_funcs-not_transformable.size())/(double)total_funcs)*100.00<<"%"<<endl; - cerr<<"# ATTRIBUTE ASSURANCE_Stack_Transformation::Total_Transformed_Functions="<<total_transformed<<endl; - cerr<<"# ATTRIBUTE ASSURANCE_Stack_Transformation::Percent_Transformable_Functions_Transformed="<<std::fixed<<std::setprecision(1)<<((double)(total_transformed)/(double)(total_funcs-not_transformable.size()))*100.00<<"%"<<endl; -} - - -vector<PNStackLayout*> PNTransformDriver::GenerateInferences(Function_t *func,int level) -{ - vector<PNStackLayout*> layouts; - - for(unsigned int inf=0;inf<transform_hierarchy[level].size();inf++) - { - cerr<<"PNTransformDriver: Generating Layout Inference for "<<transform_hierarchy[level][inf]->GetInferenceName()<<endl; - PNStackLayout *tmp = (transform_hierarchy[level][inf])->GetPNStackLayout(func); - - if(tmp == NULL) - { - cerr<<"PNTransformDriver: NULL Inference Generated"<<endl; - } - else - { - cerr<<"PNTransformDriver: Inference Successfully Generated"<<endl; - layouts.push_back(tmp); - } - } - - return layouts; -} - -bool PNTransformDriver::ShuffleValidation(int reps, PNStackLayout *layout,Function_t *func) -{ - if(!layout->DoShuffleValidate()) - return true; - - cerr<<"PNTransformDriver: ShuffleValidation(): "<<layout->GetLayoutName()<<endl; - - for(int i=0;i<reps;i++) - { - if(timeExpired) - return false; - - cerr<<"PNTransformDriver: ShuffleValidation(): Shuffle attempt "<<i+1<<endl; - - layout->Shuffle(); - - if(!Sans_Canary_Rewrite(layout, func)) - { - undo(func); - cerr<<"PNTransformDriver: ShuffleValidation(): Rewrite Failure: attempt: "<<i+1<<" "<< - layout->GetLayoutName()<<" Failed to Rewrite "<<func->GetName()<<endl; - return false; - } - else if(!Validate(orig_virp,func->GetName())) - { - undo(func); - cerr<<"PNTransformDriver: ShuffleValidation(): Validation Failure: attempt: "<<i+1<<" "<< - layout->GetLayoutName()<<" Failed to Validate "<<func->GetName()<<endl; - return false; - } - else - { - undo(func); - } - } - - return true; -} - -// Validate the modifications for the passed in FileIR_t*, creating -// a directory structure for the generated spri files in a directory -// reflecting the passed in string. -// -// If the FileIR_t* is null, Validate will generate spri -// for as FileIR_t* that have been registered in the FileIR_t* -// registry (entries in this structure are made whenever -// a function has been registered for finalization). -// Passing NULL essentially provides a mechanism of revalidating all -// previously modified and validated functions. -bool PNTransformDriver::Validate(FileIR_t *virp, string name) -{ - if(!pn_options->getShouldSpriValidate()) - return true; - - cerr<<"PNTransformDriver: Validate(): "<<name<<endl; - - string dirname = "p1.xform/" + name; - string cmd = "mkdir -p " + dirname; - int res=system(cmd.c_str()); - assert(res!=-1); - - string aspri_filename = string(get_current_dir_name()) + "/" + dirname + "/a.irdb.aspri"; - string bspri_filename = string(get_current_dir_name()) + "/" + dirname + "/a.irdb.bspri"; - ofstream aspriFile; - aspriFile.open(aspri_filename.c_str()); - - if(!aspriFile.is_open()) - { - assert(false); - } - - cerr<<"Pre genreate SPRI"<<endl; - - if(virp == NULL) - { - //Generate spri for previous files - for(set<FileIR_t*>::iterator it=registered_firps.begin(); - it!=registered_firps.end(); - ++it - ) - { - FileIR_t *firp = *it; - firp->GenerateSPRI(aspriFile,false); - } - } - //generate spri for the current file - else - virp->GenerateSPRI(aspriFile,false); // p1.xform/<function_name>/a.irdb.aspri - cerr<<"Post genreate SPRI"<<endl; - aspriFile.close(); - - char new_instr[1024]; - //This script generates the aspri and bspri files; it also runs BED - sprintf(new_instr, "%s %d %s %s", BED_script.c_str(), orig_progid, aspri_filename.c_str(), bspri_filename.c_str()); - - //If OK=BED(func), then commit - int rt=system(new_instr); - int actual_exit = -1; -// int actual_signal = -1; - if (WIFEXITED(rt)) actual_exit = WEXITSTATUS(rt); -// else actual_signal = WTERMSIG(rt); - int retval = actual_exit; - - //TODO: I have set exit code status 3 to indicate spasm failure - //if spasm fails, there is no point in continuing. - assert(retval != 3); - - //TODO: was I supposed to do something with actual_signal? - - string asm_filename = string(get_current_dir_name()) + "/" + dirname + "/a.irdb.?spri.asm"; - string bin_filename = string(get_current_dir_name()) + "/" + dirname + "/a.irdb.?spri.asm.bin"; - string map_filename = string(get_current_dir_name()) + "/" + dirname + "/a.irdb.?spri.asm.map"; - string rm_command="rm -f "; - rm_command+=bspri_filename + " "; - rm_command+=asm_filename + " "; - rm_command+=bin_filename + " "; - rm_command+=map_filename + " "; - - ignore_result(system(rm_command.c_str())); // don't bother with an error check. - - return (retval == 0); -} - -unsigned int PNTransformDriver::GetRandomCanary() -{ - - /* get a canary value from the options. - * assume the options package is returning a full 32-bits of entropy. - */ - return pn_options->getCanaryValue(); - -#if 0 -/* note: this code is being careful to get a full 32-bits of entropy, and rand() is only promising 16-bits of entropy. - */ - //TODO: check for bias. - stringstream canary; - canary.str(""); - - //canary<<hex<<pn_options->GetCanaryValue(); - for(int i=0;i<8;i++) - { - canary<<hex<< (rand()%16); - } - unsigned int ret_val; - sscanf(canary.str().c_str(),"%x",&ret_val); - - return ret_val; -#endif -} - -bool PNTransformDriver::Canary_Rewrite(PNStackLayout *orig_layout, Function_t *func) -{ - ControlFlowGraph_t cfg(func); - - string esp_reg; - string word_dec; - if(FileIR_t::GetArchitectureBitWidth()==32) - { - esp_reg="esp"; - word_dec="dword"; - } - else - { - esp_reg="rsp"; - word_dec="qword"; - } - - if(verbose_log) - cout<<"PNTransformDriver: CanaryRewrite: Rewriting function named "<<func->GetName()<<endl; - - - //TODO: hack for TNE, assuming all virp is orig_virp now. - FileIR_t *virp = orig_virp; - - if(!orig_layout->IsCanarySafe()) - return Sans_Canary_Rewrite(orig_layout,func); - - PNStackLayout tmp = orig_layout->GetCanaryLayout(); - PNStackLayout *layout = &tmp; - vector<canary> canaries; - - vector<PNRange*> mem_objects = layout->GetRanges(); - - for(unsigned int i=0;i<mem_objects.size();i++) - { - canary c; - - int floating_canary_offset = 0; - - if (do_floating_canary) - { - // nb: get_saved_reg_size is 4 or 8 depending on architecture - int reg_size = get_saved_reg_size(); - floating_canary_offset = (rand() % (layout->GetAlteredAllocSize() - layout->GetOriginalAllocSize() - reg_size)); - floating_canary_offset -= (floating_canary_offset % reg_size); - assert(floating_canary_offset >= 0); - c.floating_offset = floating_canary_offset; - } - else - { - c.floating_offset = 0; - } - - c.esp_offset = mem_objects[i]->GetOffset() + mem_objects[i]->GetDisplacement() + mem_objects[i]->GetSize(); - c.esp_offset += floating_canary_offset; - - assert(c.esp_offset >= 0); - - //TODO: make this random - c.canary_val = GetRandomCanary(); - - //bytes to frame pointer or return address (depending on if a frame - //pointer is used) from the stack pointer - c.ret_offset = (layout->GetAlteredAllocSize()+layout->GetSavedRegsSize()); - //if frame pointer is used, add 4/8 bytes to get to the return address - if(layout->HasFramePointer()) - c.ret_offset += get_saved_reg_size(); - - //Now with the total size, subtract off the esp offset to the canary - c.ret_offset = c.ret_offset - c.esp_offset; - - //The number should be positive, but we want negative so - //convert to negative - c.ret_offset = c.ret_offset*-1; - - if(verbose_log) - cerr << "c.canary_val = " << hex << c.canary_val << " c.ret_offset = " << dec << c.ret_offset << " c.esp_offset = " << c.esp_offset << " floating canary offset = " << floating_canary_offset << " (max: " << layout->GetAlteredAllocSize()-layout->GetOriginalAllocSize()<< ")" << endl; - - canaries.push_back(c); - } - - //bool stack_alloc = false; - int max = PNRegularExpressions::MAX_MATCHES; - regmatch_t *pmatch=new regmatch_t[max]; - memset(pmatch, 0,sizeof(regmatch_t) * max); - - - - for( - set<Instruction_t*>::const_iterator it=func->GetInstructions().begin(); - it!=func->GetInstructions().end(); - ++it - ) - { - Instruction_t* instr=*it; - - string matched=""; - string disasm_str = ""; - //DISASM disasm; - - //Disassemble(instr,disasm); - const auto disasm=DecodedInstruction_t(instr); - disasm_str = disasm.getDisassembly() /*CompleteInstr*/; - - if(verbose_log) - cerr<<"PNTransformDriver: Canary_Rewrite: Looking at instruction "<<disasm_str<<endl; - - //TODO: is the stack_alloc flag necessary anymore? - //if(!stack_alloc && regexec(&(pn_regex->regex_stack_alloc), disasm_str.c_str(), 5, pmatch, 0)==0) - if(regexec(&(pn_regex->regex_stack_alloc), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(verbose_log) - cerr << "PNTransformDriver: Canary Rewrite: Transforming Stack Alloc"<<endl; - - //TODO: determine size of alloc, and check if consistent with alloc size? - - //extract K from: sub esp, K - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - //extract K - unsigned int ssize; - if(str2uint(ssize, matched.c_str()) != STR2_SUCCESS) - { - //If this occurs, then the found stack size is not a - //constant integer, so it must be a register. - - //cerr<<"PNTransformDriver: Canary Rewrite: Stack alloc of non-integral type ("<<matched<<"), ignoring instruction "<<endl; - - //TODO: hack for TNE, assuming that isntruction_rewrite - //will add padding to dynamic arrays. - Instruction_Rewrite(layout,instr,&cfg); - continue; - } - } - - //TODO: I need a check to see if the previous amount is equal to - //the expect stack frame, a check is done is the inference - //generation now, so it should be okay without it, - - stringstream ss; - ss << hex << layout->GetAlteredAllocSize(); - - disasm_str = "sub " + esp_reg +", 0x"+ss.str(); - - if(verbose_log) - cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - //undo_list[instr] = instr->GetDataBits(); - //undo_list[instr] = copyInstruction(instr); - undo_list[func][instr] = copyInstruction(instr); - - virp->RegisterAssembly(instr,disasm_str); -/* - if(!instr->Assemble(disasm_str)) - return false; -*/ - //stack_alloc = true; - - for(unsigned int i=0;i<canaries.size();i++) - { - ss.str(""); - ss<<"mov "<<word_dec<<" ["<<esp_reg<<"+0x"<<hex<<canaries[i].esp_offset - <<"], 0x"<<hex<<canaries[i].canary_val; - instr = insertAssemblyAfter(virp,instr,ss.str()); - if(i==0) - instr->SetComment("Canary Setup Entry: "+ss.str()); - else - instr->SetComment("Canary Setup: "+ss.str()); - if(verbose_log) - cerr << "PNTransformDriver: canary setup = " << ss.str() << endl; - } - } - else if(regexec(&(pn_regex->regex_ret), disasm_str.c_str(),5,pmatch,0)==0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Canary Rewrite: inserting ret canary check"<<endl; - - //undo_list[instr] = instr->GetDataBits(); - //undo_list[instr] = copyInstruction(instr); - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - - - - //This could probably be done once, but having the original instruction - //allows me to produce messages that indicate more precisely where - //the overflow occurred. - Instruction_t *handler_code = getHandlerCode(virp,instr,GetMitigationPolicy(),GetDetectionExitCode()); - - //insert canary checks - // - //TODO: may need to save flags register - - for(unsigned int i=0;i<canaries.size();i++) - { - instr = insertCanaryCheckBefore(virp,instr,canaries[i].canary_val,canaries[i].ret_offset, handler_code); - } - } - //if the stack is not believed to be static, I can't check the canary using esp. - //for now don't do a canary check on calls in these situations. - else if(layout->IsStaticStack() && regexec(&(pn_regex->regex_call), disasm_str.c_str(),5,pmatch,0)==0) - { - - if(verbose_log) - cerr<<"PNTransformDriver: Canary Rewrite: inserting call canary check"<<endl; - //undo_list[instr] = copyInstruction(instr); - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - - //This could probably be done once, but having the original instruction - //allows me to produce messages that indicate more precisely where - //the overflow occurred. - Instruction_t *handler_code = getHandlerCode(virp,instr,GetMitigationPolicy(),GetDetectionExitCode()); - - //insert canary checks - // - //TODO: may need to save flags register - for(unsigned int i=0;i<canaries.size();i++) - { - instr = insertCanaryCheckBefore(virp,instr,canaries[i].canary_val,canaries[i].esp_offset, handler_code); - } - } - //TODO: message if not static stack? - else - { - if(!Instruction_Rewrite(layout,instr, &cfg)) - return false; - } - } - - - orig_layout->SetCanaries(canaries); -// orig_layout->SetBaseID(func->GetBaseID()); -// orig_layout->SetEntryID(func->GetEntryPoint()->GetBaseID()); - - EhUpdater_t eh_update(orig_virp, func, layout); - if(!eh_update.execute()) - return false; - - return true; -} - -bool PNTransformDriver::Sans_Canary_Rewrite(PNStackLayout *layout, Function_t *func) -{ - //TODO: add return value - if(verbose_log) - cerr<<"PNTransformDriver: Sans Canary Rewrite for Function = "<<func->GetName()<<endl; - - ControlFlowGraph_t cfg(func); - - for( - set<Instruction_t*>::const_iterator it=func->GetInstructions().begin(); - it!=func->GetInstructions().end(); - ++it - ) - { - Instruction_t* instr=*it; - string disasm_str = ""; - //DISASM disasm; - //Disassemble(instr,disasm); - const auto disasm=DecodedInstruction_t(instr); - disasm_str = disasm.getDisassembly() /*CompleteInstr*/; - - if(verbose_log) - cerr<<"PNTransformDriver: Sans_Canary_Rewrite: Looking at instruction "<<disasm_str<<endl; - - if(!Instruction_Rewrite(layout,instr,&cfg)) - return false; - } - - EhUpdater_t eh_update(orig_virp, func, layout); - if(!eh_update.execute()) - return false; - - return true; -} - - - -static Instruction_t* GetNextInstruction(Instruction_t *prev, Instruction_t* insn, Function_t* func) -{ - Instruction_t* ft=insn->GetFallthrough(); - Instruction_t* targ=insn->GetTarget(); - - /* if there's a fallthrough, but no targ, and the fallthrough is in the function */ - if(ft && !targ && func->GetInstructions().find(ft)!=func->GetInstructions().end()) - return ft; - - /* if there's a target, but no fallthrough, and the target is in the function */ - if(!ft && targ && func->GetInstructions().find(targ)!=func->GetInstructions().end()) - return targ; - - return NULL; -} - -// -// PNTransformDriver::prologue_offset_to_actual_offset - -// Look in the CFG to see if instr is in the prologue before the stack allocation instruction. -// If so, attempt to adjust offset so that it is relative to the offset after the stack has -// been allocated. Return adjusted offset if succesfful, else unadjusted offset. -// -int PNTransformDriver::prologue_offset_to_actual_offset(ControlFlowGraph_t* cfg, Instruction_t *instr,int offset) -{ - Function_t* func=cfg->GetFunction(); - assert(func); - BasicBlock_t* entry_block=cfg->GetEntry(); - if(!entry_block) - return offset; - - /* find the instruction in the vector */ - set<Instruction_t*>::iterator it= func->GetInstructions().find(instr); - - /* if the instruction isn't in the entry block, give up now */ - if( it == func->GetInstructions().end()) - return offset; - - - Instruction_t* insn=*it, *prev=NULL; - for(int i=0;insn!=NULL && i<MAX_JUMPS_TO_FOLLOW; ++i, insn=GetNextInstruction(prev,insn, func)) - { - assert(insn); - //DISASM d; - //Disassemble(insn,d); - const auto d=DecodedInstruction_t(insn); - string disasm_str=d.getDisassembly() /*CompleteInstr*/; - - //if(strstr(d.CompleteInstr, "push")!=NULL) - if(d.getMnemonic()=="push") - return offset; - - int max = PNRegularExpressions::MAX_MATCHES; - //regmatch_t pmatch[max]; - regmatch_t *pmatch=new regmatch_t[max]; // (max*sizeof(regmatch_t)); - - /* check for a stack alloc */ - if(regexec(&(pn_regex->regex_stack_alloc), d.getDisassembly().c_str() /*CompleteInstr*/, 5, pmatch, 0)==0) - { - - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - string matched=""; - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - //extract K - unsigned int ssize; - if(str2uint(ssize, matched.c_str()) != STR2_SUCCESS) - { - return offset; - } - // found! - // mov ... [rsp+offset] ... - // sub rsp, ssize - // note: offset is negative - - // sanity check that the allocation iss bigger than the neg offset - assert((unsigned)ssize==(unsigned)ssize); - if(-offset>(int)ssize) - return offset; - - // success - return offset+ssize; - - } - return offset; - - } - // else, check next instruction - - - } - - return offset; - -} - -inline bool PNTransformDriver::Instruction_Rewrite(PNStackLayout *layout, Instruction_t *instr, ControlFlowGraph_t* cfg) -{ - FileIR_t* virp = orig_virp; - - string esp_reg="esp"; - if(FileIR_t::GetArchitectureBitWidth()==64) - esp_reg="rsp"; - - const int max = PNRegularExpressions::MAX_MATCHES; - //regmatch_t pmatch[max]; - regmatch_t *pmatch=new regmatch_t[max]; // (regmatch_t*)malloc(max*sizeof(regmatch_t)); - regmatch_t pmatch2[max]; - memset(pmatch, 0,sizeof(regmatch_t) * max); - memset(pmatch2, 0,sizeof(regmatch_t) * max); - - string matched=""; - string disasm_str = ""; - //DISASM disasm; - //Disassemble(instr,disasm); - const auto disasm=DecodedInstruction_t(instr); - disasm_str = disasm.getDisassembly() /*CompleteInstr*/; - - //the disassmebly of lea has extra tokens not accepted by nasm, remove those tokens - if(regexec(&(pn_regex->regex_lea_hack), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming LEA Instruction"<<endl; - - matched = ""; - for (int k = 1; k < 5; ++k) - { - if (pmatch[k].rm_so >= 0 && pmatch[k].rm_eo >= 0) - { - int mlen = pmatch[k].rm_eo - pmatch[k].rm_so; - matched.append(disasm_str.substr(pmatch[k].rm_so,mlen)); - } - } - disasm_str = matched; - if(verbose_log) - cerr<<"PNTransformDriver: New LEA Instruction = "<<disasm_str<<endl; - - matched = ""; - } - - - if(instr->GetFunction() && instr->GetFunction()->GetUseFramePointer() && regexec(&(pn_regex->regex_add_rbp), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(verbose_log) - cerr << "PNTransformDriver: found add rbp insn: "<<disasm_str<<endl; - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - string dstreg=disasm_str.substr(pmatch[1].rm_so,mlen); - - int new_offset = layout->GetNewOffsetEBP(1); /* make sure we get something from within the stack frame */ - new_offset-=1; /* re-adjust for the -8 above */ - - stringstream lea_string; - lea_string<<"lea "<<dstreg<<", [rbp+"<<dstreg<<" - 0x"<<std::hex<<new_offset<<"]"; - - - if(verbose_log) - cerr << "PNTransformDriver: Convrting to "<<lea_string.str()<<endl; - - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - virp->RegisterAssembly(instr,lea_string.str()); - - } - else if(regexec(&(pn_regex->regex_stack_alloc), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(verbose_log) - cerr << "PNTransformDriver: Transforming Stack Alloc"<<endl; - - //TODO: determine size of alloc, and check if consistent with alloc size? - - - //extract K from: sub esp, K - if (pmatch[1].rm_so >= 0 && pmatch[1].rm_eo >= 0) - { - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - //extract K - unsigned int ssize; - if(str2uint(ssize, matched.c_str()) != STR2_SUCCESS) - { - //If this occurs, then the found stack size is not a - //constant integer, so it must be a register. - - //cerr<<"PNTransformDriver: Stack alloc of non-integral type ("<<matched<<"), ignoring instruction"<<endl; - - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - //TODO: hack for TNE, padd the allocation by adding a random - //amount to the register used to subtract from esp. - - stringstream ss_add; - stringstream ss_sub; - //TODO: I am uncertain how alignment will work in this situation - //if the layout is aligned, this will return a padding amount - //divisible by the alignment stride, however, without knowing - //the size of the object, this may not ensure alignment, it is - //up to the compiler to handle that else where. - auto rand_pad=layout->GetRandomPadding(); - ss_add<<"add "<<esp_reg<<" , 0x"<<hex<<rand_pad;//"0x500"; - ss_sub<<"sub "<<esp_reg<<" , 0x"<<hex<<rand_pad;//"0x500"; - - if(verbose_log) - { - cerr<<"PNTransformDriver: adding padding to dynamic stack allocation"<<endl; - cerr<<"PNTransformDriver: inserted instruction before = "<<ss_add.str()<<endl; - cerr<<"PNTransformDriver: inserted instruction after = "<<ss_sub.str()<<endl; - } - - Instruction_t *new_instr = insertAssemblyBefore(virp,instr,ss_add.str(),NULL); - new_instr->SetComment("Dynamic array padding:" +ss_add.str()); - - insertAssemblyAfter(virp,instr,ss_sub.str(),NULL); - return true; - } - } - - stringstream ss; - ss << hex << layout->GetAlteredAllocSize(); - - disasm_str = "sub "+esp_reg+", 0x"+ss.str(); - - if(verbose_log) - cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - //undo_list[instr] = instr->GetDataBits(); - //undo_list[instr] = copyInstruction(instr); - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - - virp->RegisterAssembly(instr,disasm_str); - -/* - if(!instr->Assemble(disasm_str)) - return false; -*/ - - //stack_alloc = true; - } - else if(regexec(&(pn_regex->regex_and_esp), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr << "PNTransformDriver: and_esp pattern matched, ignoring"<<endl; -/* - cerr<<"PNTransformDriver: Transforming AND ESP instruction"<<endl; - - disasm_str = "nop"; - - cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - - undo_list[instr] = copyInstruction(instr); - if(!instr->Assemble(disasm_str)) - return false; -*/ - } - else if(regexec(&(pn_regex->regex_esp_scaled_nodisp), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming ESP +scale w/o displacement Instruction ([esp+reg*scale])"<<endl; - - PNRange *closest = layout->GetClosestRangeESP(0); - - if(closest == NULL) - { - //There should always be a closet range to esp+0 - assert(false); - } - - int new_offset = closest->GetDisplacement(); - - assert(new_offset >= 0); - - if(new_offset == 0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Displacement of [esp+reg*scale] is Zero, Ignoring Transformation"<<endl; - - return true; - } - - stringstream ss; - ss<<hex<<new_offset; - - matched=((string)"+ 0x")+ss.str()+"]"; - - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - assert(mlen==1); - - disasm_str.replace(pmatch[1].rm_so,mlen,matched); - - if(verbose_log) - cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - //undo_list[instr] = instr->GetDataBits(); - //undo_list[instr] = copyInstruction(instr); - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - - virp->RegisterAssembly(instr,disasm_str); - -/* - if(!instr->Assemble(disasm_str.c_str())) - return false; -*/ - - } - else if(regexec(&(pn_regex->regex_esp_only), disasm_str.c_str(), max, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming ESP Only Instruction ([esp])"<<endl; - - PNRange *closest = layout->GetClosestRangeESP(0); - - if(closest == NULL) - { - //There should always be a closet range to esp+0 - assert(false); - } - - int new_offset = closest->GetDisplacement(); - - assert(new_offset >= 0); - - if(new_offset == 0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Displacement of [esp] is Zero, Ignoring Transformation"<<endl; - - return true; - } - - stringstream ss; - ss<<hex<<new_offset; - - matched = esp_reg+"+0x"+ss.str(); - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - disasm_str.replace(pmatch[1].rm_so,mlen,matched); - - if(verbose_log) - cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - //undo_list[instr] = instr->GetDataBits(); - //undo_list[instr] = copyInstruction(instr); - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - - virp->RegisterAssembly(instr,disasm_str); - -/* - if(!instr->Assemble(disasm_str.c_str())) - return false; -*/ - - } -#if 1 - else if(regexec(&(pn_regex->regex_esp_direct_negoffset), disasm_str.c_str(), 5, pmatch, 0)==0) - { - - if(verbose_log) - { - cerr<<"PNTransformDriver: Transforming ESP-k Relative Instruction"<<endl; - } - - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - //TODO: I don't think this can happen but just in case - assert(offset > 0); - - int revised_offset=prologue_offset_to_actual_offset(cfg,instr,-offset); - - if(revised_offset<0) - { - if(verbose_log) - cerr<<"PNTransformDriver: ignoring, not in prologue "<<endl; - - } - else - { - if(verbose_log) - cerr<<"PNTransformDriver: ESP-k revised_offset is "<<std::hex<<revised_offset<<endl; - int new_location = layout->GetNewOffsetESP(revised_offset); - if(verbose_log) - cerr<<"PNTransformDriver: ESP-k new_location is "<<std::hex<<new_location<<endl; - int new_offset = new_location-layout->GetAlteredAllocSize(); - if(verbose_log) - cerr<<"PNTransformDriver: ESP-k new_offset is "<<std::hex<<new_offset<<endl; - - // sanity - assert(new_offset<0); - - stringstream ss; - ss<<hex<<(- new_offset); // neg sign already in string - - matched = "0x"+ss.str(); - - disasm_str.replace(pmatch[1].rm_so,mlen,matched); - - if(verbose_log) - cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - - virp->RegisterAssembly(instr,disasm_str); - } - } -#endif -//TODO: the regular expression order does matter, scaled must come first, change the regex so this doesn't matter - else if(regexec(&(pn_regex->regex_esp_scaled), disasm_str.c_str(), 5, pmatch, 0)==0 || - regexec(&(pn_regex->regex_esp_direct), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming ESP Relative Instruction"<<endl; - - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - //TODO: I don't think this can happen but just in case - assert(offset >= 0); - - - // an ESP+<scale>+<const> that points at - // the saved reg area isn't likely realy indexing the saved regs. assume it's in the - // local var area instead. - int new_offset = 0; - if((int)offset==(int)layout->GetOriginalAllocSize() && - regexec(&(pn_regex->regex_esp_scaled), disasm_str.c_str(), 5, pmatch2, 0)==0) - { - if(verbose_log) - cerr<<"JDH: PNTransformDriver: found esp+scale+const pointing at saved regs."<<endl; - new_offset=layout->GetNewOffsetESP(offset-1)+1; - } - else - new_offset=layout->GetNewOffsetESP(offset); - - stringstream ss; - ss<<hex<<new_offset; - - matched = "0x"+ss.str(); - - disasm_str.replace(pmatch[1].rm_so,mlen,matched); - - if(verbose_log) - cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - //undo_list[instr] = instr->GetDataBits(); - //undo_list[instr] = copyInstruction(instr); - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - - virp->RegisterAssembly(instr,disasm_str); - -/* - if(!instr->Assemble(disasm_str.c_str())) - return false; -*/ - } - //TODO: the regular expression order does matter, scaled must come first, change the regex so this doesn't matter - //for lea esp, [ebp-<const>] it is assumed the <const> will not be in the stack frame, so it should be ignored. - //this should be validated prior to rewrite (i.e., this is a TODO, it hasn't been done yet). - else if(regexec(&(pn_regex->regex_ebp_scaled), disasm_str.c_str(), 5, pmatch, 0)==0 || - regexec(&(pn_regex->regex_ebp_direct), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming EBP Relative Instruction"<<endl; - - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - if(verbose_log) - cerr<<"PNTransformDriver: Offset = "<<offset<<endl; - - int new_offset = layout->GetNewOffsetEBP(offset); - - if(new_offset == offset) - { - if(verbose_log) - cerr<<"PNTransformDriver: No offset transformation necessary, skipping instruction"<<endl; - - return true; - } - - stringstream ss; - ss<<hex<<new_offset; - - matched = "0x"+ss.str(); - - disasm_str.replace(pmatch[1].rm_so,mlen,matched); - - if(verbose_log) - cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - - //undo_list[instr] = instr->GetDataBits(); - //undo_list[instr] = copyInstruction(instr); - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - - virp->RegisterAssembly(instr,disasm_str); - -/* - if(!instr->Assemble(disasm_str.c_str())) - return false; -*/ - - } - //if we get an instruction where ebp is the index, transform it using the - //offset as the lookup (the second pattern matched), however, it is assumed - //that only p1 is performed in these cases. - //TODO: if this is encountered, insert a switch statement to evaluate at runtime - //which offset to use. e.g., [ecx+ebp*1-0x21], at run time evaluate ecx+0x21, - //and determine which reange it falls into, and jump to an instruction which - //uses the correct offset. - else if(regexec(&(pn_regex->regex_scaled_ebp_index), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming Scaled EBP Indexed Instruction"<<endl; - - int mlen = pmatch[2].rm_eo - pmatch[2].rm_so; - matched = disasm_str.substr(pmatch[2].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - if(verbose_log) - cerr<<"PNTransformDriver: Offset = "<<offset<<endl; - - int new_offset = layout->GetNewOffsetEBP(offset); - - if(new_offset == offset) - { - if(verbose_log) - cerr<<"PNTransformDriver: No offset transformation necessary, skipping instruction"<<endl; - - return true; - } - - stringstream ss; - ss<<hex<<new_offset; - - matched = "0x"+ss.str(); - - disasm_str.replace(pmatch[2].rm_so,mlen,matched); - - if(verbose_log) - cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - //undo_list[instr] = instr->GetDataBits(); - //undo_list[instr] = copyInstruction(instr); - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - - virp->RegisterAssembly(instr,disasm_str); - -/* - if(!instr->Assemble(disasm_str.c_str())) - return false; -*/ - } - else if(regexec(&(pn_regex->regex_stack_dealloc), disasm_str.c_str(), 5, pmatch, 0)==0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Transforming Stack Dealloc Instruction"<<endl; - - //Check if the dealloc amount is 0. In unoptimized code, sometimes the - //compiler will reset esp, and then add 0 to esp - //In this case, do not deallocate the stack - - int mlen = pmatch[1].rm_eo - pmatch[1].rm_so; - matched = disasm_str.substr(pmatch[1].rm_so,mlen); - - // extract displacement - int offset = strtol(matched.c_str(),NULL,0); - - if(verbose_log) - cerr<<"PNTransformDriver: Dealloc Amount = "<<offset<<endl; - - if(offset == 0) - { - if(verbose_log) - cerr<<"PNTransformDriver: Dealloc of 0 detected, ignoring instruction"<<endl; - - return true; - } - - stringstream ss; - ss << hex <<layout->GetAlteredAllocSize(); - - disasm_str = "add "+esp_reg+", 0x"+ss.str(); - - //undo_list[instr] = instr->GetDataBits(); - //undo_list[instr] = copyInstruction(instr); - undo_list[instr->GetFunction()][instr] = copyInstruction(instr); - - if(verbose_log) - cerr<<"PNTransformDriver: New Instruction = "<<disasm_str<<endl; - - virp->RegisterAssembly(instr,disasm_str); -/* - if (!instr->Assemble(disasm_str)) - return false; -*/ - } - else - { - if(verbose_log) - { - cerr<<"PNTransformDriver: No Pattern Match"; - if(strstr(disasm_str.c_str(), "rsp")!=NULL || - strstr(disasm_str.c_str(), "esp")!=NULL) - cerr<<"BUT CAUTION ******************* esp/rsp found in instruction."; - cerr<<endl; - } - } - return true; -} - - - -//TODO: there is a memory leak, I need to write a undo_list clear to properly cleanup -//void PNTransformDriver::undo(map<Instruction_t*, Instruction_t*> undo_list, Function_t *func) -void PNTransformDriver::undo(Function_t *func) -{ - string func_name = func->GetName(); - - //rollback any changes - cerr<<"PNTransformDriver: Undo Transform: "<<undo_list[func].size()<<" instructions to rollback for function "<<func_name<<endl; - for( - map<Instruction_t*, Instruction_t*>::const_iterator mit=undo_list[func].begin(); - mit != undo_list[func].end(); - ++mit) - { - Instruction_t* alt = mit->first; - Instruction_t* orig = mit->second; - - copyInstruction(orig,alt); - - orig_virp->UnregisterAssembly(alt); - - //TODO: apparently there is a issue with this delete. - //When using the padding/shuffle transformation PN terminates - //for some reason with no segfault. Removing this delete - //solves the issue. Using the canary transformation, I haven't - //observed the same issue however there are fewer undos when - //using the canary transform. -// delete orig; - } - - for(set<Instruction_t*>::const_iterator it=inserted_instr[func].begin(); - it != inserted_instr[func].end(); - ++it - ) - { - orig_virp->UnregisterAssembly(*it); - orig_virp->GetInstructions().erase(*it); - func->GetInstructions().erase(*it); - delete *it; - } - - for(set<AddressID_t*>::const_iterator it=inserted_addr[func].begin(); - it != inserted_addr[func].end(); - ++it - ) - { - orig_virp->GetAddresses().erase(*it); - delete *it; - } - //reset_undo(func->GetName()); - - undo_list.erase(func); - inserted_instr.erase(func); - inserted_addr.erase(func); - //undo_list.clear(); -} - -/* - void PNTransformDriver::reset_undo(string func) - { - undo_list.erase(func); - inserted_instr.erase(func); - inserted_addr.erase(func); - } -*/ - - -bool PNTransformDriver::WriteStackIRToDB() -{ - // DEBUG - cerr << "Writing stack IR to IRDB!" << endl; - - PNIrdbManager irdb_manager(this->pidp->GetOriginalVariantID()); - if (!irdb_manager.TableExists()) - { - irdb_manager.CreateTable(); - } - else - { - irdb_manager.DeleteSource(PNIrdbManager::IRS_PEASOUP); - } - - std::map< std::string,std::vector<PNStackLayout*> >::const_iterator it = - transformed_history.begin(); - while (it != transformed_history.end()) - { - vector<PNStackLayout*> layouts = it->second; - for (unsigned int laynum = 0; laynum < layouts.size(); ++laynum) - { - // DEBUG - cerr << "Function: " << layouts[laynum]->GetFunctionName() << endl; - - std::vector<PNRange*> mem_objects = layouts[laynum]->GetRanges(); - for(unsigned int j = 0; j < mem_objects.size(); j++) - { - libIRDB::db_id_t new_id = irdb_manager.InsertStackObject( - layouts[laynum]->GetFunctionName(), - mem_objects[j]->GetOffset(), - mem_objects[j]->GetSize(), - PNIrdbManager::IRS_PEASOUP); - - // DEBUG - cerr<< "\tOffset = " << mem_objects[j]->GetOffset() << " Size = "<<mem_objects[j]->GetSize() << endl; - - // return with failure if any insertion fails - if (new_id == -1) - return false; - } - } - - it++; - } - - return true; -} - -void sigusr1Handler(int signum) -{ - PNTransformDriver::timeExpired = true; -} - -void PNTransformDriver::Print_Map() -{ - - map<string, vector<PNStackLayout*> >::const_iterator it; - - string exe_uri = orig_virp->GetFile()->GetURL(); - string map_uri = "p1.map"; - - ofstream map_file; - map_file.open(map_uri.c_str()); - - cerr << "exe_uri: " << exe_uri << endl; - cerr << "p1 map uri: " << map_uri << endl; - - map_file << "LAYOUT" << ";FUNCTION"<< ";FRAME_ALLOC_SIZE" << ";ALTERED_FRAME_SIZE" << ";SAVED_REG_SIZE" << ";OUT_ARGS_SIZE" << - ";NUM_MEM_OBJ" << ";PADDED" << ";SHUFFLED" << ";CANARY_SAFE" << ";CANARY" << ";FUNC_BASE_ID" << ";FUNC_ENTRY_ID" << ";CANARY_FLOATING_OFFSET" << "\n"; - - for(it = transformed_history.begin(); it != transformed_history.end(); it++) - { - for(unsigned int i=0;i<it->second.size();i++) - { - map_file << "" << it->second[i]->ToMapEntry() << endl; - } - - } - - map_file.close(); -} diff --git a/tools/transforms/PNTransformDriver.hpp b/tools/transforms/PNTransformDriver.hpp deleted file mode 100644 index 56ef2b8ee..000000000 --- a/tools/transforms/PNTransformDriver.hpp +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __PNTRANSFORMDRIVER -#define __PNTRANSFORMDRIVER - -#include <vector> -#include <set> -#include <exeio.h> -#include "PNStackLayoutInference.hpp" -#include "PNRegularExpressions.hpp" -#include <csignal> -#include "Rewrite_Utility.hpp" -#include <libIRDB-core.hpp> -#include <libIRDB-cfg.hpp> -#include "canary.h" -//#include <bea_deprecated.hpp> - - -//TODO: I should use the types defined by beaengine -//#define RetType 13 -//#define JmpType 11 -//#define CallType 12 - - -struct finalize_record -{ - Function_t *func; - PNStackLayout* layout; - FileIR_t *firp; -}; - -struct validation_record -{ - unsigned int hierarchy_index; - unsigned int layout_index; - vector<PNStackLayout*> layouts; - Function_t *func; -}; - - -class PNTransformDriver -{ - protected: - - libIRDB::VariantID_t *pidp; - libIRDB::FileIR_t *orig_virp; - EXEIO::exeio* elfiop; - std::string BED_script; - int orig_progid; - bool do_canaries; - bool do_floating_canary; - bool do_align; - //TODO: coverage map should not use function name as the key, since - //we may want to support coverage for shared objects. - std::map<std::string,std::map<std::string,double> > coverage_map; - int no_validation_level; - double coverage_threshold; - bool do_shared_object_protection; - - std::vector< std::vector<PNStackLayoutInference*> > transform_hierarchy; - PNRegularExpressions *pn_regex; - std::set<std::string> blacklist; - std::set<libIRDB::Function_t*> sanitized; - std::set<std::string> only_validate_list; - //std::map<libIRDB::Instruction_t*,std::string> undo_list; - //std::map<libIRDB::Instruction_t*,libIRDB::Instruction_t*> undo_list; - std::map<libIRDB::Function_t*, std::map<libIRDB::Instruction_t*,libIRDB::Instruction_t*> > undo_list; - std::map< std::string,std::vector<PNStackLayout*> > transformed_history; - int blacklist_funcs; - int sanitized_funcs; - int push_pop_sanitized_funcs; - int cond_frame_sanitized_funcs; - int bad_variadic_func_sanitized; - int jump_table_sanitized; - int pic_jump_table_sanitized; - int eh_sanitized; - int total_funcs; - int dynamic_frames; - std::vector<std::string> not_transformable; - std::vector<libIRDB::Function_t*> failed; - std::vector<finalize_record> finalization_registry; - std::set<FileIR_t*> registered_firps; - int high_coverage_count, low_coverage_count, no_coverage_count, validation_count; - - // write stack objects to IRDB - bool write_stack_ir_to_db; - - mitigation_policy m_mitigation_policy; - unsigned m_exit_code; - - // a way to map an instruction to it's set of predecessors. - std::map< Instruction_t* , set<Instruction_t*> > preds; - -//virtual bool Rewrite(PNStackLayout *layout, libIRDB::Function_t *func); -//virtual bool LayoutValidation(PNStackLayout *layout); -//virtual void undo(std::map<libIRDB::Instruction_t*,std::string> undo_list, libIRDB::Function_t *func); -//virtual void reset_undo(std::string func); - - virtual bool Validate(libIRDB::FileIR_t *virp, std::string name); - virtual void undo( libIRDB::Function_t *func); - virtual std::vector<PNStackLayout*> GenerateInferences(libIRDB::Function_t *func, int level); - virtual bool ShuffleValidation(int reps, PNStackLayout *layout,libIRDB::Function_t *func); - virtual void ShuffleValidation(std::vector<validation_record> &vrs); -//virtual void GenerateTransforms2(libIRDB::FileIR_t *virp,std::vector<libIRDB::Function_t*> funcs,std::string BED_script, int progid); -//virtual bool ValidateLayout(PNStackLayout *layout,std::string BED_script,int progid); -//virtual bool Canary_Rewrite(FileIR_t *virp, PNStackLayout *orig_layout,libIRDB::Function_t *func); - - //altered for TNE hack for dyn array padding, assuming all virp is orig_virp - virtual bool Canary_Rewrite( PNStackLayout *orig_layout,libIRDB::Function_t *func); - virtual bool Sans_Canary_Rewrite(PNStackLayout *orig_layout, libIRDB::Function_t *func); - inline bool Instruction_Rewrite(PNStackLayout *layout, libIRDB::Instruction_t *instr, ControlFlowGraph_t* cfg); - inline bool FunctionCheck(libIRDB::Function_t* a, libIRDB::Function_t* b); - inline bool TargetFunctionCheck(libIRDB::Instruction_t* a, libIRDB::Instruction_t* b); - inline bool FallthroughFunctionCheck(libIRDB::Instruction_t* a, libIRDB::Instruction_t* b); - - virtual PNStackLayout* Get_Next_Layout(validation_record &vr); - - virtual void Print_Report(); - virtual void Print_Map(); - virtual void Update_FrameSize(); -// virtual bool CanaryTransformHandler(PNStackLayout *layout, libIRDB::Function_t *func,bool validate); - virtual bool PaddingTransformHandler(PNStackLayout *layout, libIRDB::Function_t *func,bool validate); - virtual bool LayoutRandTransformHandler(PNStackLayout *layout, libIRDB::Function_t *func, bool validate); - virtual void GenerateTransformsInit(); - virtual bool IsBlacklisted(libIRDB::Function_t *func); - virtual unsigned int GetRandomCanary(); - virtual void GenerateTransformsHidden(std::map<std::string,double> &file_coverage_map); - void SanitizeFunctions(); -//virtual bool WriteToDB(); - virtual bool WriteStackIRToDB(); - - virtual void Finalize_Transformation(); - void Register_Finalized(std::vector<validation_record> &vrs,unsigned int start, int length); - bool Validate_Recursive(std::vector<validation_record> &vrs, unsigned int start, int length);//,bool suspect=false); -//bool Validate_Linear(std::vector<validation_record> &vrs, unsigned int start, int length); - - // see .cpp - int prologue_offset_to_actual_offset(ControlFlowGraph_t* cfg, Instruction_t *instr,int offset); - bool check_jump_tables(Instruction_t* insn); - bool check_jump_table_entries(std::set<int> insn,Function_t *func); - bool check_for_PIC_switch_table64(Instruction_t* insn, libIRDB::DecodedInstruction_t disasm); - bool backup_until(const char* insn_type, Instruction_t *& prev, Instruction_t* orig); - void calc_preds(); - void InitNewFileIR(File_t* this_file); - - - pqxxDB_t *pqxx_interface; - -public: - static bool timeExpired; - //TODO: use unsigned int? - - PNTransformDriver(libIRDB::VariantID_t *pidp, std::string BED_script, pqxxDB_t *pqxx_if); - virtual ~PNTransformDriver(); - - //Level indicates the priority of the layout when attempting - //the transform. Levels start at 1 (the highest priority). A level less than 1 raises - //an exception (for now an assert will fail). If not level is - //provided, the default is level 1. - virtual void AddInference(PNStackLayoutInference *inference, int level=0); - virtual void AddBlacklist(std::set<std::string> &blacklist); - virtual void AddBlacklistFunction(std::string func_name); - virtual void AddOnlyValidateList(std::set<std::string> &only_validate_list); - virtual void SetDoCanaries(bool do_canaries); - virtual void SetDoFloatingCanary(bool do_floating_canary); - virtual void SetDoAlignStack(bool align_stack); - virtual void SetCoverageMap(std::map<std::string,std::map<std::string,double> > coverage_map); - virtual void SetNoValidationLevel(unsigned int no_validation_level); - virtual void SetCoverageThreshold(double threshold); - virtual void SetProtectSharedObjects(bool do_protection); - - virtual void GenerateTransforms(); - virtual void SetWriteStackIrToDb(bool setting) { write_stack_ir_to_db = setting; } - - inline virtual mitigation_policy GetMitigationPolicy() const { return m_mitigation_policy; } - virtual void SetMitigationPolicy(mitigation_policy policy) { m_mitigation_policy = policy; } - virtual unsigned GetDetectionExitCode() const { return m_exit_code; } - virtual void SetDetectionExitCode(unsigned p_exitCode) { m_exit_code = p_exitCode; } -}; - -#endif - diff --git a/tools/transforms/PrecedenceBoundaryGenerator.hpp b/tools/transforms/PrecedenceBoundaryGenerator.hpp deleted file mode 100644 index 8d0197982..000000000 --- a/tools/transforms/PrecedenceBoundaryGenerator.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __PRECEDENCEBOUNDGEN -#define __PRECEDENCEBOUNDGEN -#include <libIRDB-core.hpp> -#include <libIRDB-cfg.hpp> -#include "Range.hpp" -#include "StackLayout.hpp" - -class PrecedenceBoundaryGenerator -{ -public: - virtual ~PrecedenceBoundaryGenerator(){} - virtual std::vector<Range> GetBoundaries(libIRDB::Function_t *func)=0; -}; - -#endif diff --git a/tools/transforms/PrecedenceBoundaryInference.cpp b/tools/transforms/PrecedenceBoundaryInference.cpp deleted file mode 100644 index 8b9fe5987..000000000 --- a/tools/transforms/PrecedenceBoundaryInference.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "OffsetInference.hpp" -#include "PrecedenceBoundaryInference.hpp" -#include "General_Utility.hpp" -//#include "beaengine/BeaEngine.h" -#include <cassert> -#include <iostream> -#include <cstdlib> -#include <set> -#include <fstream> -#include <algorithm> - -using namespace std; -using namespace libIRDB; - - -static bool CompareRangeBaseOffset(Range a, Range b) -{ - return (a.GetOffset() < b.GetOffset()); -} - -//TODO: I am basically repeating this code from StackLayout.cpp for a slighly different purpose, I should abstract -//out a binary search utility. -//assuming the vector is sorted -static unsigned int GetClosestIndex(vector<Range> ranges, int loc) -{ - - int high = ((int)ranges.size())-1; - int low = 0; - int mid; - - while(low <= high) - { - mid = (low+high)/2; - if((loc < (ranges[mid].GetOffset()+(int)ranges[mid].GetSize())) && (loc >= ranges[mid].GetOffset())) - return mid; - else if(loc > ranges[mid].GetOffset()) - low = mid +1; - else - high = mid -1; - } - return -1; -} - - - -PNStackLayout* PrecedenceBoundaryInference::GetPNStackLayout(libIRDB::Function_t *func) -{ - if(!base_inference || !pbgen) - return NULL; - - vector<Range> ranges = pbgen->GetBoundaries(func); - - cerr<<"PrecedenceBoundaryInference: ranges found = "<<ranges.size()<<endl; - if(ranges.size() == 0) - return NULL; - - PNStackLayout *base_layout = base_inference->GetPNStackLayout(func); - - if(!base_layout || !base_layout->IsStaticStack()) - return NULL; - - StackLayout precedence_layout(GetInferenceName(),base_layout->GetFunctionName(),base_layout->GetOriginalAllocSize(), - base_layout->GetSavedRegsSize(), base_layout->HasFramePointer(), base_layout->GetOutArgsSize()); - - //cerr<<"PrecedenceLayoutInference: inf name="<<GetInferenceName()<<" func name= "<<base_layout->GetFunctionName()<<" stack alloc size="<<base_layout->GetOriginalAllocSize()<<" saved regs size="<<base_layout->GetSavedRegsSize()<<" has frame pointer="<< base_layout->HasFramePointer()<<" out args size="<< base_layout->GetOutArgsSize()<<endl; - - - StackLayout slayout = base_layout->GetStackLayout(); - vector<Range> pnranges= slayout.GetRanges(); - - vector<Range> espranges; - - //TODO: for now I need to transform offsets to esp to keep everything consistent - for(unsigned int i=0;i<ranges.size();i++) - { - Range cur; - cur.SetOffset(ranges[i].GetOffset()); - cur.SetSize(ranges[i].GetSize()); - - if(ranges[i].GetOffset() < 0) - { - cur.SetOffset(slayout.EBPToESP(-1*ranges[i].GetOffset())); - } - espranges.push_back(cur); - } - - sort(espranges.begin(),espranges.end(),CompareRangeBaseOffset); - - - //get transitive closure of offsets - //TODO: should this be done in the generator? Requires knowing layout. - vector<Range> closure_ranges; - - Range cur; - cur.SetOffset(espranges[0].GetOffset()); - cur.SetSize(espranges[0].GetSize()); - - for(unsigned int i=1;i<espranges.size();i++) - { - int next_offset = espranges[i].GetOffset(); - unsigned int next_size = espranges[i].GetSize(); - - //if the next element's offset falls in the current range's boundary - //and its size exceeds the current range's boundary, then expand the - //current range to include this range. - - //TODO: casting cur.GetSize() to an int in two places below. - //make sure size isn't greater than int max, although I don't - //think this will happen and I don't know what to do if I see - //it occur. - if((next_offset >= cur.GetOffset()) && - (next_offset < ((int)cur.GetSize()+cur.GetOffset())) && - ((next_offset+next_size) > (cur.GetOffset()+cur.GetSize()))) - { - cur.SetSize(next_size + (next_offset-cur.GetOffset())); - } - else if(next_offset > (cur.GetOffset() + (int)cur.GetSize())) - { - closure_ranges.push_back(cur); - cur.SetOffset(next_offset); - cur.SetSize(next_size); - } - //else the next bound is completely inside the cur, so ignore. - } - - closure_ranges.push_back(cur); - - //insert all the precedence boundaries - for(unsigned int i=0;i<closure_ranges.size();i++) - { - precedence_layout.InsertESPOffset(closure_ranges[i].GetOffset()); - precedence_layout.InsertESPOffset(closure_ranges[i].GetOffset()+closure_ranges[i].GetSize()); - } - - for(unsigned int i=0;i<pnranges.size();i++) - { - //look for the offset and the offset+size for each pnrange - //if not found, -1 is returned, and in this case we want to insert - //the offset into the inference. Otherwise, the location exists inside - //one of the precedence boundaries, and therefore we should not insert. - if(GetClosestIndex(closure_ranges,pnranges[i].GetOffset()) < 0) - precedence_layout.InsertESPOffset(pnranges[i].GetOffset()); - - if(GetClosestIndex(closure_ranges,pnranges[i].GetOffset()+pnranges[i].GetSize()) < 0) - precedence_layout.InsertESPOffset(pnranges[i].GetOffset()+pnranges[i].GetSize()); - } - - //Since I am using annotations about calls to find offsets, there better - //be an out arguments region, if not, consider the loweset object the out - //args region and produce a new precedence_layout - //TODO: in the future I may want the option in stack layout to set - //the out args region after the fact. - if(precedence_layout.GetOutArgsRegionSize() == 0) - { - vector<Range> inserted_ranges = precedence_layout.GetRanges(); - - sort(inserted_ranges.begin(),inserted_ranges.end(),CompareRangeBaseOffset); - - unsigned int args_size = inserted_ranges[0].GetOffset()+inserted_ranges[0].GetSize(); - - StackLayout revised_playout(GetInferenceName(),base_layout->GetFunctionName(),base_layout->GetOriginalAllocSize(), - base_layout->GetSavedRegsSize(), base_layout->HasFramePointer(), args_size); - - for(unsigned int i=1;i<inserted_ranges.size();i++) - { - revised_playout.InsertESPOffset(inserted_ranges[i].GetOffset()+inserted_ranges[i].GetSize()); - } - -//I don't know why I marked these as not canary safe originally, I think this was -//to be somewhat conservative if the layout was incorrect, allowing the program -//to be agnostic to the change, but I am going to remove this requirement. -//and I have removed, as of this version, this inference from P1 -// revised_playout.SetCanarySafe(false); - - return new PNStackLayout(revised_playout, func); - } - -//I don't know why I marked these as not canary safe originally, I think this was -//to be somewhat conservative if the layout was incorrect, allowing the program -//to be agnostic to the change, but I am going to remove this requirement. -//and I have removed, as of this version, this inference from P1 -// precedence_layout.SetCanarySafe(false); - - return new PNStackLayout(precedence_layout, func); -} - -string PrecedenceBoundaryInference::GetInferenceName() const -{ - return string("Precedence Boundary Inference using "+(base_inference == NULL? "NULL" : base_inference->GetInferenceName())); -} diff --git a/tools/transforms/PrecedenceBoundaryInference.hpp b/tools/transforms/PrecedenceBoundaryInference.hpp deleted file mode 100644 index cab26a6c0..000000000 --- a/tools/transforms/PrecedenceBoundaryInference.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __PRECEDENCEBOUNDLAYOUTINFERENCE -#define __PRECEDENCEBOUNDLAYOUTINFERENCE -#include "PNStackLayoutInference.hpp" -#include "PNRegularExpressions.hpp" -#include "PrecedenceBoundaryGenerator.hpp" -#include <map> -#include <string> - -class PrecedenceBoundaryInference : public PNStackLayoutInference -{ -protected: - PNStackLayoutInference *base_inference; - PrecedenceBoundaryGenerator *pbgen; -public: - //deconstructor? - PrecedenceBoundaryInference(PNStackLayoutInference *inf, PrecedenceBoundaryGenerator *pbgen) : base_inference(inf) ,pbgen(pbgen) {/*TODO: exception if passed null?*/} - virtual PNStackLayout* GetPNStackLayout(libIRDB::Function_t *func); - virtual std::string GetInferenceName() const; -}; -#endif diff --git a/tools/transforms/Range.cpp b/tools/transforms/Range.cpp deleted file mode 100644 index 05f7e118c..000000000 --- a/tools/transforms/Range.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#include "Range.hpp" -#include <sstream> - -using namespace std; - -Range::Range() -{ - offset = 0; - size = 0; -} -/* - Range::Range(int base_offset, unsigned int size) - { - this->base_offset = base_offset; - this->size = size; - } -*/ -Range::Range(const Range &range) -{ - offset = range.offset; - size = range.size; -} - -int Range::GetOffset() const -{ - return offset; -} - -unsigned int Range::GetSize() const -{ - return size; -} - -void Range::SetOffset(int offset) -{ - this->offset = offset; -} - -void Range::SetSize(unsigned int size) -{ - this->size = size; -} - -string Range::ToString() const -{ - stringstream ss; - ss<<"Offset = "<<offset<<" Size = "<<size; - return ss.str(); -} diff --git a/tools/transforms/Range.hpp b/tools/transforms/Range.hpp deleted file mode 100644 index 510faa482..000000000 --- a/tools/transforms/Range.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __RANGE -#define __RANGE - -#include <string> - -class Range -{ -protected: - int offset; - unsigned int size; -public: - Range(); - // Range(int base_offset, unsigned int size); - Range(const Range &range); - virtual int GetOffset() const; - virtual unsigned int GetSize() const; - virtual void SetOffset(int offset); - virtual void SetSize(unsigned int size); - virtual std::string ToString() const; -}; - -#endif diff --git a/tools/transforms/Rewrite_Utility.cpp b/tools/transforms/Rewrite_Utility.cpp deleted file mode 100644 index 8ddd9a587..000000000 --- a/tools/transforms/Rewrite_Utility.cpp +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "Rewrite_Utility.hpp" -using namespace std; -using namespace libIRDB; - -map<Function_t*, set<Instruction_t*> > inserted_instr; //used to undo inserted instructions -map<Function_t*, set<AddressID_t*> > inserted_addr; //used to undo inserted addresses - - -void setExitCode(FileIR_t* virp, Instruction_t* exit_code); - -//For all insertBefore functions: -//The "first" instruction will have its contents replaced and a duplicate of "first" will be in the follow of first. -//This duplicate is returned since the user already has a pointer to first. -//To insert before an instruction is the same as modifying the original instruction, and inserting after it -//a copy of the original instruction -Instruction_t* insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target) -{ - Instruction_t* next = copyInstruction(virp,first); - - //In case the fallthrough is null, generate spri has to have a - //place to jump, which is determined by the original address. - //This code is not placed in copyInstruction since this is only needed - //when inserting before - next->SetOriginalAddressID(first->GetOriginalAddressID()); - //"Null" out the original address (it should be as if the instruction was not in the database). - first->SetOriginalAddressID(BaseObj_t::NOT_IN_DATABASE); - first->GetRelocations().clear(); - first->SetIBTargets(NULL); - - virp->ChangeRegistryKey(first,next); - setInstructionAssembly(virp,first,assembly,next,target); - - return next; -} - -Instruction_t* insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly) -{ - return insertAssemblyBefore(virp,first,assembly,NULL); -} - -Instruction_t* insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits) -{ - return insertDataBitsBefore(virp,first,dataBits,NULL); -} - -Instruction_t* insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target) -{ - Instruction_t* next = copyInstruction(virp,first); - - //In case the fallthrough is null, generate spri has to have a - //place to jump, which is determined by the original address. - //This code is not placed in copyInstruction since this is only needed - //when inserting before - next->SetOriginalAddressID(first->GetOriginalAddressID()); - //"Null" out the original address (it should be as if the instruction was not in the database). - first->SetOriginalAddressID(BaseObj_t::NOT_IN_DATABASE); - first->GetRelocations().clear(); - - setInstructionDataBits(virp,first,dataBits,next,target); - - return next; -} - -Instruction_t* insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target) -{ - Instruction_t *new_instr = allocateNewInstruction(virp,first); - setInstructionAssembly(virp,new_instr,assembly,first->GetFallthrough(), target); - first->SetFallthrough(new_instr); - return new_instr; -} - -Instruction_t* insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly) -{ - return insertAssemblyAfter(virp,first,assembly,NULL); - -} - -Instruction_t* insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target) -{ - Instruction_t *new_instr = allocateNewInstruction(virp,first); - setInstructionDataBits(virp,new_instr,dataBits,first->GetFallthrough(), target); - first->SetFallthrough(new_instr); - - return new_instr; -} - -Instruction_t* insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits) -{ - return insertDataBitsAfter(virp,first,dataBits,NULL); -} - -//Does not insert into any variant -Instruction_t* copyInstruction(Instruction_t* instr) -{ - Instruction_t* cpy = new Instruction_t(); - - copyInstruction(instr,cpy); - - return cpy; -} - -Instruction_t* copyInstruction(FileIR_t* virp, Instruction_t* instr) -{ - Instruction_t* cpy = allocateNewInstruction(virp,instr); - - copyInstruction(instr,cpy); - - return cpy; -} - -void copyInstruction(Instruction_t* src, Instruction_t* dest) -{ - dest->SetDataBits(src->GetDataBits()); - dest->SetComment(src->GetComment()); - dest->SetCallback(src->GetCallback()); - dest->SetFallthrough(src->GetFallthrough()); - dest->SetTarget(src->GetTarget()); - dest->SetIBTargets(src->GetIBTargets()); - dest->GetRelocations()=src->GetRelocations(); - dest->SetEhProgram(src->GetEhProgram()); - dest->SetEhCallSite(src->GetEhCallSite()); -} - -Instruction_t* allocateNewInstruction(FileIR_t* virp, db_id_t p_fileID,Function_t* func) -{ - Instruction_t *instr = new Instruction_t(); - AddressID_t *a =new AddressID_t(); - - a->SetFileID(p_fileID); - - instr->SetFunction(func); - instr->SetAddress(a); - - virp->GetInstructions().insert(instr); - virp->GetAddresses().insert(a); - - inserted_instr[func].insert(instr); - inserted_addr[func].insert(a); - - return instr; -} - -Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, string p_asm) -{ - Instruction_t* newinstr; - if (p_instr) - newinstr = allocateNewInstruction(firp,p_instr->GetAddress()->GetFileID(), p_instr->GetFunction()); - else - newinstr = allocateNewInstruction(firp,BaseObj_t::NOT_IN_DATABASE, NULL); - - firp->RegisterAssembly(newinstr, p_asm); - - if (p_instr) - { - newinstr->SetFallthrough(p_instr->GetFallthrough()); - p_instr->SetFallthrough(newinstr); - } - - return newinstr; -} - -Instruction_t* addNewDatabits(FileIR_t* firp, Instruction_t *p_instr, string p_bits) -{ - Instruction_t* newinstr; - if (p_instr) - newinstr = allocateNewInstruction(firp,p_instr->GetAddress()->GetFileID(), p_instr->GetFunction()); - else - newinstr = allocateNewInstruction(firp,BaseObj_t::NOT_IN_DATABASE, NULL); - - newinstr->SetDataBits(p_bits); - - if (p_instr) - { - newinstr->SetFallthrough(p_instr->GetFallthrough()); - p_instr->SetFallthrough(newinstr); - } - - return newinstr; -} - - -Instruction_t* allocateNewInstruction(FileIR_t* virp, Instruction_t *template_instr) -{ - Function_t *func = template_instr->GetFunction(); - db_id_t fileID = template_instr->GetAddress()->GetFileID(); - return allocateNewInstruction(virp, fileID, func); -} - -void setInstructionAssembly(FileIR_t* virp,Instruction_t *p_instr, string p_assembly, Instruction_t *p_fallThrough, Instruction_t *p_target) -{ - if (p_instr == NULL) return; - - ///TODO: what if bad assembly? - virp->RegisterAssembly(p_instr,p_assembly); - -// p_instr->Assemble(p_assembly); - p_instr->SetComment(p_assembly); - p_instr->SetFallthrough(p_fallThrough); - p_instr->SetTarget(p_target); - - virp->GetAddresses().insert(p_instr->GetAddress()); - virp->GetInstructions().insert(p_instr); -} - -void setInstructionDataBits(FileIR_t* virp, Instruction_t *p_instr, string p_dataBits, Instruction_t *p_fallThrough, Instruction_t *p_target) -{ - if (p_instr == NULL) return; - - p_instr->SetDataBits(p_dataBits); - p_instr->SetComment(p_instr->getDisassembly()); - p_instr->SetFallthrough(p_fallThrough); - p_instr->SetTarget(p_target); - - virp->GetAddresses().insert(p_instr->GetAddress()); - virp->GetInstructions().insert(p_instr); -} - -string getRetDataBits() -{ - string dataBits; - dataBits.resize(1); - dataBits[0] = 0xc3; - return dataBits; -} - -string getJumpDataBits() -{ - string dataBits; - dataBits.resize(5); - dataBits[0] = 0xe9; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - dataBits[2] = 0x00; // value doesn't matter -- we will fill it in later - dataBits[3] = 0x00; // value doesn't matter -- we will fill it in later - dataBits[4] = 0x00; // value doesn't matter -- we will fill it in later - return dataBits; -} - -// jns - jump not signed -string getJnsDataBits() -{ - string dataBits; - dataBits.resize(2); - dataBits[0] = 0x79; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - return dataBits; -} - -// jz - jump zero -string getJzDataBits() -{ - string dataBits; - dataBits.resize(2); - dataBits[0] = 0x74; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - - return dataBits; -} - -// jnz - jump not zero -string getJnzDataBits() -{ - string dataBits; - dataBits.resize(2); - dataBits[0] = 0x75; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - - return dataBits; -} - -// jecxz - jump ecx zero -string getJecxzDataBits() -{ - string dataBits; - dataBits.resize(2); - dataBits[0] = 0xe3; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - - return dataBits; -} - -Instruction_t* getHandlerCode(FileIR_t* virp, Instruction_t* fallthrough, mitigation_policy policy, unsigned exit_code) -{ - Instruction_t *handler_code ; - if(virp->GetArchitectureBitWidth()==32) - { -#ifdef CGC - handler_code = allocateNewInstruction(virp,fallthrough); - setInstructionAssembly(virp,handler_code,"mov eax, 1",NULL,NULL); - Instruction_t* int80 = insertAssemblyAfter(virp,handler_code,"int 0x80",NULL); - int80->SetFallthrough(fallthrough); -#else - handler_code = allocateNewInstruction(virp,fallthrough); - setInstructionAssembly(virp,handler_code,"pusha",NULL,NULL); - Instruction_t* pushf = insertAssemblyAfter(virp,handler_code,"pushf",NULL); - stringstream ss; - ss<<"push dword 0x"; - ss<<hex<<policy; - Instruction_t *policy_push = insertAssemblyAfter(virp,pushf,ss.str(),NULL); - ss.str(""); - ss<<"push dword 0x"; - ss<<hex<<fallthrough->GetAddress()->GetVirtualOffset(); - Instruction_t *addr_push = insertAssemblyAfter(virp,policy_push,ss.str(),NULL); - //I am not planning on returning, but pass the address at which the overflow was detected. - Instruction_t *ret_push = insertAssemblyAfter(virp,addr_push,ss.str(),NULL); - Instruction_t *callback = insertAssemblyAfter(virp,ret_push,"nop",NULL); - - callback->SetCallback("buffer_overflow_detector"); - - - Instruction_t *popf = insertAssemblyAfter(virp,callback,"popf",NULL); - Instruction_t *popa = insertAssemblyAfter(virp,popf,"popa",NULL); - popa->SetFallthrough(fallthrough); -#endif - - } - else - { - assert(virp->GetArchitectureBitWidth()==64); - if (policy == P_CONTROLLED_EXIT) - { - string exit_code_str = "mov rdi, " + std::to_string(exit_code); - handler_code = allocateNewInstruction(virp,fallthrough); - - setInstructionAssembly(virp,handler_code,exit_code_str.c_str(), NULL,NULL); - Instruction_t* syscall_num = insertAssemblyAfter(virp,handler_code,"mov rax, 60",NULL); - Instruction_t* syscall_i = insertAssemblyAfter(virp,syscall_num,"syscall",NULL); - syscall_i->SetFallthrough(fallthrough); - } - else if (policy == P_HARD_EXIT) - { - handler_code= allocateNewInstruction(virp,fallthrough); - setInstructionAssembly(virp,handler_code,"hlt",NULL,NULL); - handler_code->SetComment("hlt ; hard exit requested"); - handler_code->SetFallthrough(fallthrough); - } - else - { - handler_code= allocateNewInstruction(virp,fallthrough); - setInstructionAssembly(virp,handler_code,"hlt",NULL,NULL); - handler_code->SetComment("hlt ; Make this into a callback: jdh@getHandlerCode"); - handler_code->SetFallthrough(fallthrough); - } - } - - return handler_code; -} - -Instruction_t* insertCanaryCheckBefore(FileIR_t* virp,Instruction_t *first, unsigned int canary_val, int esp_offset, Instruction_t *fail_code) -{ - auto do_zero=(first->getDisassembly().find("ret")!=string::npos); - stringstream ss; - const char *sp_reg="esp"; - if(virp->GetArchitectureBitWidth()==64) - sp_reg="rsp"; - - ss<<"cmp dword ["<<sp_reg; - - bool esp_neg=false; - if(esp_offset <0) - { - ss<<"-"; - esp_offset = esp_offset*-1; - esp_neg=true; - } - else - ss<<"+"; - - ss<<"0x"<<hex<<esp_offset<<"], 0x"<<hex<<canary_val; - - //Insert the cmp before - Instruction_t* next = insertAssemblyBefore(virp,first,ss.str()); - - //Then insert the jmp after the compare. - //The fallthrough of the inserted jmp will be a copy of the original - //instruction, still pointed to by "first". - insertDataBitsAfter(virp,first,getJnzDataBits(),fail_code); - first->SetComment("Canary Check: "+first->GetComment()); - - //TODO: move canary zero to option - if(esp_neg) - esp_offset *= -1; - - if(do_zero) - insertCanaryZeroAfter(virp,first,esp_offset,fail_code); - - return next; - -} - -Instruction_t* insertCanaryZeroAfter(FileIR_t* virp, Instruction_t *first, int esp_offset, Instruction_t *fail_code) -{ - stringstream ss; - const char *sp_reg="esp"; - if(virp->GetArchitectureBitWidth()==64) - { - sp_reg="rsp"; - ss<<"mov qword ["<<sp_reg; // clear all 64-bits - } - else - { - ss<<"mov dword ["<<sp_reg; - } - - if(esp_offset <0) - { - ss<<"-"; - esp_offset = esp_offset*-1; - } - else - ss<<"+"; - - ss<<"0x"<<hex<<esp_offset<<"], 0x0"; - - //Insert the cmp before - Instruction_t* next = insertAssemblyAfter(virp,first,ss.str()); - first->SetComment("Canary Zero: "+first->GetComment()); - - return next; -} - -Relocation_t* createNewRelocation(FileIR_t* firp, Instruction_t* insn, string type, int offset) -{ - Relocation_t* reloc=new Relocation_t; - insn->GetRelocations().insert(reloc); - firp->GetRelocations().insert(reloc); - - reloc->SetType(type); - reloc->SetOffset(offset); - - return reloc; -} - diff --git a/tools/transforms/Rewrite_Utility.hpp b/tools/transforms/Rewrite_Utility.hpp deleted file mode 100644 index caa1ff8f2..000000000 --- a/tools/transforms/Rewrite_Utility.hpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include <libIRDB-core.hpp> -#include "globals.h" - -using namespace libIRDB; -using namespace std; - -//The "first" instruction will have its contents replaced and a duplicate of "first" will be in the follow of first. -//This duplicate is returned since the user already has a pointer to first. -Instruction_t* insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target); -Instruction_t* insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string assembly); -Instruction_t* insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target); -Instruction_t* insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits); - -//The new instruction inserted after "first" is returned -Instruction_t* insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly, Instruction_t *target); -Instruction_t* insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly); -Instruction_t* insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target); -Instruction_t* insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits); -Instruction_t* addNewDatabits(FileIR_t* firp, Instruction_t *p_instr, string p_bits); -Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, string p_asm); - - - -//Does not insert into any variant, just copies data about the instruction itself, see the copyInstruction(src,dest) to see what is copied. -Instruction_t* copyInstruction(Instruction_t* instr); - -Instruction_t* copyInstruction(FileIR_t* virp, Instruction_t* instr); -//copy src to destination -void copyInstruction(Instruction_t* src, Instruction_t* dest); - -Instruction_t* allocateNewInstruction(FileIR_t* virp, db_id_t p_fileID,Function_t* func); -Instruction_t* allocateNewInstruction(FileIR_t* virp, Instruction_t *template_instr); -void setInstructionDataBits(FileIR_t* virp, Instruction_t *p_instr, string p_dataBits, Instruction_t *p_fallThrough, Instruction_t *p_target); -void setInstructionAssembly(FileIR_t* virp,Instruction_t *p_instr, string p_assembly, Instruction_t *p_fallThrough, Instruction_t *p_target); -string getJumpDataBits(); -string getJnsDataBits(); -string getJzDataBits(); -string getJnzDataBits(); -string getJecxzDataBits(); -string getRetDataBits(); -Instruction_t* getHandlerCode(FileIR_t* virp, Instruction_t* fallthrough, mitigation_policy policy, unsigned exitcode ); - -//The esp offset is allowed to be negative, and is handled properly. -//Returns the pointer for the copied "first" instruction, which is at the -//end of the canary check block of instructions. -Instruction_t* insertCanaryCheckBefore(FileIR_t* virp,Instruction_t *first, unsigned int canary_val, int ret_offset, Instruction_t *fail_code); -Instruction_t* insertCanaryZeroAfter(FileIR_t* virp, Instruction_t *first, int esp_offset, Instruction_t *fail_code); - -Relocation_t* createNewRelocation(FileIR_t* firp, Instruction_t* insn, string type, int offset); - - - diff --git a/tools/transforms/SConscript b/tools/transforms/SConscript deleted file mode 100644 index 7cc87696d..000000000 --- a/tools/transforms/SConscript +++ /dev/null @@ -1,51 +0,0 @@ -import os - -Import('env') -myenv=env.Clone() -myenv.Replace(SECURITY_TRANSFORMS_HOME=os.environ['SECURITY_TRANSFORMS_HOME']) - - -libname="IRDB-util" -cpppath=''' - $SECURITY_TRANSFORMS_HOME/include/ - $SECURITY_TRANSFORMS_HOME/libIRDB/include/ - $SECURITY_TRANSFORMS_HOME/libMEDSannotation/include/ - $SECURITY_TRANSFORMS_HOME/libtransform/include/ - $SECURITY_TRANSFORMS_HOME/libEXEIO/include - ''' - -LIBS= " xform IRDB-cfg MEDSannotation transform " + env.subst('$BASE_IRDB_LIBS') -LIBPATH="$SECURITY_TRANSFORMS_HOME/lib" - -#integer_files="transformutils.cpp integertransformdriver.cpp" - -# doesn't work on solaris. -#myenv.Append(CFLAGS="-Wall") -#myenv.Append(CCFLAGS="-Wall") - -myenv.Append(CXXFLAGS = " -std=c++11 ") - -all_files="PNTransformDriver.cpp PNStackLayout.cpp PNRange.cpp Range.cpp OffsetInference.cpp DirectOffsetInference.cpp ScaledOffsetInference.cpp P1Inference.cpp PNRegularExpressions.cpp PNMain.cpp StackLayout.cpp General_Utility.cpp AnnotationBoundaryGenerator.cpp PrecedenceBoundaryInference.cpp PNIrdbManager.cpp EhUpdater.cpp" - - -myenv=myenv.Clone(CPPPATH=Split(cpppath)) -ru_obj=myenv.Object("Rewrite_Utility.cpp"); -ru_lib=myenv.Library("rewrite", ru_obj); -install1=myenv.Install("$SECURITY_TRANSFORMS_HOME/lib/", ru_lib) -Default(install1) - -p1=myenv.Program("p1transform.exe", Split(all_files), LIBS=Split(LIBS)+ru_lib, LIBPATH=Split(LIBPATH)) -install2=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", p1) -Default(install2) -install3=myenv.InstallAs("$SECURITY_TRANSFORMS_HOME/bin/pntransform.exe", p1) -Default(install3) -#install=myenv.InstallAs("p1transform.exe", p1) -#Default(install) - -#intdr=myenv.Program("integertransformdriver.exe", Split(integer_files), LIBS=Split(LIBS)+ru_lib, LIBPATH=Split(LIBPATH)) -#install4=myenv.Install("$SECURITY_TRANSFORMS_HOME/bin/", intdr) -#Default(install4) - - -install=[]+install1 + install2 + install3 -Return('install') diff --git a/tools/transforms/SConstruct b/tools/transforms/SConstruct deleted file mode 100644 index b3bd01322..000000000 --- a/tools/transforms/SConstruct +++ /dev/null @@ -1,7 +0,0 @@ - - - -env=Environment() -Export('env') -lib=SConscript("SConscript") -Return('lib') diff --git a/tools/transforms/ScaledOffsetInference.cpp b/tools/transforms/ScaledOffsetInference.cpp deleted file mode 100644 index e06d0068d..000000000 --- a/tools/transforms/ScaledOffsetInference.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "ScaledOffsetInference.hpp" -#include <cassert> - -using namespace std; -using namespace libIRDB; - -ScaledOffsetInference::ScaledOffsetInference(OffsetInference *offset_inference) -{ - //TODO: throw exception - assert(offset_inference != NULL); - - this->offset_inference = offset_inference; -} - -PNStackLayout* ScaledOffsetInference::GetPNStackLayout(Function_t *func) -{ - return offset_inference->GetScaledAccessLayout(func); -} - -std::string ScaledOffsetInference::GetInferenceName() const -{ - return "Scaled Offset Inference"; -} diff --git a/tools/transforms/ScaledOffsetInference.hpp b/tools/transforms/ScaledOffsetInference.hpp deleted file mode 100644 index c8ec5ebe7..000000000 --- a/tools/transforms/ScaledOffsetInference.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - - -#ifndef __SCALEDOFFSETINFERENCE -#define __SCALEDOFFSETINFERENCE - -#include "OffsetInference.hpp" -#include "PNStackLayoutInference.hpp" - -class ScaledOffsetInference : public PNStackLayoutInference -{ -protected: - OffsetInference *offset_inference; -public: - ScaledOffsetInference(OffsetInference *offset_inference); - virtual PNStackLayout* GetPNStackLayout(libIRDB::Function_t *func); - virtual std::string GetInferenceName() const; - -}; -#endif diff --git a/tools/transforms/StackLayout.cpp b/tools/transforms/StackLayout.cpp deleted file mode 100644 index 9c89806d3..000000000 --- a/tools/transforms/StackLayout.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include "StackLayout.hpp" -#include <cassert> -#include <iostream> -#include "globals.h" - -using namespace std; - -StackLayout::StackLayout(const std::string &layout_name, const std::string &function_name, unsigned int frame_alloc_size, - unsigned int saved_regs_size, bool frame_pointer,unsigned int out_args_size) -{ - assert(out_args_size <= frame_alloc_size); - - this->layout_name = layout_name; - this->function_name = function_name; - this->frame_alloc_size = frame_alloc_size; - this->saved_regs_size = saved_regs_size; - this->has_frame_pointer = frame_pointer; - this->out_args_size = out_args_size; - has_out_args = out_args_size > 0; - is_canary_safe = true; - is_padding_safe = true; - //TODO: is static stack hacked in for TNE, needs a redesign - is_static_stack = true;//innocent 'til proven guilty. - is_recursive = false; //innocent 'til proven guilty - - //The initial layout is one entry the size of the stack frame. - //The size is minus the out args size, if greater than 0 - //an out args memory object is pushed below. - //The offset is following the out args region, if one exists. - PNRange frame; - frame.SetOffset((int)out_args_size); - frame.SetSize((int)frame_alloc_size-(int)out_args_size); - - //If there are out args, then it is automatically pushed as a mem_objects - //starting at 0. - if(has_out_args) - { - if(out_args_size != frame_alloc_size) - { - PNRange out_args; - out_args.SetOffset(0); - out_args.SetSize((int)out_args_size); - mem_objects.push_back(out_args); - } - else - { - frame.SetOffset(0); - frame.SetSize((int)out_args_size); - } - } - - //Push frame last to ensure the mem_objects vector is sorted - //by offset if there is an out args region - mem_objects.push_back(frame); -} - -StackLayout::StackLayout(const StackLayout &layout) -{ - this->layout_name = layout.layout_name; - this->function_name = layout.function_name; - this->frame_alloc_size = layout.frame_alloc_size; - this->saved_regs_size = layout.saved_regs_size; - this->out_args_size = layout.out_args_size; - this->has_frame_pointer = layout.has_frame_pointer; - has_out_args = layout.out_args_size > 0; - is_canary_safe = layout.is_canary_safe; - is_padding_safe = layout.is_padding_safe; - is_static_stack = layout.is_static_stack; - is_recursive = layout.is_recursive; - - for(unsigned int i=0;i<layout.mem_objects.size();i++) - { - this->mem_objects.push_back(layout.mem_objects[i]); - } -} - -void StackLayout::InsertESPOffset(int offset) -{ - //No Negative offsets allowed - if(offset < 0) - { - cerr<<"StackLayout: InsertESPOffset(): Negative Offset Encountered, Ignoring Insert"<<endl; - //assert(false); - return; - } - - if(verbose_log) - cerr<<"StackLayout: Attempting to insert offset "<<offset<<endl; - - - if(offset >= (int)frame_alloc_size) - { - //This can happen when an esp offset is accessing stored registers or function parameters - if(verbose_log) - cerr<<"StackLayout: InsertESPOffset(): Offset is larger than or equal to the allocated stack, Ignoring insert"<<endl; - return; - } - - if(has_out_args) - { - //If there are out args, mem_objects[0] is assumed to be the out args region - //if the new offset being inserted is in this range, the offset is ignored. - //The out args region is not divided - if(offset < (int)mem_objects[0].GetSize()) - { - if(verbose_log) - cerr<<"StackLayout: InsertESPOffset(): Offset in out args region, Ignoring insert"<<endl; - return; - } - } - - PNRange new_range; - - new_range.SetOffset(offset); - - int index = GetClosestIndex(offset); - - if(index < 0) - { - //TODO: don't assert false, ignore, but for now I want to find when this happens - if(verbose_log) - cerr<<"StackLayout: InsertESPOffset(): Could not Find Range to Insert Into, Asserting False for Now"<<endl; - //TODO: throw exception or ignore? - assert(false); - } - - //This should never happen, but just in case, assert false. - if(index > ((int)mem_objects.size())-1) - assert(false); //TODO: throw exception - - if(verbose_log) - cerr<<"PNStackLayout: InsertESPOffset(): found offset = "<< - mem_objects[index].GetOffset()<<endl; - //If offset is unique, insert it after the closest - //range (closest base address with out going over offset) - if(offset != mem_objects[index].GetOffset()) - { - if(index+1 == (int)mem_objects.size()) - mem_objects.push_back(new_range); - else - mem_objects.insert(mem_objects.begin()+index+1,new_range); - } - //else no need to insert, the offset already exists - else - { - if(verbose_log) - cerr<<"StackLayout: InsertESPOffset(): Offset already exists, ignoring insert"<<endl; - return; - } - - //The memory object that was divided has to have its size adjusted - //based on where the new memory object was inserted (its offset). - mem_objects[index].SetSize(mem_objects[index+1].GetOffset()-mem_objects[index].GetOffset()); - - //If the location of the newly inserted range is the end of the vector - //then the size will be the difference between the frame size and the - //offset of the new range - if((int)mem_objects.size() == index+2) - mem_objects[index+1].SetSize(((int)frame_alloc_size)-mem_objects[index+1].GetOffset()); - //Otherwise it is the difference between the next offset and the current offset - else - mem_objects[index+1].SetSize(mem_objects[index+2].GetOffset()-mem_objects[index+1].GetOffset()); - - if(verbose_log) - { - cerr<<"Stacklayout: Insert Successful, Post Insert Offsets"<<endl; - for(unsigned int i=0;i<mem_objects.size();i++) - { - cerr<<"\tOffset = "<<mem_objects[i].GetOffset()<<endl; - } - } -} - -void StackLayout::InsertEBPOffset(int offset) -{ - //The size of the saved regs must be taken into consideration when transforming - //the EBP offset to an esp relative offset - if(verbose_log) - cerr<<"StackLayout: InsertEBPOffset(): Offset="<<offset<<" frame alloc size="<<frame_alloc_size<<" saved regs size="<<saved_regs_size<<endl; - int esp_conversion = EBPToESP(offset);//((int)frame_alloc_size+(int)saved_regs_size) - offset; - - //It is possible to have ebp offsets that extend beyond the stack pointer. I haven't seen it - //but still. If this occurs, ignore the insert. We currently do not handle this case - if(esp_conversion >= 0) - InsertESPOffset(esp_conversion); - else - { - if(verbose_log) - cerr<<"PNStackLayout: InsertEBPOffset: Coverted EBP offset to negative ESP offset, ignoring insert"<<endl; - } -} - -unsigned int StackLayout::GetClosestIndex(int loc) const -{ - int high = ((int)mem_objects.size())-1; - int low = 0; - int mid; - - while(low <= high) - { - mid = (low+high)/2; - if((loc < (mem_objects[mid].GetOffset()+(int)mem_objects[mid].GetSize())) && (loc >= mem_objects[mid].GetOffset())) - return mid; - else if(loc > mem_objects[mid].GetOffset()) - low = mid +1; - else - high = mid -1; - } - return -1; -} - - -unsigned int StackLayout::GetAllocSize() -{ - return frame_alloc_size; -} - -unsigned int StackLayout::GetSavedRegsSize() -{ - return saved_regs_size; -} - -unsigned int StackLayout::GetOutArgsRegionSize() -{ - return out_args_size; -} - -//TODO: maybe this should be an unsigned int, since I am assuming it is -//positive. -int StackLayout::EBPToESP(int offset) -{ - return ((int)frame_alloc_size+(int)saved_regs_size) - offset; -} diff --git a/tools/transforms/StackLayout.hpp b/tools/transforms/StackLayout.hpp deleted file mode 100644 index 5e7c2411f..000000000 --- a/tools/transforms/StackLayout.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __STACKLAYOUT -#define __STACKLAYOUT -#include "PNRange.hpp" -#include <vector> -#include <string> - -class StackLayout -{ -protected: - //frame_alloc_size is the amount subtracted from esp to set up the stack - //saved regs size is the size in bits of the number of registers pushed after ebp but before the stack alloc instruction - - std::vector<Range> mem_objects; - unsigned int frame_alloc_size; - unsigned int saved_regs_size; - std::string function_name; - unsigned int out_args_size; - bool has_out_args; - bool has_frame_pointer; - bool is_canary_safe; - bool is_padding_safe; - bool is_static_stack; - bool is_recursive; - std::string layout_name; - -public: - -//NOTE: the following todo came from PNStackLayout where the insert functionality used to be, I am not sure what it means -//anymore, but just in case it is useful in the future, here is that original comment. -//TODO: change the code such that only inserts are allowed in the stack alloc region, create two frame sizes, local and total - StackLayout(const std::string &layout_name, const std::string &function_name, unsigned int frame_alloc_size, - unsigned int saved_regs_size, bool frame_pointer, unsigned int out_args_size); - StackLayout(const StackLayout &layout); - virtual ~StackLayout() {} - virtual void InsertESPOffset(int offset); - virtual void InsertEBPOffset(int offset); - virtual int EBPToESP(int offset); - - virtual std::string GetFunctionName() const { return function_name; }; - virtual std::string GetLayoutName() const { return layout_name; }; - virtual unsigned int GetAllocSize(); - virtual unsigned int GetSavedRegsSize(); - virtual unsigned int GetOutArgsRegionSize(); - virtual bool HasFramePointer(){return has_frame_pointer;} - virtual void SetCanarySafe(bool val){ is_canary_safe = val;} - //TODO: handle this better. - virtual void SetPaddingSafe(bool val){ is_padding_safe = val; is_canary_safe = is_canary_safe && val;} - virtual void SetStaticStack(bool val){ is_static_stack = val; } - virtual void SetRecursive(bool val){ is_recursive = val; } - virtual std::vector<Range> GetRanges() { return mem_objects; } - //TODO: why is this public - virtual unsigned int GetClosestIndex(int loc) const; - - friend class PNStackLayout; -}; - -#endif diff --git a/tools/transforms/canary.h b/tools/transforms/canary.h deleted file mode 100644 index 369620036..000000000 --- a/tools/transforms/canary.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __CANARY_H -#define __CANARY_H - -struct canary -{ - unsigned int canary_val; - int ret_offset;//Should be negative, the value to subtract from esp if esp is at ret addr - int esp_offset; - int floating_offset; -}; - -#endif diff --git a/tools/transforms/globals.h b/tools/transforms/globals.h deleted file mode 100644 index f9bfd02f2..000000000 --- a/tools/transforms/globals.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef __GLOBALS -#define __GLOBALS - -#include <set> -#include <string> -#include <stdlib.h> -#include <sys/types.h> -#include <unistd.h> -#include <limits.h> - - - -extern bool verbose_log; - -#define DEFAULT_DETECTION_EXIT_CODE 189 - -// make sure these match values in detector_handlers.h in the strata library -enum mitigation_policy -{ - P_NONE=0, - P_CONTINUE_EXECUTION, - P_CONTROLLED_EXIT, - P_CONTINUE_EXECUTION_SATURATING_ARITHMETIC, - P_CONTINUE_EXECUTION_WARNONLY, - P_HARD_EXIT -}; - - - -class PNOptions -{ - public: - // default configuration parameters go here - PNOptions() { - // specify defaults; - min_stack_padding = 128; - max_stack_padding = min_stack_padding*2; - recursive_min_stack_padding = 64; - recursive_max_stack_padding = recursive_min_stack_padding*2; - do_canaries = true; - do_selective_canaries = false; - should_double_frame_size=true; - random_seed=getpid(); - canary_value=0; - canary_value_inited=false; - double_threshold=32*1024; // 32kb - spri_validate=false; - detection_policy=P_HARD_EXIT; - detection_exit_code=DEFAULT_DETECTION_EXIT_CODE; - } - - void setMinStackPadding(int val) { min_stack_padding = val; } - void setMaxStackPadding(int val) { max_stack_padding = val; } - void setRecursiveMinStackPadding(int val) { recursive_min_stack_padding = val; } - void setRecursiveMaxStackPadding(int val) { recursive_max_stack_padding = val; } - void setShouldDoubleFrameSize(bool val) { should_double_frame_size = val; } - void setRandomSeed(int val) { random_seed = val; } - void setCanaryValue(int val) { canary_value = val; canary_value_inited=true; } - void setDoubleThreshold(int val) { double_threshold = val; } - - int getMinStackPadding() const { return min_stack_padding; } - int getMaxStackPadding() const { return max_stack_padding; } - int getRecursiveMinStackPadding() const { return recursive_min_stack_padding; } - int getRecursiveMaxStackPadding() const { return recursive_max_stack_padding; } - bool getShouldDoubleFrameSize() const { return should_double_frame_size; } - bool getShouldSpriValidate() const { return spri_validate; } - int getDoubleThreshold() { return double_threshold; } - int getRandomSeed() { return random_seed; } - int getCanaryValue() - { - if (canary_value_inited) - return canary_value; - else - return (rand()&0xffff) | (rand()<<16); - } - - void setDoCanaries(bool canaries) { do_canaries = canaries; } - bool getDoCanaries() const { return do_canaries; } - - void addSelectiveCanaryFunction(std::string func) { do_selective_canaries = true; canary_functions.insert(func);} - bool shouldCanaryFunction(std::string func) - { - if(do_selective_canaries) - { - bool notfound = (canary_functions.find(func)==canary_functions.end()); - bool found=!notfound; - return found; - } - else - return getDoCanaries(); - } - - void setDetectionPolicy(mitigation_policy p_policy) { detection_policy = p_policy; } - mitigation_policy getDetectionPolicy() const { return detection_policy; } - unsigned getDetectionExitCode() const { return detection_exit_code; } - void setDetectionExitCode(unsigned p_exitCode) { detection_exit_code = p_exitCode; } - - private: - int min_stack_padding; - int max_stack_padding; - int recursive_min_stack_padding; - int recursive_max_stack_padding; - bool do_canaries; - bool do_selective_canaries; - bool should_double_frame_size; - int random_seed; - int canary_value; - bool canary_value_inited; - - int double_threshold; - bool spri_validate; - - std::set<std::string> canary_functions; - - mitigation_policy detection_policy; - unsigned detection_exit_code; -}; - -extern PNOptions *pn_options; - -#endif diff --git a/tools/transforms/integertransformdriver.cpp b/tools/transforms/integertransformdriver.cpp deleted file mode 100644 index a7df8ad22..000000000 --- a/tools/transforms/integertransformdriver.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include <stdlib.h> -#include <fstream> -#include <libIRDB-core.hpp> -#include <getopt.h> -#include <libgen.h> - -#include "MEDS_AnnotationParser.hpp" -#include "transformutils.h" -#include "integertransform.hpp" -#include "integertransform32.hpp" -#include "integertransform64.hpp" -#include "pointercheck64.hpp" - -// current convention -#define BINARY_NAME "a.ncexe" -#define ANNOTATION_SUFFIX ".infoannot" -#define SHARED_OBJECTS_DIR "shared_objects" - -using namespace std; -using namespace libTransform; - -bool saturating_arithmetic = false; -bool path_manip_detected = false; // deprecated -bool instrument_idioms = false; -bool warning_only = false; -bool check_pointers = false; - -void usage() -{ - cerr << "Usage: integertransformdriver.exe <variant_id> <filtered_functions> <integer.warning.addresses> [--saturate] [--instrument-idioms] [--check-pointers] [--warning]"<<endl; -} - -int parse_args(int p_argc, char* p_argv[]) -{ - int option = 0; - char options[] = "s:i:w:c"; - struct option long_options[] = { - {"saturate", no_argument, NULL, 's'}, - {"instrument-idioms", no_argument, NULL, 'i'}, - {"warning", no_argument, NULL, 'w'}, - {"check-pointers", no_argument, NULL, 'c'}, - {NULL, no_argument, NULL, '\0'}, // end-of-array marker - }; - - while ((option = getopt_long( - p_argc, - p_argv, - options, - long_options, - NULL)) != -1) - { - switch (option) - { - case 's': - { - saturating_arithmetic = true; - printf("saturating arithmetic enabled\n"); - break; - } - case 'i': - { - printf("instrument idioms enabled\n"); - instrument_idioms = true; - break; - } - case 'w': - { - printf("warning only mode\n"); - warning_only = true; - break; - } - case 'c': - { - printf("check pointers mode\n"); - check_pointers = true; - break; - } - default: - return 1; - } - } - return 0; -} - -std::set<VirtualOffset> getInstructionWarnings(char *warningFilePath) -{ - std::set<VirtualOffset> warnings; - ifstream warningsFile; - - warningsFile.open(warningFilePath); - - if (warningsFile.is_open()) - { - while (!warningsFile.eof()) - { - string address; - getline(warningsFile, address); - - if (!address.empty()) - { - VirtualOffset vo(address); - warnings.insert(vo); - - cerr << "Detected warning address at: 0x" << hex << vo.getOffset() << endl; - } - } - } - - warningsFile.close(); - - cerr << "Detected a total of " << warnings.size() << " benign addresses" << endl; - return warnings; -} - -int main(int argc, char **argv) -{ - if(argc < 4) - { - usage(); - exit(1); - } - - string programName(argv[0]); - int variantID = atoi(argv[1]); - set<string> filteredFunctions = getFunctionList(argv[2]); - char *integerWarnings = argv[3]; - - parse_args(argc, argv); - - VariantID_t *pidp=NULL; - - /* setup the interface to the sql server */ - pqxxDB_t pqxx_interface; - BaseObj_t::SetInterface(&pqxx_interface); - - pidp=new VariantID_t(variantID); - assert(pidp->IsRegistered()==true); - - bool one_success = false; - for(set<File_t*>::iterator it=pidp->GetFiles().begin(); - it!=pidp->GetFiles().end(); - ++it) - { - File_t* this_file = *it; - FileIR_t *firp = new FileIR_t(*pidp, this_file); - char *fileBasename = basename((char*)this_file->GetURL().c_str()); - - assert(firp && pidp); - - try - { - string annotationFilename; - // need to map filename to integer annotation file produced by STARS - // this should be retrieved from the IRDB but for now, we use files to store annotations - // convention from within the peasoup subdirectory is: - // a.ncexe.infoannot - // shared_objects/<shared-lib-filename>.infoannot - if (strcmp(fileBasename, BINARY_NAME) == 0) - annotationFilename = string(BINARY_NAME) + string(ANNOTATION_SUFFIX); - else - annotationFilename = string(SHARED_OBJECTS_DIR) + "/" + fileBasename + ANNOTATION_SUFFIX; - - cerr << "annotation file: " << annotationFilename << endl; - - // parse MEDS integer annotations - ifstream annotationFile(annotationFilename.c_str(), ifstream::in); - if (!annotationFile.is_open()) - { - cerr << "annotation file not found: " << annotationFilename.c_str() << endl; - continue; - } - - MEDS_AnnotationParser annotationParser(annotationFile); - - // this is now wrong as we're instrumenting shared libraries - // we need to display file IDs along with the PC to distinguish between various libs - std::set<VirtualOffset> warnings = getInstructionWarnings(integerWarnings); // keep track of instructions that should be instrumented as warnings (upon detection, print diagnostic & continue) - - MEDS_Annotations_t annotations = annotationParser.getAnnotations(); - - cout << "integer transform driver: found " << annotations.size() << " annotations" << endl; - - // do the transformation - - libTransform::IntegerTransform *intxform = NULL; - if(firp->GetArchitectureBitWidth()==64) - { - if (check_pointers) - { - intxform = new PointerCheck64(pidp, firp, &annotations, &filteredFunctions, &warnings); - intxform->setInstrumentIdioms(true); - } - else - intxform = new IntegerTransform64(pidp, firp, &annotations, &filteredFunctions, &warnings); - } - else - { - intxform = new IntegerTransform32(pidp, firp, &annotations, &filteredFunctions, &warnings); - } - - intxform->setSaturatingArithmetic(saturating_arithmetic); - intxform->setPathManipulationDetected(path_manip_detected); - intxform->setInstrumentIdioms(instrument_idioms); - intxform->setWarningsOnly(warning_only); - - int exitcode = intxform->execute(); - - if (exitcode == 0) - { - one_success = true; - firp->WriteToDB(); - intxform->logStats(); - delete firp; - } - } - catch (DatabaseError_t pnide) - { - cerr << programName << ": Unexpected database error: " << pnide << "file url: " << this_file->GetURL() << endl; - } - catch (...) - { - cerr << programName << ": Unexpected error file url: " << this_file->GetURL() << endl; - } - } // end file iterator - - // if any integer transforms for any files succeeded, we commit - if (one_success) - pqxx_interface.Commit(); - - return 0; -} diff --git a/tools/transforms/nulltransform.cpp b/tools/transforms/nulltransform.cpp deleted file mode 100644 index b1951aecd..000000000 --- a/tools/transforms/nulltransform.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include <iostream> -#include "targ-config.h" - -#include "elfio/elfio.hpp" -#include "elfio/elfio_dump.hpp" - -#include "null_transform.h" - - -int main(int argc, char **argv) -{ - if (argc < 3) - { - std::cerr << "usage: " << argv[0] << " <elfFile> <annotationFile> [<spriFile>]" << std::endl; - return 1; - } - - std::cout << "Reading elf file:" << argv[1] << std::endl; - std::cout << "Reading MEDS annotation file:" << argv[2] << std::endl; - - NullTransform *nullTransform; - - if (argc == 3) - nullTransform = new NullTransform(argv[1], argv[2], (char*)"spri.out"); - else - nullTransform = new NullTransform(argv[1], argv[2], argv[3]); - - nullTransform->rewrite(); - - vector<wahoo::Function*> ncf = nullTransform->getNonCandidateFunctions(); - vector<wahoo::Function*> cf = nullTransform->getCandidateFunctions(); - vector<wahoo::Function*> af = nullTransform->getAllFunctions(); - - std::cout << "#functions: " << af.size() << std::endl; - std::cout << "#candidate functions: " << cf.size() << std::endl; - std::cout << "#non-candidate functions: " << ncf.size() << std::endl; -} diff --git a/tools/transforms/sample_meds_int.annot b/tools/transforms/sample_meds_int.annot deleted file mode 100644 index 745cf6d9b..000000000 --- a/tools/transforms/sample_meds_int.annot +++ /dev/null @@ -1,8 +0,0 @@ -80482bc 3 INSTR CHECK OVERFLOW UNSIGNED 32 EAX ZZ add eax, 1 -8048325 6 INSTR CHECK OVERFLOW SIGNED 16 [esp+2AH] ZZ add word ptr [esp+2Ah], 1 -804832b 6 INSTR CHECK OVERFLOW UNSIGNED 16 [esp+2CH] ZZ add word ptr [esp+2Ch], 1 -8048336 5 INSTR CHECK SIGNEDNESS SIGNED 16 AX ZZ mov [esp+28h], ax -80483db 5 INSTR CHECK UNDERFLOW SIGNED 32 EAX ZZ sub eax, 7FFFFFFFh -80483fd 3 INSTR CHECK UNDERFLOW SIGNED 32 EAX ZZ sub eax, 1 -8048492 5 INSTR CHECK TRUNCATION 32 EAX 16 AX ZZ mov [esp+26h], ax -8048492 5 INSTR CHECK SIGNEDNESS SIGNED 16 AX ZZ mov [esp+26h], ax diff --git a/tools/transforms/tests/test_buffer_overflow.c b/tools/transforms/tests/test_buffer_overflow.c deleted file mode 100644 index 39c151a88..000000000 --- a/tools/transforms/tests/test_buffer_overflow.c +++ /dev/null @@ -1,19 +0,0 @@ -#include <stdio.h> -#include <string.h> - -#define BUFSIZE 32 - -void do_overflow(char *s) -{ - char tmp[BUFSIZE]; - strcpy(tmp, s); - printf("target string is: %s\n", tmp); -} - -int main(int argc, char **argv) -{ - if (argc > 1) - do_overflow(argv[1]); - else - printf("specify long string on command line as argument to overflow (bufsize=%d)\n", BUFSIZE); -} diff --git a/tools/transforms/tests/test_buffer_overflow.sh b/tools/transforms/tests/test_buffer_overflow.sh deleted file mode 100755 index d92d7328e..000000000 --- a/tools/transforms/tests/test_buffer_overflow.sh +++ /dev/null @@ -1,120 +0,0 @@ -#!/bin/bash - -do_p1() -{ - if [[ -f $2 ]]; then - echo "Eliding rebuild of $2" - else - if [ -z "$3" ]; then - $PSZ $1 $2 --step p1transform=on - else - $PSZ $1 $2 --step p1transform=on --step-option p1transform:"$3" - fi - fi -} - -get_correct() -{ - ./test_buffer_overflow.exe > correct - ./test_buffer_overflow.exe abc >> correct -} - -test_functional() -{ - ./$1 > out - ./$1 abc >> out - - cmp out correct - if [ $? = 1 ]; then - fails=$(expr $fails + 1 ) - echo test failed $1 $2 $3 - echo "=== out ===" - cat out - echo "======" - else - passes=$(expr $passes + 1 ) - echo test passed. - fi -} - -test_detection() -{ - ./$1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - exitcode=$? - if [ $exitcode -eq $2 ]; then - passes=$(expr $passes + 1 ) - echo test passed. - else - fails=$(expr $fails + 1 ) - echo "test failed: does not detect overflow or wrong exit code: $1 (expected $2, got $exitcode)" - fi -} - -build() -{ - gcc -o test_buffer_overflow.exe test_buffer_overflow.c -fno-stack-protector -} - -build_with_stack_protector() -{ - gcc -o test_buffer_overflow.exe.sp test_buffer_overflow.c -} - - -protect() -{ - do_p1 ./test_buffer_overflow.exe test_buffer_overflow.exe.p1.139 # new default is halt - do_p1 ./test_buffer_overflow.exe test_buffer_overflow.exe.p1.188 "--detection_policy exit --detection_exit_code 188" - do_p1 ./test_buffer_overflow.exe test_buffer_overflow.exe.p1.hlt "--detection_policy halt" - do_p1 ./test_buffer_overflow.exe.sp test_buffer_overflow.exe.sp.p1.189 "--detection_policy exit --detection_exit_code 189" -} - -clean() -{ - rm out 2>/dev/null - rm correct 2>/dev/null - rm -Rf test_buffer_overflow.exe* peasoup_exe* 2>/dev/null -} - -report () -{ - total=$(expr $passes + $fails) - echo "Passes: $passes / $total" - echo "Fails : $fails / $total" -} - -main() -{ - build - build_with_stack_protector - protect - get_correct - - echo "Test functionality" - test_functional test_buffer_overflow.exe # unprotected - should pass! - test_functional test_buffer_overflow.exe.p1.139 - test_functional test_buffer_overflow.exe.p1.188 - test_functional test_buffer_overflow.exe.p1.hlt - test_functional test_buffer_overflow.exe.sp.p1.189 - - echo "Test detection (segfaults, etc. expected) -- errors do not effect test results" - test_detection test_buffer_overflow.exe.p1.139 139 - test_detection test_buffer_overflow.exe.p1.188 188 - test_detection test_buffer_overflow.exe.p1.hlt 139 - - # verify P1 detection comes before gcc stack smashing protection - test_detection test_buffer_overflow.exe.sp.p1.189 189 - - report - - if [[ $1 == "-k" ]] ; then - echo "Skipping cleanup" - else - clean - fi -} - -passes=0 -fails=0 - -main $* diff --git a/tools/transforms/tests/test_spec.sh b/tools/transforms/tests/test_spec.sh deleted file mode 100755 index 62ceac1a7..000000000 --- a/tools/transforms/tests/test_spec.sh +++ /dev/null @@ -1,235 +0,0 @@ -#!/bin/bash - -# the bad boys -#benchmarks=" -# 400.perlbench -# 403.gcc -# 445.gobmk -# 450.soplex -# 453.povray -# 458.sjeng -# 464.h264ref -# 465.tonto -# 471.omnetpp -# 481.wrf -# 482.sphinx3 -# 483.xalancbmk -# " - -# all -all_benchmarks="400.perlbench 401.bzip2 403.gcc 410.bwaves 416.gamess 429.mcf 433.milc 434.zeusmp 435.gromacs 436.cactusADM 437.leslie3d 444.namd 445.gobmk 450.soplex 453.povray 454.calculix 456.hmmer 458.sjeng 459.GemsFDTD 462.libquantum 464.h264ref 465.tonto 470.lbm 471.omnetpp 473.astar 481.wrf 482.sphinx3 483.xalancbmk" -#all_benchmarks=" 403.gcc " - - -number=1 - -setup() -{ - - if [ ! -d spec2006 ]; then - #svn co ^/spec2006/trunk spec2006 - git clone --depth 1 http://git.zephyr-software.com/allzp/spec2006.git spec2006 - fi - - if [[ ! -f /usr/bin/gfortran ]]; then - sudo apt-get install gfortran -y - fi - - cd spec2006/ - if [ ! -L bin ]; then - ln -s bin.power/ bin - fi - source shrc - bin/relocate -} - - -run_test() -{ - config_name=$1 - config=$2 - benchmarks="$3" - cd $SPEC - if [ ! -d result.$config_name ]; then - dropdb $PGDATABASE - createdb $PGDATABASE - $PEASOUP_HOME/tools/db/pdb_setup.sh - rm -Rf result/* - runspec --action scrub --config $config $benchmarks - - echo - echo "**************************************************************************" - echo "Starting test of $config_name" - echo "**************************************************************************" - echo - runspec --action validate --config $config -n $number $benchmarks - cp benchspec/CPU2006/*/exe/* result - mv result result.$config_name - for bench in $benchmarks - do - mv benchspec/CPU2006/$bench/run/build*/peasoup*/logs result.$config_name/$bench.log - done - fi - -} - -get_size_result() -{ - bench=$1 - if [ -e $bench ]; then - size=$(stat --printf="%s" $bench) - #echo -n "$size" - #LC_ALL= numfmt --grouping $size - #LC_ALL= printf "%'d" $size - #LC_NUMERIC=en_US printf "%'d" $size - #LC_NUMERIC=en_US printf "%'f" $size - #LC_NUMERIC=en_US printf "%'.f" $size - #LC_NUMERIC=en_US printf "%'10.10f" $size - #LC_NUMERIC=en_US /usr/bin/printf "%'d" $size - echo $size - else - echo -n "0" - fi -} - -get_result() -{ - bench=$1 - config=$2 - - results=$(cat $SPEC/result.$config/CPU2006.002.log|grep Success|grep $bench|grep ratio=|sed 's/.*ratio=//'|sed 's/,.*//') - - sum=0 - count=0 - for res in $results - do - sum=$(echo $sum + $res | bc) - count=$(echo $count + 1 | bc) - done - #echo sum=$sum - #echo count=$count - res=$(echo "scale=2; $sum / $count" | bc 2> /dev/null ) - - count=$(echo $res|wc -w) - - if [ $count = 1 ]; then - echo -n $res - else - echo -n "0" - fi - -} - - -get_raw_results() -{ - get_raw_perf_results "$@" - get_raw_size_results "$@" - get_raw_fde_results "$@" -} - -get_raw_perf_results() -{ - configs=$* - first_config=$1 - echo "--------------------------------------------------------------" - echo "Performance results are:" - echo "--------------------------------------------------------------" - echo benchmark $configs - for bench in $benchmarks - do - echo -n "$bench " - for config in $* - do - get_result $bench $config - echo -n " " - done - echo - done -} - -get_raw_size_results() -{ - echo "--------------------------------------------------------------" - echo "Size results are:" - echo "--------------------------------------------------------------" - configs=$* - echo benchmark $configs - for bench in $SPEC/result.$first_config/*_base.amd64-m64-gcc42-nn - do - echo -n "$(basename $bench _base.amd64-m64-gcc42-nn) " - for config in $* - do - if [[ $config == "baseline" ]]; then - file="$SPEC/result.$config/$(basename $bench)" - cp $file /tmp/foo.exe - strip /tmp/foo.exe - file="/tmp/foo.exe" - else - file="$SPEC/result.$config/$(basename $bench)" - fi - res=$(get_size_result $file) - - #printf "%15s" $res - echo -n " $res" - done - echo - done - -} - -get_raw_fde_results() -{ - echo "--------------------------------------------------------------" - echo "FDE results are:" - echo "--------------------------------------------------------------" - configs=$* - echo benchmark $configs - for bench in $SPEC/result.$first_config/*_base.amd64-m64-gcc42-nn - do - #printf "%-20s" $(basename $bench _base.amd64-m64-gcc42-nn) - echo -n $(basename $bench _base.amd64-m64-gcc42-nn) - for config in $* - do - file="$SPEC/result.$config/$(basename $bench)" - res=$(readelf -w $file |grep FDE|wc -l ) - #if [[ $config == "baseline" ]]; then - #else - #fi - - #printf "%15s" $res - echo -n " $res" - done - echo - done - -} - -main() -{ - zipr_flags=" --backend zipr --step-option zipr:--add-sections --step-option zipr:true" - trace_flags=" --step-option zipr:--traceplacement:on --step-option zipr:true" - relax_flags=" --step-option zipr:--relax:on --step-option zipr:true --step-option zipr:--unpin:on --step-option zipr:false" - nounpin_flags=" --step-option zipr:--unpin:on --step-option zipr:false" - split_flags=" --step-option fill_in_indtargs:--split-eh-frame " - icall_flags=" --step-option fix_calls:--no-fix-icalls " - p1flags=" -c p1transform=on " - start_dir=$(pwd) - setup - - # baseline - run_test baseline $SPEC/config/ubuntu14.04lts-64bit.cfg "$all_benchmarks" - - # should be 100% success, tested by jdh on 4/11/18 as 100% success. - PSOPTS="$zipr_flags " run_test zipr $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - - # two failures as of 4/11/18 -- cactusADM and povray - PSOPTS="$zipr_flags $p1flags " run_test zipr-p1 $SPEC/config/ubuntu14.04lts-64bit-withps.cfg "$all_benchmarks" - - get_raw_results baseline zipr zipr-p1 -} - -main "$@" - - - diff --git a/tools/transforms/transformutils.cpp b/tools/transforms/transformutils.cpp deleted file mode 100644 index bfab574de..000000000 --- a/tools/transforms/transformutils.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#include <iostream> -#include <fstream> -#include <string> - -#include "transformutils.h" - -using namespace std; - -set<string> getFunctionList(char *p_filename) -{ - set<string> functionList; - - ifstream candidateFile; - candidateFile.open(p_filename); - - if(candidateFile.is_open()) - { - while(!candidateFile.eof()) - { - string functionName; - getline(candidateFile, functionName); - - functionList.insert(functionName); - } - - candidateFile.close(); - } - - return functionList; -} - diff --git a/tools/transforms/transformutils.h b/tools/transforms/transformutils.h deleted file mode 100644 index 5143412f3..000000000 --- a/tools/transforms/transformutils.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2013, 2014 - University of Virginia - * - * This file may be used and modified for non-commercial purposes as long as - * all copyright, permission, and nonwarranty notices are preserved. - * Redistribution is prohibited without prior written consent from the University - * of Virginia. - * - * Please contact the authors for restrictions applying to commercial use. - * - * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * Author: University of Virginia - * e-mail: jwd@virginia.com - * URL : http://www.cs.virginia.edu/ - * - */ - -#ifndef _TRANSFORM_UTILS_ -#define _TRANSFORM_UTILS_ - -#include <string> -#include <set> - -extern std::set<std::string> getFunctionList(char *p_filename); - -#endif -- GitLab