diff --git a/.gitattributes b/.gitattributes index 4cce1ecd1d8a876251dd495c11e3206e7080abdf..43eda93c14250ace45830aa45b04276db6f12c04 100644 --- a/.gitattributes +++ b/.gitattributes @@ -233,10 +233,12 @@ libMEDSannotation/src/Makefile -text libMEDSannotation/src/VirtualOffset.cpp -text libtransform/Makefile -text libtransform/include/integertransform.hpp -text +libtransform/include/integertransform64.hpp -text libtransform/include/leapattern.hpp -text libtransform/include/transform.hpp -text libtransform/src/Makefile -text libtransform/src/integertransform.cpp -text +libtransform/src/integertransform64.cpp -text libtransform/src/leapattern.cpp -text libtransform/src/transform.cpp -text libtransform/tests/Makefile -text diff --git a/libtransform/include/integertransform64.hpp b/libtransform/include/integertransform64.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7931a93a53b35ec8cca4cb4612f2858a5ab1bbde --- /dev/null +++ b/libtransform/include/integertransform64.hpp @@ -0,0 +1,65 @@ +#ifndef _LIBTRANSFORM_INTEGERTRANSFORM64_H_ +#define _LIBTRANSFORM_INTEGERTRANSFORM64_H_ + +#include "transform.hpp" +#include "MEDS_Register.hpp" +#include "VirtualOffset.hpp" + +namespace libTransform +{ + +using namespace std; +using namespace libIRDB; + +class IntegerTransform64 : public Transform +{ + public: + IntegerTransform64(VariantID_t *, FileIR_t*, std::map<VirtualOffset, MEDS_InstructionCheckAnnotation> *p_annotations, set<std::string> *p_filteredFunctions, set<VirtualOffset> *p_warnings); + + int execute(); + + void setSaturatingArithmetic(bool p_satArithmetic) { m_policySaturatingArithmetic = p_satArithmetic; } + bool isSaturatingArithmetic() { return m_policySaturatingArithmetic; } + void setPathManipulationDetected(bool p_pathManip) { m_pathManipulationDetected = p_pathManip; } + bool isPathManipulationDetected() { return m_pathManipulationDetected; } + void setWarningsOnly(bool p_warn) { m_policyWarningsOnly = p_warn; } + bool isWarningsOnly() { return m_policyWarningsOnly; } + void logStats(); + + bool isBlacklisted(Function_t *func); + + std::map<VirtualOffset, MEDS_InstructionCheckAnnotation>* getAnnotations() { return m_annotations; } + + protected: + void handleOverflowCheck(Instruction_t *p_instruction, const MEDS_InstructionCheckAnnotation& p_annotation, int p_policy); + void addOverflowCheck(Instruction_t *p_instruction, const MEDS_InstructionCheckAnnotation& p_annotation, int p_policy); + void logMessage(const std::string &p_method, const std::string &p_msg); + void logMessage(const std::string &p_method, const MEDS_InstructionCheckAnnotation&, const std::string &p_msg); + + private: + std::map<VirtualOffset, MEDS_InstructionCheckAnnotation> *m_annotations; + std::set<VirtualOffset>* m_benignFalsePositives; + bool m_policySaturatingArithmetic; + bool m_policyWarningsOnly; + bool m_pathManipulationDetected; + + // statistics + unsigned m_numAnnotations; + unsigned m_numIdioms; + unsigned m_numBlacklisted; + unsigned m_numBenign; + unsigned m_numOverflows; + unsigned m_numUnderflows; + unsigned m_numTruncations; + unsigned m_numSignedness; + unsigned m_numOverflowsSkipped; + unsigned m_numUnderflowsSkipped; + unsigned m_numTruncationsSkipped; + unsigned m_numSignednessSkipped; + unsigned m_numFP; +}; + + +} // end namespace + +#endif diff --git a/libtransform/include/transform.hpp b/libtransform/include/transform.hpp index ee637175ee6683a3543023015c20dbd27470ca62..25a9c3319f98244691acc19881d69c2927911ed9 100644 --- a/libtransform/include/transform.hpp +++ b/libtransform/include/transform.hpp @@ -49,6 +49,7 @@ class Transform { void addJnz(Instruction_t *p_instr, Instruction_t *p_fallThrough, Instruction_t *p_target); void addJae(Instruction_t *p_instr, Instruction_t *p_fallThrough, Instruction_t *p_target); void addNot(Instruction_t *p_instr, Register::RegisterName, Instruction_t *p_fallThrough); + void addHlt(Instruction_t *p_instr, Instruction_t *p_fallThrough); void addAddRegisters(Instruction_t *p_instr, Register::RegisterName p_regTgt, Register::RegisterName p_regSrc, Instruction_t *p_fallThrough); void addAddRegisterConstant(Instruction_t *p_instr, Register::RegisterName p_regTgt, int p_constantValue, Instruction_t *p_fallThrough); diff --git a/libtransform/src/Makefile b/libtransform/src/Makefile index 42a516afd53b771ba3a308d48a6ae45716a5dc56..49c3c4e7fe2598c572d7a133e2542dc4fee2db4e 100644 --- a/libtransform/src/Makefile +++ b/libtransform/src/Makefile @@ -1,6 +1,6 @@ LIB=../lib/libtransform.a -OBJS=transform.o integertransform.o leapattern.o +OBJS=transform.o integertransform.o leapattern.o integertransform64.o all: $(OBJS) diff --git a/libtransform/src/integertransform64.cpp b/libtransform/src/integertransform64.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44e6aca2e6701d8dc1a359bb59421e97eb25c44f --- /dev/null +++ b/libtransform/src/integertransform64.cpp @@ -0,0 +1,210 @@ +#include <assert.h> + +#include "integertransform64.hpp" + +using namespace libTransform; + +IntegerTransform64::IntegerTransform64(VariantID_t *p_variantID, FileIR_t *p_fileIR, std::map<VirtualOffset, MEDS_InstructionCheckAnnotation> *p_annotations, set<std::string> *p_filteredFunctions, set<VirtualOffset> *p_benignFalsePositives) : Transform(p_variantID, p_fileIR, p_annotations, p_filteredFunctions) +{ + m_benignFalsePositives = p_benignFalsePositives; + m_policySaturatingArithmetic = false; + m_policyWarningsOnly = false; + m_pathManipulationDetected = false; + m_annotations = p_annotations; + + m_numAnnotations = 0; + m_numIdioms = 0; + m_numBlacklisted = 0; + m_numBenign = 0; + m_numOverflows = 0; + m_numUnderflows = 0; + m_numTruncations = 0; + m_numSignedness = 0; + m_numFP = 0; + m_numOverflowsSkipped = 0; + m_numUnderflowsSkipped = 0; + m_numTruncationsSkipped = 0; + m_numSignednessSkipped = 0; +} + +// iterate through all functions +// filter those functions that should be ignored +// iterate through all instructions in function +// if MEDS annotation says to instrument +// add instrumentation +int IntegerTransform64::execute() +{ + if (isWarningsOnly()) + logMessage(__func__, "warnings only mode"); + + for( + set<Function_t*>::const_iterator itf=getFileIR()->GetFunctions().begin(); + itf!=getFileIR()->GetFunctions().end(); + ++itf + ) + { + Function_t* func=*itf; + + if (getFilteredFunctions()->find(func->GetName()) != getFilteredFunctions()->end()) + { + logMessage(__func__, "filter out: " + func->GetName()); + continue; + } + + if (isBlacklisted(func)) + { + logMessage(__func__, "blacklisted: " + func->GetName()); + m_numBlacklisted++; + continue; + } + + logMessage(__func__, "processing fn: " + func->GetName()); + + for( + set<Instruction_t*>::const_iterator it=func->GetInstructions().begin(); + it!=func->GetInstructions().end(); + ++it) + { + Instruction_t* insn=*it; + + if (insn && insn->GetAddress()) + { + int policy = POLICY_EXIT; // default for now is exit -- no callback handlers yet + virtual_offset_t irdb_vo = insn->GetAddress()->GetVirtualOffset(); + if (irdb_vo == 0) continue; + + VirtualOffset vo(irdb_vo); + + MEDS_InstructionCheckAnnotation annotation = (*getAnnotations())[vo]; + if (!annotation.isValid()) + continue; + + logMessage(__func__, annotation, "-- instruction: " + insn->getDisassembly()); + m_numAnnotations++; + + if (annotation.isIdiom()) + { + logMessage(__func__, "skip IDIOM"); + m_numIdioms++; + continue; + } + + if (!insn->GetFallthrough()) + { + logMessage(__func__, "Warning: no fall through for instruction -- skipping"); + continue; + } + + if (annotation.isOverflow()) + { + // nb: safe with respect to esp (except for lea) + handleOverflowCheck(insn, annotation, policy); + } + } + } // end iterate over all instructions in a function + } // end iterate over all functions + + return 0; +} + +void IntegerTransform64::handleOverflowCheck(Instruction_t *p_instruction, const MEDS_InstructionCheckAnnotation& p_annotation, int p_policy) +{ + if (isMultiplyInstruction(p_instruction) || (p_annotation.isOverflow() && !p_annotation.isUnknownSign())) + { + // handle signed/unsigned add/sub overflows (non lea) + addOverflowCheck(p_instruction, p_annotation, p_policy); + } + else + { + m_numOverflowsSkipped++; + logMessage(__func__, "OVERFLOW type not yet handled"); + } +} + +// +// mul a, b ; <instruction to instrument> +// jno <OrigNext> +// halt +// OrigNext: <nextInstruction> +// +void IntegerTransform64::addOverflowCheck(Instruction_t *p_instruction, const MEDS_InstructionCheckAnnotation& p_annotation, int p_policy) +{ + Instruction_t* jncond_i = NULL; + Instruction_t* hlt_i = NULL; + + assert(getFileIR() && p_instruction && p_instruction->GetFallthrough()); + + cerr << __func__ << ": instr: " << p_instruction->getDisassembly() << " address: " << std::hex << p_instruction->GetAddress() << " annotation: " << p_annotation.toString() << " policy: " << p_policy << endl; + + jncond_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction()); + hlt_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction()); + + Instruction_t* next_i = p_instruction->GetFallthrough(); + p_instruction->SetFallthrough(jncond_i); + + if (p_annotation.isUnsigned()) + { + addJnc(jncond_i, hlt_i, next_i); + } + else + { + addJno(jncond_i, hlt_i, next_i); + } + addHlt(hlt_i, next_i); + + if (p_annotation.isUnderflow()) + m_numUnderflows++; + else + m_numOverflows++; +} + +// @todo: move to base class +void IntegerTransform64::logMessage(const std::string &p_method, const std::string &p_msg) +{ + std::cerr << p_method << ": " << p_msg << std::endl; +} + +// @todo: move to base class +void IntegerTransform64::logMessage(const std::string &p_method, const MEDS_InstructionCheckAnnotation& p_annotation, const std::string &p_msg) +{ + logMessage(p_method, p_msg + " annotation: " + p_annotation.toString()); +} + +void IntegerTransform64::logStats() +{ + std::string fileURL = getFileIR()->GetFile()->GetURL(); + + std::cerr << "# ATTRIBUTE file_name=" << fileURL << std::endl; + std::cerr << "# ATTRIBUTE num_annotations_processed=" << dec << m_numAnnotations << std::endl; + std::cerr << "# ATTRIBUTE num_idioms=" << m_numIdioms << std::endl; + std::cerr << "# ATTRIBUTE num_blacklisted=" << m_numBlacklisted << std::endl; + std::cerr << "# ATTRIBUTE num_benign=" << m_numBenign << std::endl; + std::cerr << "# ATTRIBUTE num_overflows_instrumented=" << m_numOverflows << std::endl; + std::cerr << "# ATTRIBUTE num_overflows_skipped=" << m_numOverflowsSkipped << std::endl; + std::cerr << "# ATTRIBUTE num_underflows_instrumented=" << m_numUnderflows << std::endl; + std::cerr << "# ATTRIBUTE num_underflows_skipped=" << m_numUnderflowsSkipped << std::endl; + std::cerr << "# ATTRIBUTE num_truncations_instrumented=" << m_numTruncations << std::endl; + std::cerr << "# ATTRIBUTE num_truncations_skipped=" << m_numTruncationsSkipped << std::endl; + std::cerr << "# ATTRIBUTE num_signedness_instrumented=" << m_numSignedness << std::endl; + std::cerr << "# ATTRIBUTE num_signedness_skipped=" << m_numSignednessSkipped << std::endl; + std::cerr << "# ATTRIBUTE num_floating_point=" << m_numFP << std::endl; +} + +// functions known to be problematic b/c of bitwise manipulation +bool IntegerTransform64::isBlacklisted(Function_t *func) +{ + if (!func) return false; + const char *funcName = func->GetName().c_str(); + return (strcasestr(funcName, "hash") || + strcasestr(funcName, "compress") || + strcasestr(funcName, "encode") || + strcasestr(funcName, "decode") || + strcasestr(funcName, "crypt") || + strcasestr(funcName, "yyparse") || + strcasestr(funcName, "yyerror") || + strcasestr(funcName, "yydestruct") || + strcasestr(funcName, "yyrestart") || + strcasestr(funcName, "yylex") || + strcasestr(funcName, "yy_")); +} + diff --git a/libtransform/src/transform.cpp b/libtransform/src/transform.cpp index f00cda0de4df59b6592b6e1a1b2eca782fda7407..08e80ee14e556875072147d76bc21ea65998a018 100644 --- a/libtransform/src/transform.cpp +++ b/libtransform/src/transform.cpp @@ -872,18 +872,6 @@ void Transform::addJo(Instruction_t *p_instr, Instruction_t *p_fallThrough, Inst addInstruction(p_instr, dataBits, p_fallThrough, p_target); } - -// jno - jump not overflow -void Transform::addJno(Instruction_t *p_instr, Instruction_t *p_fallThrough, Instruction_t *p_target) -{ - string dataBits; - dataBits.resize(2); - dataBits[0] = 0x71; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - - addInstruction(p_instr, dataBits, p_fallThrough, p_target); -} - // jc - jump carry void Transform::addJc(Instruction_t *p_instr, Instruction_t *p_fallThrough, Instruction_t *p_target) { @@ -895,17 +883,6 @@ void Transform::addJc(Instruction_t *p_instr, Instruction_t *p_fallThrough, Inst addInstruction(p_instr, dataBits, p_fallThrough, p_target); } -// jnc - jump not carry -void Transform::addJnc(Instruction_t *p_instr, Instruction_t *p_fallThrough, Instruction_t *p_target) -{ - string dataBits; - dataBits.resize(2); - dataBits[0] = 0x73; - dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later - - addInstruction(p_instr, dataBits, p_fallThrough, p_target); -} - // not <reg> -- negate register void Transform::addNot(Instruction_t *p_instr, Register::RegisterName p_reg, Instruction_t *p_fallThrough) { @@ -1173,3 +1150,48 @@ void Transform::addAndRegister32Mask(Instruction_t *p_instr, Register::RegisterN p_instr->SetComment("Saturating arithmetic by masking"); } +// known to be used on x86-64 + +// hlt +void Transform::addHlt(Instruction_t *p_instr, Instruction_t *p_fallThrough) +{ + string assembly("hlt"); + m_fileIR->RegisterAssembly(p_instr, assembly); + p_instr->SetFallthrough(p_fallThrough); +} + + +// jno - jump not overflow +void Transform::addJno(Instruction_t *p_instr, Instruction_t *p_fallThrough, Instruction_t *p_target) +{ +#ifdef OLD_WAY + string dataBits; + dataBits.resize(2); + dataBits[0] = 0x71; + dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later + + addInstruction(p_instr, dataBits, p_fallThrough, p_target); +#endif + + string assembly("jno 0x22"); + m_fileIR->RegisterAssembly(p_instr, assembly); + p_instr->SetFallthrough(p_fallThrough); + p_instr->SetTarget(p_target); +} + +// jnc - jump not carry +void Transform::addJnc(Instruction_t *p_instr, Instruction_t *p_fallThrough, Instruction_t *p_target) +{ +#ifdef OLD_WAY + string dataBits; + dataBits.resize(2); + dataBits[0] = 0x73; + dataBits[1] = 0x00; // value doesn't matter -- we will fill it in later + + addInstruction(p_instr, dataBits, p_fallThrough, p_target); +#endif + string assembly("jnc 0x22"); + m_fileIR->RegisterAssembly(p_instr, assembly); + p_instr->SetFallthrough(p_fallThrough); + p_instr->SetTarget(p_target); +} diff --git a/libtransform/tests/Makefile b/libtransform/tests/Makefile index a5511e6728545969610d30561061db6a2b655a95..0d0c8a997e36f25963f15db46c11ac8404b0cf2d 100644 --- a/libtransform/tests/Makefile +++ b/libtransform/tests/Makefile @@ -8,7 +8,7 @@ LD=DO_NOT_USE #exes=dumbledore_cmd.exe test1.exe #exes=overflow1.exe #overflow2.exe #exes=dumbledore_cmd.exe -exes=integerbug.exe +exes=unsigned_mul.exe signed_add.exe all: env_check ${exes} @@ -20,7 +20,7 @@ all: env_check ${exes} # gcc -g $< -o $@ gcc $< -o $@ # ${PEASOUP_HOME}/tools/ps_analyze.sh $@ $@.peasoup - ${PEASOUP_HOME}/tools/ps_analyze.sh $@ $@.peasoup --step ilr=off --step concolic=off --step p1transform=off --step isr=off + ${PEASOUP_HOME}/tools/ps_analyze64.sh $@ $@.peasoup --step ilr=off --step concolic=off --step p1transform=off --step isr=off .c.o: # gcc -O2 -c $< diff --git a/libtransform/tests/signed_add.c b/libtransform/tests/signed_add.c index da3e4adb333ac93a5be81dc7a584d29195f37495..c74cd0afdf2e52ff75efade4165007e280195609 100644 --- a/libtransform/tests/signed_add.c +++ b/libtransform/tests/signed_add.c @@ -1,12 +1,18 @@ +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> + int main(int argc, char **argv) { - int a = atoi(argv[1]); - int b = atoi(argv[2]); - volatile int result; + int64_t a = atol(argv[1]); + int64_t b = atol(argv[2]); + volatile int64_t result; - printf("a = %d; b = %d\n", a, b); + printf("a = %ld; b = %ld\n", a, b); result = 1 + a + b; - printf("1 + a=%d + b=%d = %d\n", a, b, result); + printf("1 + a=%ld + b=%ld = %ld\n", a, b, result); + + return 0; } diff --git a/libtransform/tests/unsigned_mul.c b/libtransform/tests/unsigned_mul.c index c9d30a68ee1469d30ab69f6474d1442a1e45fb23..0263f28b4074a99d017b0643f25cac760d3a8b2f 100644 --- a/libtransform/tests/unsigned_mul.c +++ b/libtransform/tests/unsigned_mul.c @@ -15,4 +15,6 @@ int main(int argc, char **argv) d = a * b; printf("%u\n", d); + + return 0; } diff --git a/tools/transforms/integertransformdriver.cpp b/tools/transforms/integertransformdriver.cpp index 88bc03c54e9875334f082b7aed086d68c9a043d7..4d52823e6ce9d519dd2bb00506f29d5ffe2fce86 100644 --- a/tools/transforms/integertransformdriver.cpp +++ b/tools/transforms/integertransformdriver.cpp @@ -5,6 +5,7 @@ #include "MEDS_AnnotationParser.hpp" #include "transformutils.h" +#include "integertransform64.hpp" #include "integertransform.hpp" // current convention @@ -106,7 +107,7 @@ main(int argc, char **argv) assert(pidp->IsRegistered()==true); bool one_success = false; - for(set<File_t*>::iterator it=pidp->GetFiles().begin(); + for(set<File_t*>::iterator it=pidp->GetFiles().begin(); it!=pidp->GetFiles().end(); ++it) { @@ -148,18 +149,38 @@ main(int argc, char **argv) std::map<VirtualOffset, MEDS_InstructionCheckAnnotation> annotations = annotationParser.getAnnotations(); // do the transformation - libTransform::IntegerTransform integerTransform(pidp, firp, &annotations, &filteredFunctions, &warnings); - integerTransform.setSaturatingArithmetic(isSaturatingArithmeticOn(argc, argv)); - integerTransform.setPathManipulationDetected(isPathManipDetected(argc, argv)); - integerTransform.setWarningsOnly(isWarningsOnly(argc, argv)); - int exitcode = integerTransform.execute(); - if (exitcode == 0) + if(firp->GetArchitectureBitWidth()==64) { - one_success = true; - firp->WriteToDB(); - integerTransform.logStats(); - delete firp; + libTransform::IntegerTransform64 integerTransform64(pidp, firp, &annotations, &filteredFunctions, &warnings); + integerTransform64.setSaturatingArithmetic(isSaturatingArithmeticOn(argc, argv)); + integerTransform64.setPathManipulationDetected(isPathManipDetected(argc, argv)); + integerTransform64.setWarningsOnly(isWarningsOnly(argc, argv)); + + int exitcode = integerTransform64.execute(); + if (exitcode == 0) + { + one_success = true; + firp->WriteToDB(); + integerTransform64.logStats(); + delete firp; + } + } + else if(firp->GetArchitectureBitWidth()==32) + { + libTransform::IntegerTransform integerTransform(pidp, firp, &annotations, &filteredFunctions, &warnings); + integerTransform.setSaturatingArithmetic(isSaturatingArithmeticOn(argc, argv)); + integerTransform.setPathManipulationDetected(isPathManipDetected(argc, argv)); + integerTransform.setWarningsOnly(isWarningsOnly(argc, argv)); + + int exitcode = integerTransform.execute(); + if (exitcode == 0) + { + one_success = true; + firp->WriteToDB(); + integerTransform.logStats(); + delete firp; + } } } catch (DatabaseError_t pnide)