mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-28 23:21:46 +00:00
GP-2730 corrected ELF read-only memory update issue
This commit is contained in:
parent
b1cf7d1b61
commit
df184ab91c
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user