GP-2730 corrected ELF read-only memory update issue

This commit is contained in:
ghidra1 2023-01-23 11:48:52 -05:00
parent b1cf7d1b61
commit df184ab91c

View File

@ -34,6 +34,7 @@ import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter;
import ghidra.app.util.bin.format.elf.relocation.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.framework.store.LockException;
import ghidra.program.database.mem.FileBytes;
import ghidra.program.database.register.AddressRangeObjectMap;
import ghidra.program.model.address.*;
@ -572,41 +573,94 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
monitor.setMessage("Processing read-only memory changes");
setReadOnlyMemory(elf.getSection(".data.rel.ro"), null);
for (ElfProgramHeader roSegment : elf
for (ElfProgramHeader relRoHeader : elf
.getProgramHeaders(ElfProgramHeaderConstants.PT_GNU_RELRO)) {
// TODO: (GP-2730) Identify read-only region which should be transformed
setReadOnlyMemory(elf.getProgramLoadHeaderContaining(roSegment.getVirtualAddress()),
null);
long size = relRoHeader.getMemorySize();
if (size <= 0) {
log("PT_GNU_RELRO has unsupported memory size: " + size);
continue;
}
Address startAddr = getSegmentLoadAddress(relRoHeader);
if (!startAddr.isLoadedMemoryAddress()) {
log("Failed to identify PT_GNU_RELRO memory at address offset " +
Long.toHexString(relRoHeader.getVirtualAddress()));
continue;
}
Address endAddr = startAddr.add(relRoHeader.getAdjustedMemorySize() - 1);
setReadOnlyMemory(new AddressRangeImpl(startAddr, endAddr));
}
}
/**
* Transition load segment to read-only
* @param loadedSegment loaded segment
* @param region constrained read-only region or null for entire load segment
*/
private void setReadOnlyMemory(MemoryLoadable loadedSegment, AddressRange region) {
private void setReadOnlyMemory(MemoryLoadable loadedSegment) {
if (loadedSegment == null) {
return;
}
List<AddressRange> resolvedLoadAddresses = getResolvedLoadAddresses(loadedSegment);
if (resolvedLoadAddresses == null) {
// TODO: (GP-2730) PT_LOAD may have been discarded in favor of named section - need to apply
// read-only to address range affected by region
log("Set read-only failed for: " + loadedSegment + " (please report this issue)");
return;
}
for (AddressRange blockRange : resolvedLoadAddresses) {
MemoryBlock block = memory.getBlock(blockRange.getMinAddress());
if (block != null) {
// TODO: (GP-2730) If sections have been stripped the block should be split-up
// based upon the size of the RO region indicated by the roSegment data
log("Setting block " + block.getName() +
" to read-only based upon PT_GNU_RELRO data");
block.setWrite(false);
for (AddressRange range : resolvedLoadAddresses) {
setReadOnlyMemory(range);
}
}
/**
* Transition memory range to read-only
* @param range constrained read-only region or null for entire load segment
*/
private void setReadOnlyMemory(AddressRange range) {
AddressSet set = new AddressSet(range);
set = set.intersect(memory.getLoadedAndInitializedAddressSet());
if (set.isEmpty()) {
log("Ignored attempt to set non-loaded memory as read-only: " + range);
return;
}
try {
while (!set.isEmpty()) {
AddressRange subrange = set.getFirstRange();
Address startAddr = set.getMinAddress();
MemoryBlock block = memory.getBlock(startAddr);
block = setReadOnlyBlockRange(block, subrange);
set.delete(startAddr, block.getEnd());
}
}
catch (MemoryBlockException | LockException | NotFoundException e) {
throw new AssertException(e); // unexpected
}
}
private MemoryBlock setReadOnlyBlockRange(MemoryBlock block, AddressRange range)
throws MemoryBlockException, LockException, NotFoundException {
if (!block.isWrite()) {
return block;
}
Address startAddr = block.getStart();
boolean split = false;
if (!startAddr.equals(block.getStart())) {
memory.split(block, startAddr);
block = memory.getBlock(startAddr);
split = true;
}
if (!range.contains(block.getEnd())) {
memory.split(block, range.getMaxAddress().next());
block = memory.getBlock(startAddr);
split = true;
}
String msg = "";
if (split) {
msg = " (block split was required)";
}
log("Setting block " + block.getName() + " to read-only" + msg);
block.setWrite(false);
return block;
}
private void processEntryPoints(TaskMonitor monitor) throws CancelledException {