Skip to content

Commit

Permalink
Fix issue #466
Browse files Browse the repository at this point in the history
  • Loading branch information
rthomas committed Sep 26, 2020
1 parent 9e6902c commit 923ad13
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 3 deletions.
3 changes: 3 additions & 0 deletions include/LIEF/ELF/Binary.hpp
Expand Up @@ -562,6 +562,9 @@ class LIEF_API Binary : public LIEF::Binary {
void shift_symbols(uint64_t from, uint64_t shift);
void shift_relocations(uint64_t from, uint64_t shift);

template<class ELF_T>
void fix_got_entries(uint64_t from, uint64_t shift);

LIEF::Binary::functions_t eh_frame_functions(void) const;
LIEF::Binary::functions_t armexid_functions(void) const;

Expand Down
6 changes: 6 additions & 0 deletions src/ELF/Binary.cpp
Expand Up @@ -1357,6 +1357,12 @@ Section& Binary::extend(const Section& section, uint64_t size) {
this->shift_symbols(from_address, shift);
this->shift_relocations(from_address, shift);

if (this->type() == ELF_CLASS::ELFCLASS32) {
this->fix_got_entries<ELF32>(from_address, shift);
} else {
this->fix_got_entries<ELF64>(from_address, shift);
}


if (this->header().entrypoint() >= from_address) {
this->header().entrypoint(this->header().entrypoint() + shift);
Expand Down
37 changes: 37 additions & 0 deletions src/ELF/Binary.tcc
Expand Up @@ -484,6 +484,12 @@ Segment& Binary::add_segment<E_TYPE::ET_DYN>(const Segment& segment, uint64_t ba
this->shift_symbols(from, shift);
this->shift_relocations(from, shift);

if (this->type() == ELF_CLASS::ELFCLASS32) {
this->fix_got_entries<ELF32>(from, shift);
} else {
this->fix_got_entries<ELF64>(from, shift);
}

if (this->header().entrypoint() >= from) {
this->header().entrypoint(this->header().entrypoint() + shift);
}
Expand Down Expand Up @@ -594,6 +600,12 @@ Segment& Binary::extend_segment<SEGMENT_TYPES::PT_LOAD>(const Segment& segment,
this->shift_symbols(from_address, shift);
this->shift_relocations(from_address, shift);

if (this->type() == ELF_CLASS::ELFCLASS32) {
this->fix_got_entries<ELF32>(from_address, shift);
} else {
this->fix_got_entries<ELF64>(from_address, shift);
}

if (this->header().entrypoint() >= from_address) {
this->header().entrypoint(this->header().entrypoint() + shift);
}
Expand Down Expand Up @@ -686,5 +698,30 @@ Section& Binary::add_section<false>(const Section& section) {
return *(this->sections_.back());
}

template<class ELF_T>
void Binary::fix_got_entries(uint64_t from, uint64_t shift) {
using ptr_t = typename ELF_T::Elf_Addr;

if (not this->has(DYNAMIC_TAGS::DT_PLTGOT)) {
return;
}
const uint64_t addr = this->get(DYNAMIC_TAGS::DT_PLTGOT).value();
std::vector<uint8_t> content = this->get_content_from_virtual_address(addr, 3 * sizeof(ptr_t));
if (content.size() != 3 * sizeof(ptr_t)) {
LOG(ERROR) << "Cant't read got entries!";
return;
}

auto got = reinterpret_cast<ptr_t*>(content.data());
if (got[0] > 0 and got[0] > from) { // Offset to the dynamic section
got[0] += shift;
}

if (got[1] > 0 and got[1] > from) { // Prelinked value (unlikely?)
got[1] += shift;
}
this->patch_address(addr, content);
}

}
}
8 changes: 5 additions & 3 deletions src/ELF/Builder.tcc
Expand Up @@ -1210,14 +1210,16 @@ void Builder::build_section_relocations(void) {
it_sections sections = this->binary_->sections();

std::vector<Section*> rel_section;
for(Section& S: sections)
if(S.type() == ((isRela)?ELF_SECTION_TYPES::SHT_RELA:ELF_SECTION_TYPES::SHT_REL))
for (Section& S: sections) {
if (S.type() == ((isRela) ? ELF_SECTION_TYPES::SHT_RELA:ELF_SECTION_TYPES::SHT_REL)) {
rel_section.push_back(&S);
}
}


// FIXME: Warn if not rel section found?

for(Section* section: rel_section) {
for (Section* section: rel_section) {

if (section->information() == 0 or section->information() >= sections.size())
throw LIEF::not_found("Unable to find associated section for SHT_REL{A} section");
Expand Down
4 changes: 4 additions & 0 deletions tests/elf/CMakeLists.txt
Expand Up @@ -170,6 +170,10 @@ if (PYTHON_TESTS_ENABLED)
${PYTHON_EXECUTABLE}
"${CMAKE_CURRENT_SOURCE_DIR}/test_core.py")

ADD_PYTHON_TEST(ELF_PYTHON_issue_466
${PYTHON_EXECUTABLE}
"${CMAKE_CURRENT_SOURCE_DIR}/test_466.py")


# Examples
# --------
Expand Down
73 changes: 73 additions & 0 deletions tests/elf/test_466.py
@@ -0,0 +1,73 @@
#!/usr/bin/env python
import unittest
import logging
import os
import sys
import stat
import re
import subprocess
import tempfile
import shutil
from subprocess import Popen

import lief
from lief.ELF import Section

from unittest import TestCase
from utils import get_sample, has_recent_glibc

class TestGOTPatch(TestCase):
def setUp(self):
self.logger = logging.getLogger(__name__)
self.tmp_dir = tempfile.mkdtemp(suffix='_lief_test_466')
self.logger.debug("temp dir: {}".format(self.tmp_dir))


@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
@unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
def test_freebl(self):
libfreebl3_path = get_sample('ELF/ELF64_x86-64_library_libfreebl3.so')
output_ls = os.path.join(self.tmp_dir, "ls.new")
output_libfreebl3 = os.path.join(self.tmp_dir, "libfreebl3.so")

libfreebl3 = lief.parse(libfreebl3_path)
ls = lief.parse("/usr/bin/ls")

ls[lief.ELF.DYNAMIC_TAGS.FLAGS_1].remove(lief.ELF.DYNAMIC_FLAGS_1.PIE)

ls.add_library("libfreebl3.so")

ls += lief.ELF.DynamicEntryRunPath("$ORIGIN")
libfreebl3 += lief.ELF.DynamicEntryRunPath("$ORIGIN")

ls.write(output_ls)
libfreebl3.write(output_libfreebl3)

st = os.stat(output_ls)
os.chmod(output_ls, st.st_mode | stat.S_IEXEC)

st = os.stat(output_libfreebl3)
os.chmod(output_libfreebl3, st.st_mode | stat.S_IEXEC)

p = Popen([output_ls, "--version"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, _ = p.communicate()
self.logger.debug(stdout.decode("utf8"))
self.assertIsNotNone(re.search(r'ls \(GNU coreutils\) ', stdout.decode("utf8")))
self.assertEqual(p.returncode, 0)

def tearDown(self):
# Delete it
if os.path.isdir(self.tmp_dir):
shutil.rmtree(self.tmp_dir)

if __name__ == '__main__':

root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)

ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
root_logger.addHandler(ch)

unittest.main(verbosity=2)

0 comments on commit 923ad13

Please sign in to comment.