From 2a85f8289fff008d9bfb82f8081cd05008c144c9 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 14 Aug 2008 09:53:17 -0400 Subject: [PATCH] BUG: Remove both RPATH and RUNPATH entries Removal of the RPATH and RUNPATH from ELF binaries must work when both entries are present. Both entries should be removed. Previously only one would be removed and the other would be blanked because it pointed at the same string which was zeroed. This fixes gentoo bug number 224901. --- Source/cmSystemTools.cxx | 156 +++++++++++++++++++++++---------------- 1 file changed, 93 insertions(+), 63 deletions(-) diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 4e1f9453e..f4ce41c78 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -26,6 +26,7 @@ #if defined(CMAKE_BUILD_WITH_CMAKE) # include #endif +#include #if defined(_WIN32) # include @@ -2478,54 +2479,87 @@ bool cmSystemTools::ChangeRPath(std::string const& file, bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) { #if defined(CMAKE_USE_ELF_PARSER) - unsigned long rpathPosition = 0; - unsigned long rpathSize = 0; - unsigned long rpathEntryPosition = 0; + int zeroCount = 0; + unsigned long zeroPosition[2] = {0,0}; + unsigned long zeroSize[2] = {0,0}; + unsigned long bytesBegin = 0; std::vector bytes; { // Parse the ELF binary. cmELF elf(file.c_str()); - // Get the RPATH or RUNPATH entry from it. - cmELF::StringEntry const* se = elf.GetRPath(); - if(!se) + // Get the RPATH and RUNPATH entries from it and sort them by index + // in the dynamic section header. + int se_count = 0; + cmELF::StringEntry const* se[2] = {0, 0}; + if(cmELF::StringEntry const* se_rpath = elf.GetRPath()) { - se = elf.GetRunPath(); + se[se_count++] = se_rpath; + } + if(cmELF::StringEntry const* se_runpath = elf.GetRunPath()) + { + se[se_count++] = se_runpath; + } + if(se_count == 0) + { + // There is no RPATH or RUNPATH anyway. + return true; + } + if(se_count == 2 && se[1]->IndexInSection < se[0]->IndexInSection) + { + cmsys_stl::swap(se[0], se[1]); } - if(se) + // Get the size of the dynamic section header. + unsigned int count = elf.GetDynamicEntryCount(); + if(count == 0) { - // Store information about the entry. - rpathPosition = se->Position; - rpathSize = se->Size; - rpathEntryPosition = elf.GetDynamicEntryPosition(se->IndexInSection); - - // Get the file range containing the rest of the DYNAMIC table - // after the RPATH entry. - unsigned long nextEntryPosition = - elf.GetDynamicEntryPosition(se->IndexInSection+1); - unsigned int count = elf.GetDynamicEntryCount(); - if(count == 0) + // This should happen only for invalid ELF files where a DT_NULL + // appears before the end of the table. + if(emsg) { - // This should happen only for invalid ELF files where a DT_NULL - // appears before the end of the table. - if(emsg) - { - *emsg = "DYNAMIC section contains a DT_NULL before the end."; - } - return false; + *emsg = "DYNAMIC section contains a DT_NULL before the end."; } - unsigned long nullEntryPosition = elf.GetDynamicEntryPosition(count); + return false; + } - // Allocate and fill a buffer with zeros. - bytes.resize(nullEntryPosition - rpathEntryPosition, 0); + // Save information about the string entries to be zeroed. + zeroCount = se_count; + for(int i=0; i < se_count; ++i) + { + zeroPosition[i] = se[i]->Position; + zeroSize[i] = se[i]->Size; + } - // Read the part of the DYNAMIC section header that will move. - // The remainder of the buffer will be left with zeros which - // represent a DT_NULL entry. - if(!elf.ReadBytes(nextEntryPosition, - nullEntryPosition - nextEntryPosition, - &bytes[0])) + // Get the range of file positions corresponding to each entry and + // the rest of the table after them. + unsigned long entryBegin[3] = {0,0,0}; + unsigned long entryEnd[2] = {0,0}; + for(int i=0; i < se_count; ++i) + { + entryBegin[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection); + entryEnd[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection+1); + } + entryBegin[se_count] = elf.GetDynamicEntryPosition(count); + + // The data are to be written over the old table entries starting at + // the first one being removed. + bytesBegin = entryBegin[0]; + unsigned long bytesEnd = entryBegin[se_count]; + + // Allocate a buffer to hold the part of the file to be written. + // Initialize it with zeros. + bytes.resize(bytesEnd - bytesBegin, 0); + + // Read the part of the DYNAMIC section header that will move. + // The remainder of the buffer will be left with zeros which + // represent a DT_NULL entry. + char* data = &bytes[0]; + for(int i=0; i < se_count; ++i) + { + // Read data between the entries being removed. + unsigned long sz = entryBegin[i+1] - entryEnd[i]; + if(sz > 0 && !elf.ReadBytes(entryEnd[i], sz, data)) { if(emsg) { @@ -2533,11 +2567,7 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) } return false; } - } - else - { - // There is no RPATH or RUNPATH anyway. - return true; + data += sz; } } @@ -2554,7 +2584,7 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) } // Write the new DYNAMIC table header. - if(!f.seekp(rpathEntryPosition)) + if(!f.seekp(bytesBegin)) { if(emsg) { @@ -2571,33 +2601,33 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) return false; } - // Fill the RPATH string with zero bytes. - if(!f.seekp(rpathPosition)) + // Fill the RPATH and RUNPATH strings with zero bytes. + for(int i=0; i < zeroCount; ++i) { - if(emsg) + if(!f.seekp(zeroPosition[i])) { - *emsg = "Error seeking to RPATH position."; + if(emsg) + { + *emsg = "Error seeking to RPATH position."; + } + return false; + } + for(unsigned long j=0; j < zeroSize[i]; ++j) + { + f << '\0'; + } + if(!f) + { + if(emsg) + { + *emsg = "Error writing the empty rpath string to the file."; + } + return false; } - return false; - } - for(unsigned long i=0; i < rpathSize; ++i) - { - f << '\0'; } - // Make sure everything was okay. - if(f) - { - return true; - } - else - { - if(emsg) - { - *emsg = "Error writing the empty rpath to the file."; - } - return false; - } + // Everything was updated successfully. + return true; #else (void)file; (void)emsg;