Merge remote-tracking branch 'origin/GP-6887_ghidra1_ElfGnuHashBoundsCheck' into patch

This commit is contained in:
Ryan Kurtz
2026-06-01 05:06:58 -04:00
@@ -697,7 +697,7 @@ public class ElfHeader implements StructConverter {
// p_vaddr to find it relative to a PT_LOAD segment
long vaddr = dynamicHeaders[0].getVirtualAddress();
if (vaddr == 0 || dynamicHeaders[0].getFileSize() == 0) {
Msg.warn(this, "ELF Dynamic table appears to have been stripped from binary");
logError("ELF Dynamic table appears to have been stripped from binary");
return;
}
@@ -931,7 +931,7 @@ public class ElfHeader implements StructConverter {
!dynamicTable.containsDynamicValue(ElfDynamicType.DT_SYMENT) ||
dynamicHashType == null) {
if (dynamicStringTable != null) {
Msg.warn(this, "Failed to parse DT_SYMTAB, missing dynamic dependency");
logError("Failed to parse DT_SYMTAB, missing dynamic dependency");
}
return null;
}
@@ -1017,9 +1017,21 @@ public class ElfHeader implements StructConverter {
int bloomWordSize = is64Bit() ? 8 : 4;
long bucketsOffset = gnuHashTableOffset + 16 + (bloomWordSize * bloomSize);
// Identify restricted region which contains GNU hash table (arbitrary min-length)
long maxOffset = getMaxOffsetForLoadedRegionContaining(gnuHashTableOffset, 12);
if (maxOffset <= 0) {
logError("Failed to idenitify loaded GNU Hash table");
return 0;
}
long bucketOffset = bucketsOffset;
int maxSymbolIndex = 0;
for (int i = 0; i < numBuckets; i++) {
if (bucketOffset < gnuHashTableOffset || bucketOffset > maxOffset) {
logError("Error occured while inspecting GNU Hash table");
return 0;
}
int symbolIndex = reader.readInt(bucketOffset);
if (symbolIndex > maxSymbolIndex) {
maxSymbolIndex = symbolIndex;
@@ -1032,6 +1044,10 @@ public class ElfHeader implements StructConverter {
++maxSymbolIndex;
long chainOffset = bucketOffset + (4 * chainIndex); // chains immediately follow buckets
while (true) {
if (chainOffset < gnuHashTableOffset || chainOffset > maxOffset) {
logError("Error occured while inspecting GNU Hash table");
return 0;
}
int chainValue = reader.readInt(chainOffset);
if ((chainValue & 1) != 0) {
break;
@@ -1042,6 +1058,25 @@ public class ElfHeader implements StructConverter {
return maxSymbolIndex;
}
private long getMaxOffsetForLoadedRegionContaining(long offset, long minSize) {
long maxOffset = -1;
if (e_shnum != 0) {
ElfSectionHeader sectionContaining =
getSectionHeaderContainingFileRange(offset, minSize);
if (sectionContaining != null) {
maxOffset = sectionContaining.getOffset() + sectionContaining.getSize() - 1;
}
}
else {
ElfProgramHeader containingSegment =
getProgramLoadHeaderContainingFileOffset(offset);
if (containingSegment != null) {
maxOffset = containingSegment.getOffset() + containingSegment.getFileSize() - 1;
}
}
return maxOffset;
}
/**
* Walk DT_GNU_XHASH table to determine dynamic symbol count
* @param gnuHashTableOffset DT_GNU_XHASH table file offset
@@ -1296,6 +1331,7 @@ public class ElfHeader implements StructConverter {
}
}
catch (IOException e) {
logError("Elf prelink read failure (see log)");
Msg.error(this, "Elf prelink read failure", e);
}
return preLinkImageBase;