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.
This commit is contained in:
Brad King 2008-08-14 09:53:17 -04:00
parent 777e2d328a
commit 2a85f8289f
1 changed files with 93 additions and 63 deletions

View File

@ -26,6 +26,7 @@
#if defined(CMAKE_BUILD_WITH_CMAKE) #if defined(CMAKE_BUILD_WITH_CMAKE)
# include <cmsys/Terminal.h> # include <cmsys/Terminal.h>
#endif #endif
#include <cmsys/stl/algorithm>
#if defined(_WIN32) #if defined(_WIN32)
# include <windows.h> # include <windows.h>
@ -2478,32 +2479,38 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
{ {
#if defined(CMAKE_USE_ELF_PARSER) #if defined(CMAKE_USE_ELF_PARSER)
unsigned long rpathPosition = 0; int zeroCount = 0;
unsigned long rpathSize = 0; unsigned long zeroPosition[2] = {0,0};
unsigned long rpathEntryPosition = 0; unsigned long zeroSize[2] = {0,0};
unsigned long bytesBegin = 0;
std::vector<char> bytes; std::vector<char> bytes;
{ {
// Parse the ELF binary. // Parse the ELF binary.
cmELF elf(file.c_str()); cmELF elf(file.c_str());
// Get the RPATH or RUNPATH entry from it. // Get the RPATH and RUNPATH entries from it and sort them by index
cmELF::StringEntry const* se = elf.GetRPath(); // in the dynamic section header.
if(!se) 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.
{
// 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(); unsigned int count = elf.GetDynamicEntryCount();
if(count == 0) if(count == 0)
{ {
@ -2515,17 +2522,44 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
} }
return false; return false;
} }
unsigned long nullEntryPosition = elf.GetDynamicEntryPosition(count);
// Allocate and fill a buffer with zeros. // Save information about the string entries to be zeroed.
bytes.resize(nullEntryPosition - rpathEntryPosition, 0); zeroCount = se_count;
for(int i=0; i < se_count; ++i)
{
zeroPosition[i] = se[i]->Position;
zeroSize[i] = se[i]->Size;
}
// 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. // Read the part of the DYNAMIC section header that will move.
// The remainder of the buffer will be left with zeros which // The remainder of the buffer will be left with zeros which
// represent a DT_NULL entry. // represent a DT_NULL entry.
if(!elf.ReadBytes(nextEntryPosition, char* data = &bytes[0];
nullEntryPosition - nextEntryPosition, for(int i=0; i < se_count; ++i)
&bytes[0])) {
// 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) if(emsg)
{ {
@ -2533,11 +2567,7 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
} }
return false; return false;
} }
} data += sz;
else
{
// There is no RPATH or RUNPATH anyway.
return true;
} }
} }
@ -2554,7 +2584,7 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
} }
// Write the new DYNAMIC table header. // Write the new DYNAMIC table header.
if(!f.seekp(rpathEntryPosition)) if(!f.seekp(bytesBegin))
{ {
if(emsg) if(emsg)
{ {
@ -2571,8 +2601,10 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
return false; return false;
} }
// Fill the RPATH string with zero bytes. // Fill the RPATH and RUNPATH strings with zero bytes.
if(!f.seekp(rpathPosition)) for(int i=0; i < zeroCount; ++i)
{
if(!f.seekp(zeroPosition[i]))
{ {
if(emsg) if(emsg)
{ {
@ -2580,24 +2612,22 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg)
} }
return false; return false;
} }
for(unsigned long i=0; i < rpathSize; ++i) for(unsigned long j=0; j < zeroSize[i]; ++j)
{ {
f << '\0'; f << '\0';
} }
if(!f)
// Make sure everything was okay.
if(f)
{
return true;
}
else
{ {
if(emsg) if(emsg)
{ {
*emsg = "Error writing the empty rpath to the file."; *emsg = "Error writing the empty rpath string to the file.";
} }
return false; return false;
} }
}
// Everything was updated successfully.
return true;
#else #else
(void)file; (void)file;
(void)emsg; (void)emsg;