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)
# include <cmsys/Terminal.h>
#endif
#include <cmsys/stl/algorithm>
#if defined(_WIN32)
# include <windows.h>
@ -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<char> 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;