Skip to content

Commit

Permalink
Merge branch 'stack-properties-auxdata' into 'main'
Browse files Browse the repository at this point in the history
Create ELF stack properties auxdata

Closes #585

See merge request rewriting/ddisasm!1170
  • Loading branch information
aeflores committed Nov 9, 2023
2 parents f6bea62 + 4bb0243 commit 60f3f8d
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 59 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* Use pre-existing code blocks as hints when disassembling a RAW binary.
* Better data access computation for MIPS binaries.
* Detect incremental linking regions in PE binaries.
* Create elfStackSize and elfStackExec auxdata from ELF PT_GNU_STACK segments.
* Requires gtirb >=1.12.1, gtirb-pprinter >=2.0.0

# 1.7.0
* Update code inference to use weighted interval scheduling to resolve blocks;
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,12 @@ endif()
# ---------------------------------------------------------------------------
# gtirb
# ---------------------------------------------------------------------------
find_package(gtirb 1.10.5 REQUIRED)
find_package(gtirb 1.12.1 REQUIRED)

# ---------------------------------------------------------------------------
# pretty-printer
# ---------------------------------------------------------------------------
find_package(gtirb_pprinter 1.8.1 REQUIRED)
find_package(gtirb_pprinter 2.0.0 REQUIRED)

# ---------------------------------------------------------------------------
# libehp
Expand Down
4 changes: 2 additions & 2 deletions doc/source/GENERAL/2-Building-Ddisasm.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ that standard such as gcc 9, clang 6, or MSVC 2017.

To build Ddisasm from source, the following requirements should be installed:

- [gtirb](https://github.com/grammatech/gtirb)
- [gtirb-pprinter](https://github.com/grammatech/gtirb-pprinter)
- [gtirb](https://github.com/grammatech/gtirb) version 1.12.1 or later
- [gtirb-pprinter](https://github.com/grammatech/gtirb-pprinter), version 2.0.0 or later
- [Capstone](http://www.capstone-engine.org/), version 5.0.0 or later
- GrammaTech builds and tests using the [GrammaTech/capstone](https://github.com/GrammaTech/capstone) fork.
- [Souffle](https://souffle-lang.github.io), version 2.4 with support for 64 bit numbers (via `-DSOUFFLE_DOMAIN_64BIT=1` during configuration)
Expand Down
2 changes: 2 additions & 0 deletions src/Registration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ void registerAuxDataTypes()
gtirb::AuxDataContainer::registerAuxDataType<Overlay>();
gtirb::AuxDataContainer::registerAuxDataType<ElfDynamicInit>();
gtirb::AuxDataContainer::registerAuxDataType<ElfDynamicFini>();
gtirb::AuxDataContainer::registerAuxDataType<ElfStackSize>();
gtirb::AuxDataContainer::registerAuxDataType<ElfStackExec>();
}

void registerDatalogLoaders()
Expand Down
76 changes: 23 additions & 53 deletions src/gtirb-builder/ElfReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,6 @@ void ElfReader::buildSections()
relocateSections();
}

bool GnuStackSectionExist = false;
uint64_t Index = 0;
for(auto &Section : Elf->sections())
{
Expand Down Expand Up @@ -712,11 +711,6 @@ void ElfReader::buildSections()
SectionProperties[S->getUUID()] = {static_cast<uint64_t>(Section.type()),
static_cast<uint64_t>(Section.flags())};

if(Section.name() == ".note.GNU-stack")
{
GnuStackSectionExist = true;
}

// In case of ARM32, inspect .ARM.attributes section to see
// if the binary is Microcontroller.
if(Module->getISA() == gtirb::ISA::ARM && Section.name() == ".ARM.attributes")
Expand All @@ -730,53 +724,6 @@ void ElfReader::buildSections()
Index++;
}

// If .note.GNU-stack section does not exist and there is a segment
// type of PT_GNU_STACK, create an artificial section for it.
if(!GnuStackSectionExist)
{
auto GnuStackSegment = std::find_if(
Elf->segments().begin(), Elf->segments().end(),
[](auto &S) { return S.type() == LIEF::ELF::SEGMENT_TYPES::PT_GNU_STACK; });

if(GnuStackSegment != Elf->segments().end())
{
gtirb::Section *S = Module->addSection(*Context, ".note.GNU-stack");
S->addFlag(gtirb::SectionFlag::Loaded);
S->addFlag(gtirb::SectionFlag::Readable);
S->addFlag(gtirb::SectionFlag::Initialized);
uint64_t Addr = GnuStackSegment->virtual_address();
// If Addr is 0, create an address after TLS.
if(Addr == 0)
{
uint64_t TlsSize = 0;
std::optional<std::pair<uint64_t, uint64_t>> TlsAddr = getTls();
if(TlsAddr)
{
TlsSize = TlsAddr->second - TlsAddr->first;
}
Addr = tlsBaseAddress() + TlsSize;
// Use the next available page.
Addr = (Addr & ~(0x1000 - 1)) + 0x1000;

SectionRelocations[S->getName()] = Addr;
}

uint64_t Size = GnuStackSegment->virtual_size();
auto Bytes = Elf->get_content_from_virtual_address(Addr, Size);
gtirb::ByteInterval *BI = S->addByteInterval(*Context, gtirb::Addr(Addr), Bytes.begin(),
Bytes.end(), Size, Bytes.size());
auto DataBlock = gtirb::DataBlock::Create(*Context, Size);
BI->addBlock(0, DataBlock);

uint64_t Type = static_cast<uint64_t>(LIEF::ELF::ELF_SECTION_TYPES::SHT_PROGBITS);
uint64_t Flags = 0;

Alignment[S->getUUID()] = 0;
SectionIndex[Index++] = S->getUUID();
SectionProperties[S->getUUID()] = {Type, Flags};
}
}

// Add `overlay` aux data table.
if(auto Overlay = Elf->overlay(); Overlay.size() > 0)
{
Expand Down Expand Up @@ -1272,6 +1219,29 @@ void ElfReader::addAuxData()
DynamicEntryTuples.insert({it->first, it->second});
}
Module->addAuxData<gtirb::schema::DynamicEntries>(std::move(DynamicEntryTuples));

// Build segment auxdata
bool FoundStackSegment = false;
for(auto &Segment : Elf->segments())
{
switch(Segment.type())
{
case LIEF::ELF::SEGMENT_TYPES::PT_GNU_STACK:
{
if(FoundStackSegment)
{
std::cerr << "\nWARNING: multiple PT_GNU_STACK segments\n";
continue;
}
Module->addAuxData<gtirb::schema::ElfStackSize>(Segment.virtual_size());
Module->addAuxData<gtirb::schema::ElfStackExec>(
Segment.has(LIEF::ELF::ELF_SEGMENT_FLAGS::PF_X));
}
default:
// all other segments types are currently ignored.
continue;
}
}
}

std::string ElfReader::getRelocationType(const LIEF::ELF::Relocation &Entry)
Expand Down
2 changes: 0 additions & 2 deletions src/tests/ElfReader.Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ TEST_P(ElfReaderTest, sections)
for(const auto& Section : Module.sections())
{
const std::string& Name = Section.getName();
if(Name == ".note.GNU-stack")
continue;
EXPECT_EQ(Names.count(Name), 1);
EXPECT_EQ(Sizes[Name], Section.getSize());
EXPECT_EQ(Addresses[Name], static_cast<uint64_t>(Section.getAddress().value()));
Expand Down
2 changes: 2 additions & 0 deletions src/tests/Main.Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ void registerTestAuxDataTypes()
gtirb::AuxDataContainer::registerAuxDataType<LibraryPaths>();
gtirb::AuxDataContainer::registerAuxDataType<SymbolicExpressionSizes>();
gtirb::AuxDataContainer::registerAuxDataType<DdisasmVersion>();
gtirb::AuxDataContainer::registerAuxDataType<ElfStackSize>();
gtirb::AuxDataContainer::registerAuxDataType<ElfStackExec>();
}

int main(int argc, char** argv)
Expand Down
48 changes: 48 additions & 0 deletions tests/misc_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,54 @@ def test_dynamic_init_fini(self):
self.assertEqual(int(init_match.group(1), 16), init.address)
self.assertEqual(int(fini_match.group(1), 16), fini.address)

@unittest.skipUnless(
platform.system() == "Linux", "This test is linux only."
)
def test_stack_size(self):
"""
Test that a PT_GNU_STACK segment with size populates elfStackSize
"""
binary = "ex"
with cd(ex_dir / "ex1"):
stack_size = 0x200000
self.assertTrue(
compile(
"gcc", "g++", "-O0", [f"-Wl,-z,stack-size={stack_size}"]
)
)
self.assertTrue(disassemble(binary, format="--ir")[0])

ir = gtirb.IR.load_protobuf(binary + ".gtirb")
m = ir.modules[0]

self.assertEqual(m.aux_data["elfStackSize"].data, stack_size)

@unittest.skipUnless(
platform.system() == "Linux", "This test is linux only."
)
def test_stack_exec(self):
"""
Test that a PT_GNU_STACK segment populates correct executable flags
"""
cases = (
("execstack", True),
("noexecstack", False),
)

for ld_keyword, is_exec in cases:
binary = "ex"
with self.subTest(keyword=ld_keyword), cd(ex_dir / "ex1"):
self.assertTrue(
compile("gcc", "g++", "-O0", [f"-Wl,-z,{ld_keyword}"])
)
self.assertTrue(disassemble(binary, format="--ir")[0])

ir = gtirb.IR.load_protobuf(binary + ".gtirb")
m = ir.modules[0]

# verify executable bit
self.assertEqual(m.aux_data["elfStackExec"].data, is_exec)


class RawGtirbTests(unittest.TestCase):
@unittest.skipUnless(
Expand Down

0 comments on commit 60f3f8d

Please sign in to comment.