From e37e8d6c8156ece6cacfccc946988c4503cec8ff Mon Sep 17 00:00:00 2001 From: jdh8d <jdh8d@git.zephyr-software.com> Date: Tue, 3 Feb 2015 16:10:32 +0000 Subject: [PATCH] adjustments for selective cfi w/o faulting --- callbacks/lib/crt.s | 2 +- include/memory_space.h | 8 ++- include/nonce_relocs.h | 16 ++++-- include/zipr.h | 10 +--- include/zipr_all.h | 1 + src/nonce_relocs.cpp | 123 ++++++++++++++++++++++++++++++++++++----- src/zipr.cpp | 3 + 7 files changed, 133 insertions(+), 30 deletions(-) diff --git a/callbacks/lib/crt.s b/callbacks/lib/crt.s index ef26ea3..7e085ee 100644 --- a/callbacks/lib/crt.s +++ b/callbacks/lib/crt.s @@ -1,4 +1,4 @@ -bits 64 +bits 32 global _start section .text _start: diff --git a/include/memory_space.h b/include/memory_space.h index 33e5202..38f6b82 100644 --- a/include/memory_space.h +++ b/include/memory_space.h @@ -46,7 +46,6 @@ struct Range_tCompare class MemorySpace_t : public std::map<RangeAddress_t,char> { public: -// MemorySpace_t():m_opts(NULL) { } MemorySpace_t(Options_t *opts) : m_opts(opts) { @@ -78,6 +77,8 @@ class MemorySpace_t : public std::map<RangeAddress_t,char> void PlopByte(RangeAddress_t addr, char the_byte) { + min_plopped=std::min(addr,min_plopped); + max_plopped=std::max(addr,max_plopped); if(this->find(addr) == this->end() ) this->SplitFreeRange(addr); (*this)[addr]=the_byte; @@ -87,11 +88,16 @@ class MemorySpace_t : public std::map<RangeAddress_t,char> char bytes[]={(char)0xe9,(char)0,(char)0,(char)0,(char)0}; // jmp rel8 this->PlopBytes(addr,bytes,sizeof(bytes)); } + RangeAddress_t GetMinPlopped() const { return min_plopped; } + RangeAddress_t GetMaxPlopped() const { return max_plopped; } + protected: std::set<Range_t, Range_tCompare> free_ranges; // keep ordered Options_t *m_opts; private: + RangeAddress_t min_plopped; + RangeAddress_t max_plopped; }; #endif diff --git a/include/nonce_relocs.h b/include/nonce_relocs.h index fce63f0..ad36b89 100644 --- a/include/nonce_relocs.h +++ b/include/nonce_relocs.h @@ -47,19 +47,21 @@ class NonceRelocs_t // main workhorse void HandleNonceRelocs(); + void UpdateAddrRanges(std::map<libIRDB::Instruction_t*,RangeAddress_t> &final_insn_locations); private: // helpers - bool IsNonceRelocation(libIRDB::Relocation_t& reloc); int GetNonceValue(libIRDB::Relocation_t& reloc); int GetNonceSize(libIRDB::Relocation_t& reloc); - void HandleNonceRelocation(libIRDB::Instruction_t& insn, libIRDB::Relocation_t& reloc); + bool IsNonceRelocation(libIRDB::Relocation_t& reloc); + libIRDB::Relocation_t* FindRelocation(libIRDB::Instruction_t* insn, std::string type); libIRDB::Relocation_t* FindNonceRelocation(libIRDB::Instruction_t* insn); - void AddSlowPathInstructions(); libIRDB::Relocation_t* FindSlowpathRelocation(libIRDB::Instruction_t* insn); - + // major workhorses + void HandleNonceRelocation(libIRDB::Instruction_t& insn, libIRDB::Relocation_t& reloc); + void AddSlowPathInstructions(); // references to input MemorySpace_t &m_memory_space; @@ -73,7 +75,11 @@ class NonceRelocs_t // couldn't. This will be necessary when we need to emit code for the slow path libIRDB::InstructionSet_t slow_path_nonces; - + + // max_addr_updates + libIRDB::InstructionSet_t max_addr_update; + libIRDB::InstructionSet_t min_addr_update; + }; #endif diff --git a/include/zipr.h b/include/zipr.h index b124b82..dde5478 100644 --- a/include/zipr.h +++ b/include/zipr.h @@ -72,19 +72,11 @@ class Zipr_t void UpdateCallbacks(); void PrintStats(); - // emitting bytes. -// moved to memory_space.Plop* -// void PlopByte(RangeAddress_t addr, char the_byte); -// void PlopBytes(RangeAddress_t addr, const char the_byte[], int num); -// void PlopJump(RangeAddress_t addr); - // emiting instructions - RangeAddress_t PlopInstruction(libIRDB::Instruction_t* insn,RangeAddress_t addr); + RangeAddress_t PlopInstruction(libIRDB::Instruction_t* insn, RangeAddress_t addr); RangeAddress_t PlopWithTarget(libIRDB::Instruction_t* insn, RangeAddress_t at); RangeAddress_t PlopWithCallback(libIRDB::Instruction_t* insn, RangeAddress_t at); - - // patching void PatchJump(RangeAddress_t at_addr, RangeAddress_t to_addr); void ApplyPatches(libIRDB::Instruction_t* insn); diff --git a/include/zipr_all.h b/include/zipr_all.h index d10a9e5..96e5839 100644 --- a/include/zipr_all.h +++ b/include/zipr_all.h @@ -37,6 +37,7 @@ #include <list> #include <map> #include <libIRDB-core.hpp> +#include <algorithm> #include "elfio/elfio.hpp" #include "elfio/elfio_dump.hpp" diff --git a/src/nonce_relocs.cpp b/src/nonce_relocs.cpp index ec5e1d5..7764a98 100644 --- a/src/nonce_relocs.cpp +++ b/src/nonce_relocs.cpp @@ -1,6 +1,7 @@ #include <zipr_all.h> #include <string> +#include <algorithm> #include "utils.hpp" #include "Rewrite_Utility.hpp" @@ -10,6 +11,7 @@ using namespace std; using namespace zipr; using namespace ELFIO; + static Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, string p_asm) { Instruction_t* newinstr; @@ -90,33 +92,76 @@ void NonceRelocs_t::HandleNonceRelocation(Instruction_t &insn, Relocation_t& rel void NonceRelocs_t::AddSlowPathInstructions() { - Instruction_t* slow_path=NULL, *tmp=NULL; + InstructionSet_t::iterator it; + for( it=m_firp.GetInstructions().begin(); it!=m_firp.GetInstructions().end(); ++it) + { + Instruction_t* insn=*it; + Relocation_t* reloc=FindSlowpathRelocation(insn); + if(reloc) + break; + } + // exited loop normally, or hit the break statement? + if(it==m_firp.GetInstructions().end()) + { + cout<<"Found no slow paths to link, skipping slow-path code."<<endl; + return; + } + + +// optimization +// find out if slow path insns are even needed! + + Instruction_t* slow_path=NULL, *exit_node=NULL, *tmp=NULL; + string reg="ecx"; + if(m_firp.GetArchitectureBitWidth()==64) + reg="rcx"; + // call exit. + exit_node= slow_path=tmp = addNewAssembly(&m_firp, NULL, "mov eax, 1"); tmp = insertAssemblyAfter(&m_firp,tmp,"int 0x80",NULL); - for(InstructionSet_t::iterator it=slow_path_nonces.begin(); - it!=slow_path_nonces.end(); - ++it - ) + for(it=slow_path_nonces.begin(); it!=slow_path_nonces.end(); ++it) { Instruction_t* insn=*it; Relocation_t* reloc=FindNonceRelocation(insn); assert(reloc); - string reg="ecx"; - if(m_firp.GetArchitectureBitWidth()==64) - reg="rcx"; string assembly="cmp "+reg+", "+to_string(insn->GetIndirectBranchTargetAddress()->GetVirtualOffset()); + // insert before acts weird, and really does enough bookkeeping to insert-after in a way to mimic insert before. Instruction_t* after = insertAssemblyBefore(&m_firp,slow_path,assembly); Instruction_t* jne = insertAssemblyAfter(&m_firp, slow_path, "je 0", insn); + exit_node=after; } - for(InstructionSet_t::iterator it=m_firp.GetInstructions().begin(); - it!=m_firp.GetInstructions().end(); - ++it - ) +#ifdef CGC + // CGC needs to keep from faulting, so we have to check to make sure the IB is an intra-module IB. + // if not, we terminate immediately. + // so, we emit this sequence before we try the slow path: + // pop rcx (get ret addr) + // cmp rcx, start_segement_addr + // jlt terminate + // cmp rcx, end_segment_addr + // jgt terminate + // After we're sure it's in this segment, we can + // go ahead and check for a nonce that we layed down previously. + // cmp byte [rcx-1], 0xf4 + // jeq slow_path + + Instruction_t* after = insertAssemblyBefore(&m_firp,slow_path,"pop "+reg); + tmp = insertAssemblyAfter(&m_firp,slow_path,"cmp "+reg+", 0x12345678"); + min_addr_update.insert(tmp); + tmp = insertAssemblyAfter(&m_firp,tmp,"jl 0",exit_node); // terminate + tmp = insertAssemblyAfter(&m_firp,tmp,"cmp "+reg+", 0x87654321"); + max_addr_update.insert(tmp); + tmp = insertAssemblyAfter(&m_firp,tmp,"jg 0",exit_node); // terminate + tmp = insertAssemblyAfter(&m_firp,tmp,"cmp byte ["+reg+"-1], 0xf4"); + tmp = insertAssemblyAfter(&m_firp,tmp,"jne 0",after); // finally, go to the slow path checks when a nonce didn't work. + tmp = insertAssemblyAfter(&m_firp,tmp,"jmp "+reg); +#endif // CGC + + for( it=m_firp.GetInstructions().begin(); it!=m_firp.GetInstructions().end(); ++it) { Instruction_t* insn=*it; Relocation_t* reloc=FindSlowpathRelocation(insn); @@ -124,17 +169,18 @@ void NonceRelocs_t::AddSlowPathInstructions() insn->SetTarget(slow_path); } + m_firp.SetBaseIDS(); // assign a unique ID to each insn. m_firp.AssembleRegistry(); // resolve all assembly into actual bits. } -Relocation_t* NonceRelocs_t::FindSlowpathRelocation(Instruction_t* insn) +Relocation_t* NonceRelocs_t::FindRelocation(Instruction_t* insn, string type) { Instruction_t* first_slow_path_insn=NULL; RelocationSet_t::iterator rit; for( rit=insn->GetRelocations().begin(); rit!=insn->GetRelocations().end(); ++rit) { Relocation_t& reloc=*(*rit); - if(reloc.GetType()=="slow_cfi_path") + if(reloc.GetType()==type) { return &reloc; } @@ -142,6 +188,11 @@ Relocation_t* NonceRelocs_t::FindSlowpathRelocation(Instruction_t* insn) return NULL; } +Relocation_t* NonceRelocs_t::FindSlowpathRelocation(Instruction_t* insn) +{ + return FindRelocation(insn,"slow_cfi_path"); +} + Relocation_t* NonceRelocs_t::FindNonceRelocation(Instruction_t* insn) { Instruction_t* first_slow_path_insn=NULL; @@ -174,6 +225,9 @@ void NonceRelocs_t::HandleNonceRelocs() { HandleNonceRelocation(insn,*reloc); handled++; + + assert(insn.GetIndirectBranchTargetAddress()); + } } @@ -185,3 +239,44 @@ void NonceRelocs_t::HandleNonceRelocs() } + +void NonceRelocs_t::UpdateAddrRanges(std::map<libIRDB::Instruction_t*,RangeAddress_t> &final_insn_locations) +{ + RangeAddress_t min_addr=m_memory_space.GetMinPlopped(); + RangeAddress_t max_addr=m_memory_space.GetMaxPlopped(); + + InstructionSet_t::iterator it; + for(it=min_addr_update.begin(); it!=min_addr_update.end(); ++it) + { + Instruction_t& insn=*(*it); + RangeAddress_t insn_addr=final_insn_locations[&insn]; + if(insn_addr) + { + cout<<"Updating min_addr at "<<hex<<insn_addr<<" to compare to "<<min_addr<<endl; + m_memory_space.PlopBytes(insn_addr+2,(const char*)&min_addr,sizeof(RangeAddress_t)); + } + else + { + cout<<"No addr for min_addr at "<<hex<<insn_addr<<" to compare to "<<min_addr<<endl; + } + } + + for(it=max_addr_update.begin(); it!=max_addr_update.end(); ++it) + { + Instruction_t& insn=*(*it); + RangeAddress_t insn_addr=final_insn_locations[&insn]; + assert(insn_addr); + if(insn_addr) + { + cout<<"Updating max_addr at "<<hex<<insn_addr<<" to compare to "<<max_addr<<endl; + m_memory_space.PlopBytes(insn_addr+2,(const char*)&max_addr,sizeof(RangeAddress_t)); + } + else + { + cout<<"No addr for max_addr at "<<hex<<insn_addr<<" to compare to "<<max_addr<<endl; + } + } + + + +} diff --git a/src/zipr.cpp b/src/zipr.cpp index d6da1f1..111b714 100644 --- a/src/zipr.cpp +++ b/src/zipr.cpp @@ -147,6 +147,9 @@ void Zipr_t::CreateBinaryFile(const std::string &name) // go ahead and update any callback sites with the new locations UpdateCallbacks(); + // tell the Nonce class to update it's range of high/low addrs if it used any. + nr.UpdateAddrRanges(final_insn_locations); + m_stats->total_free_ranges = memory_space.GetRangeCount(); // write binary file to disk -- GitLab