From e89a8dcde33f10d04bc614b8a711313cdb342f53 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Wed, 9 Jun 2021 18:26:05 -0400 Subject: [PATCH] GP-1029 Detect and mark unsupported EXTERNAL data relocation and correct MIPS compound relocation processing bug. --- .../elf/relocation/ElfRelocationHandler.java | 43 +++++++++++++++++++ .../AARCH64_ElfRelocationHandler.java | 5 +++ .../relocation/ARM_ElfRelocationHandler.java | 8 +++- .../relocation/MIPS_ElfRelocationHandler.java | 13 ++++-- .../PowerPC64_ElfRelocationHandler.java | 11 +++-- .../PowerPC_ElfRelocationHandler.java | 14 +++--- .../RISCV_ElfRelocationHandler.java | 6 +++ .../X86_32_ElfRelocationHandler.java | 7 +++ .../X86_64_ElfRelocationHandler.java | 9 +++- 9 files changed, 102 insertions(+), 14 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java index 2f0e0443e1..44142e1fff 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java @@ -22,6 +22,7 @@ import ghidra.app.util.importer.MessageLog; import ghidra.program.model.address.Address; import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.mem.MemoryBlock; import ghidra.util.classfinder.ExtensionPoint; import ghidra.util.exception.NotFoundException; @@ -69,6 +70,48 @@ abstract public class ElfRelocationHandler implements ExtensionPoint { ElfRelocation relocation, Address relocationAddress) throws MemoryAccessException, NotFoundException; + /** + * Determine if symbolAddr is contained within the EXTERNAL block. If so, relocationAddress will be marked + * with a error bookmark. + * NOTE: This method should only be invoked when the symbol offset will be adjust with a non-zero + * value (i.e., addend). + * @param program + * @param relocationAddress relocation address to be bookmarked if EXTERNAL block relocation + * @param symbolAddr symbol address correspondng to relocation (may be null) + * @param symbolName symbol name (may not be null if symbolAddr is not null) + * @param adjustment relocation symbol offset adjustment/addend + * @param log import log + * @return true if symbolAddress contained within EXTERNAL block. + */ + public static boolean isUnsupportedExternalRelocation(Program program, + Address relocationAddress, Address symbolAddr, String symbolName, long adjustment, + MessageLog log) { + + if (symbolAddr == null) { + return false; + } + + MemoryBlock block = program.getMemory().getBlock(symbolAddr); + if (block == null || !MemoryBlock.EXTERNAL_BLOCK_NAME.equals(block.getName())) { + return false; + } + + String sign = "+"; + if (adjustment < 0) { + adjustment = -adjustment; + sign = "-"; + } + String adjStr = sign + "0x" + Long.toHexString(adjustment); + + symbolName = symbolName == null ? "" : symbolName; + log.appendMsg("Unsupported EXTERNAL Data Elf Relocation: at " + relocationAddress + + " (External Location = " + symbolName + adjStr + ")"); + BookmarkManager bookmarkManager = program.getBookmarkManager(); + bookmarkManager.setBookmark(relocationAddress, BookmarkType.ERROR, "EXTERNAL Relocation", + "Unsupported EXTERNAL Data Elf Relocation: External Location = " + symbolName + adjStr); + return true; + } + /** * Generate error log entry and bookmark at relocationAddress indicating * an unhandled relocation. diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java index 729606616d..112471d611 100644 --- a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java +++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java @@ -64,12 +64,17 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler { boolean isBigEndianInstructions = program.getLanguage().getLanguageDescription().getInstructionEndian().isBigEndian(); + Address symbolAddr = elfRelocationContext.getSymbolAddress(sym); long symbolValue = elfRelocationContext.getSymbolValue(sym); long newValue = 0; switch (type) { // .xword: (S+A) case AARCH64_ElfRelocationConstants.R_AARCH64_ABS64: { + if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress, + symbolAddr, symbolName, addend, elfRelocationContext.getLog())) { + addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup + } newValue = (symbolValue + addend); memory.setLong(relocationAddress, newValue); break; diff --git a/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java b/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java index dae88b4da3..6bb4254096 100644 --- a/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java +++ b/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java @@ -59,6 +59,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler { long offset = (int) relocationAddress.getOffset(); + Address symbolAddr = elfRelocationContext.getSymbolAddress(sym); long symbolValue = elfRelocationContext.getSymbolValue(sym); int newValue = 0; @@ -85,6 +86,10 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler { if (elfRelocationContext.extractAddend()) { addend = memory.getInt(relocationAddress); } + if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress, + symbolAddr, symbolName, addend, elfRelocationContext.getLog())) { + addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup + } newValue = (int) (symbolValue + addend); if (isThumb) { newValue |= 1; @@ -354,8 +359,9 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler { oldValue = (oldValue ^ 0x8000) - 0x8000; oldValue += symbolValue; - if (type == ARM_ElfRelocationConstants.R_ARM_MOVT_ABS) + if (type == ARM_ElfRelocationConstants.R_ARM_MOVT_ABS) { oldValue >>= 16; + } newValue &= 0xfff0f000; newValue |= ((oldValue & 0xf000) << 4) | diff --git a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java index ffa54949bf..ae996731a4 100644 --- a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java +++ b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java @@ -121,8 +121,8 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler { ElfSymbol elfSymbol = mipsRelocationContext.getSymbol(symbolIndex); + Address symbolAddr = mipsRelocationContext.getSymbolAddress(elfSymbol); long symbolValue = mipsRelocationContext.getSymbolValue(elfSymbol); - String symbolName = elfSymbol.getNameAsString(); long addend = 0; @@ -152,7 +152,6 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler { } } - mipsRelocationContext.useSavedAddend = saveValue; mipsRelocationContext.savedAddendHasError = false; mipsRelocationContext.savedAddend = 0; @@ -407,7 +406,13 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler { symbolValue = mipsRelocationContext.getImageBaseWordAdjustmentOffset(); } value = (int) symbolValue; - value += mipsRelocationContext.extractAddend() ? oldValue : addend; + int a = (int) (mipsRelocationContext.extractAddend() ? oldValue : addend); + // NOTE: this may not detect correctly for all combound relocations + if (a != 0 && isUnsupportedExternalRelocation(program, relocationAddress, + symbolAddr, symbolName, a, log)) { + a = 0; // prefer bad fixup for EXTERNAL over really-bad fixup + } + value += a; newValue = value; writeNewValue = true; @@ -720,6 +725,8 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler { } } + mipsRelocationContext.useSavedAddend = saveValue; + } private boolean isMIPS16Reloc(int type) { diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java index c6021c645b..aff180180e 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java @@ -66,6 +66,8 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler { long offset = relocationAddress.getOffset(); ElfSymbol sym = elfRelocationContext.getSymbol(symbolIndex); + String symbolName = sym.getNameAsString(); + Address symbolAddr = elfRelocationContext.getSymbolAddress(sym); long symbolValue = elfRelocationContext.getSymbolValue(sym); int oldValue = memory.getInt(relocationAddress); @@ -93,7 +95,7 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler { Symbol tocBaseSym = SymbolUtilities.getLabelOrFunctionSymbol(program, PowerPC64_ElfExtension.TOC_BASE, err -> log.error("PPC_ELF", err)); if (tocBaseSym == null) { - markAsError(program, relocationAddress, type, sym.getNameAsString(), + markAsError(program, relocationAddress, type, symbolName, "TOC_BASE unknown", log); return; } @@ -104,7 +106,7 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler { switch (type) { case PowerPC64_ElfRelocationConstants.R_PPC64_COPY: - markAsWarning(program, relocationAddress, "R_PPC64_COPY", sym.getNameAsString(), + markAsWarning(program, relocationAddress, "R_PPC64_COPY", symbolName, symbolIndex, "Runtime copy not supported", elfRelocationContext.getLog()); break; case PowerPC64_ElfRelocationConstants.R_PPC64_ADDR32: @@ -220,6 +222,10 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler { case PowerPC64_ElfRelocationConstants.R_PPC64_UADDR64: case PowerPC64_ElfRelocationConstants.R_PPC64_ADDR64: case PowerPC64_ElfRelocationConstants.R_PPC64_GLOB_DAT: + if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress, + symbolAddr, symbolName, addend, elfRelocationContext.getLog())) { + addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup + } value64 = symbolValue + addend; memory.setLong(relocationAddress, value64); break; @@ -227,7 +233,6 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler { memory.setLong(relocationAddress, toc); break; default: - String symbolName = sym.getNameAsString(); markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName, elfRelocationContext.getLog()); break; diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java index 248f830c45..178b04d091 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java @@ -63,7 +63,7 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler { int offset = (int) relocationAddress.getOffset(); ElfSymbol sym = elfRelocationContext.getSymbol(symbolIndex); - int symbolValue; + // if (sym.isLocal() && sym.getSectionHeaderIndex() != ElfSectionHeaderConstants.SHN_UNDEF) { // // // see glibc - sysdeps/powerpc/powerpc32/dl-machine.h elf_machine_rela @@ -75,20 +75,26 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler { // symbolValue = (int) elfRelocationContext.getImageBaseWordAdjustmentOffset(); // } // else { - symbolValue = (int) elfRelocationContext.getSymbolValue(sym); + Address symbolAddr = (elfRelocationContext.getSymbolAddress(sym)); + int symbolValue = (int) elfRelocationContext.getSymbolValue(sym); // } + String symbolName = sym.getNameAsString(); int oldValue = memory.getInt(relocationAddress); int newValue = 0; switch (type) { case PowerPC_ElfRelocationConstants.R_PPC_COPY: - markAsWarning(program, relocationAddress, "R_PPC_COPY", sym.getNameAsString(), + markAsWarning(program, relocationAddress, "R_PPC_COPY", symbolName, symbolIndex, "Runtime copy not supported", elfRelocationContext.getLog()); break; case PowerPC_ElfRelocationConstants.R_PPC_ADDR32: case PowerPC_ElfRelocationConstants.R_PPC_UADDR32: case PowerPC_ElfRelocationConstants.R_PPC_GLOB_DAT: + if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress, + symbolAddr, symbolName, addend, elfRelocationContext.getLog())) { + addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup + } newValue = symbolValue + addend; memory.setInt(relocationAddress, newValue); break; @@ -194,13 +200,11 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler { // TODO: Handle this case if needed - hopefully the EXTERNAL block is // not too far away since a fabricated GOT would be in the same block // and we may only have room in the plt for two instructions. - String symbolName = sym.getNameAsString(); markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName, elfRelocationContext.getLog()); } break; default: - String symbolName = sym.getNameAsString(); markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName, elfRelocationContext.getLog()); break; diff --git a/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java b/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java index 940f03b7e8..25e3bcfc2a 100644 --- a/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java +++ b/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java @@ -51,6 +51,7 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler { long base = elfRelocationContext.getImageBaseWordAdjustmentOffset(); ElfSymbol sym = null; long symbolValue = 0; + Address symbolAddr = null; String symbolName = null; int symbolIndex = relocation.getSymbolIndex(); @@ -59,6 +60,7 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler { } if (null != sym) { + symbolAddr = elfRelocationContext.getSymbolAddress(sym); symbolValue = elfRelocationContext.getSymbolValue(sym); symbolName = sym.getNameAsString(); } @@ -94,6 +96,10 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler { case RISCV_ElfRelocationConstants.R_RISCV_64: // Runtime relocation word64 = S + A + if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress, + symbolAddr, symbolName, addend, elfRelocationContext.getLog())) { + addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup + } value64 = symbolValue + addend; memory.setLong(relocationAddress, value64); break; diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java index 147b410d9a..2a116cd78f 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java @@ -59,12 +59,15 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler { ElfSymbol sym = null; long symbolValue = 0; + Address symbolAddr = null; String symbolName = null; + if (symbolIndex != 0) { sym = elfRelocationContext.getSymbol(symbolIndex); } if (sym != null) { + symbolAddr = elfRelocationContext.getSymbolAddress(sym); symbolValue = elfRelocationContext.getSymbolValue(sym); symbolName = sym.getNameAsString(); } @@ -79,6 +82,10 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler { switch (type) { case X86_32_ElfRelocationConstants.R_386_32: + if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress, + symbolAddr, symbolName, addend, elfRelocationContext.getLog())) { + addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup + } value = (int) (symbolValue + addend); memory.setInt(relocationAddress, value); break; diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java index c19386d51b..04d599f32a 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java @@ -59,16 +59,17 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler { ElfSymbol sym = null; long symbolValue = 0; - long st_value = 0; + Address symbolAddr = null; String symbolName = null; long symbolSize = 0; + if (symbolIndex != 0) { sym = elfRelocationContext.getSymbol(symbolIndex); } if (sym != null) { + symbolAddr = elfRelocationContext.getSymbolAddress(sym); symbolValue = elfRelocationContext.getSymbolValue(sym); - st_value = sym.getValue(); symbolName = sym.getNameAsString(); symbolSize = sym.getSize(); } @@ -86,6 +87,10 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler { "Runtime copy not supported", elfRelocationContext.getLog()); break; case X86_64_ElfRelocationConstants.R_X86_64_64: + if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress, + symbolAddr, symbolName, addend, elfRelocationContext.getLog())) { + addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup + } value = symbolValue + addend; memory.setLong(relocationAddress, value); break;