fix(mips): retain unexamined RELR declaration coverage
This commit is contained in:
1 parent
0a9bcbed42
commit
22d3236c31
4 files changed
+86
-2
No files matched your search
@@ -261,3 +261,9 @@ next match. Coverage can overlap between pages; do not sum it as unique memory.
|
||||
page. These blocks are never searched. Cancellation returns a typed error,
|
||||
discards the active Ghidra database, and does not return a successful partial page.
|
||||
Hopper byte search remains unavailable until its implementation is verified.
|
||||
|
||||
MIPS16 shared-image admission requires examined dynamic REL declarations.
|
||||
RELR dynamic tags or nonempty `SHT_RELR` sections leave relocation coverage
|
||||
unavailable and the profile unsupported; REA does not infer an empty relocation
|
||||
set from the absence of REL declarations. RELR loader semantics have not been
|
||||
verified for this lane.
|
||||
@@ -179,7 +179,11 @@ export const readMipsElfMetadata = async (
|
||||
gnuAttributes = parsed.value;
|
||||
continue;
|
||||
}
|
||||
if (metadata.type === 3 && table.optional && (type === 4 || type === 9))
|
||||
if (
|
||||
metadata.type === 3 &&
|
||||
table.optional &&
|
||||
(type === 4 || type === 9 || type === 19)
|
||||
)
|
||||
relocationSections.push({
|
||||
type,
|
||||
offset: u32(contents.value, position + 16),
|
||||
|
||||
@@ -103,7 +103,7 @@ export const readMipsElfSharedLoad = async (
|
||||
// Bound temporary storage, not admitted artifact size. ELF32 records are
|
||||
// exact eight-byte structures; every declared record is examined or refused.
|
||||
const chunkBytes = 64 * 1024;
|
||||
const relevant = new Set([2, 7, 8, 9, 17, 18, 19, 20, 23]);
|
||||
const relevant = new Set([2, 7, 8, 9, 17, 18, 19, 20, 23, 35, 36, 37]);
|
||||
const tags = new Map<number, number>();
|
||||
let terminated = false;
|
||||
for (
|
||||
@@ -130,6 +130,10 @@ export const readMipsElfSharedLoad = async (
|
||||
}
|
||||
}
|
||||
if (!terminated) return err("MIPS dynamic table has no DT_NULL terminator");
|
||||
if ([35, 36, 37].some((tag) => tags.has(tag)))
|
||||
return err(
|
||||
"MIPS shared RELR relocation declarations require separate verification",
|
||||
);
|
||||
if ([2, 7, 8, 9, 23].some((tag) => (tags.get(tag) ?? 0) !== 0))
|
||||
return err(
|
||||
"MIPS shared RELA or PLT relocation declarations require separate verification",
|
||||
|
||||
@@ -110,6 +110,76 @@ for (const little of [true, false]) {
|
||||
/Symbol-bearing R_MIPS_REL32/u,
|
||||
);
|
||||
});
|
||||
|
||||
it.each([false, true])(
|
||||
`leaves RELR dynamic declarations unverified with existing REL=%s (${little ? "LE" : "BE"})`,
|
||||
async (withRel) => {
|
||||
const bytes = fixture(little);
|
||||
const write = (value: number, offset: number) =>
|
||||
little
|
||||
? bytes.writeUInt32LE(value, offset)
|
||||
: bytes.writeUInt32BE(value, offset);
|
||||
const start = withRel ? 280 : 256;
|
||||
write(35, start); // DT_RELRSZ
|
||||
write(4, start + 4);
|
||||
write(36, start + 8); // DT_RELR
|
||||
write(2048, start + 12);
|
||||
write(37, start + 16); // DT_RELRENT
|
||||
write(4, start + 20);
|
||||
write(0, start + 24);
|
||||
write(64, 100);
|
||||
write(64, 104);
|
||||
const target = await resolve(bytes);
|
||||
assert.equal(target.mips.sharedLoad?.status, "unavailable");
|
||||
assert.match(ghidraMipsUnsupportedReason(target) ?? "", /RELR/u);
|
||||
},
|
||||
);
|
||||
|
||||
it(`does not ignore an isolated zero-valued RELR declaration (${little ? "LE" : "BE"})`, async () => {
|
||||
const bytes = fixture(little);
|
||||
if (little) bytes.writeUInt32LE(37, 280);
|
||||
else bytes.writeUInt32BE(37, 280);
|
||||
if (little) {
|
||||
bytes.writeUInt32LE(40, 100);
|
||||
bytes.writeUInt32LE(40, 104);
|
||||
} else {
|
||||
bytes.writeUInt32BE(40, 100);
|
||||
bytes.writeUInt32BE(40, 104);
|
||||
}
|
||||
const target = await resolve(bytes);
|
||||
assert.equal(target.mips.sharedLoad?.status, "unavailable");
|
||||
assert.match(ghidraMipsUnsupportedReason(target) ?? "", /RELR/u);
|
||||
});
|
||||
|
||||
it.each([false, true])(
|
||||
`includes SHT_RELR in source coverage with existing REL=%s (${little ? "LE" : "BE"})`,
|
||||
async (withRel) => {
|
||||
const bytes = fixture(little);
|
||||
const write = (value: number, offset: number) =>
|
||||
little
|
||||
? bytes.writeUInt32LE(value, offset)
|
||||
: bytes.writeUInt32BE(value, offset);
|
||||
if (!withRel) write(0, 256);
|
||||
write(1024, 32);
|
||||
if (little) {
|
||||
bytes.writeUInt16LE(40, 46);
|
||||
bytes.writeUInt16LE(2, 48);
|
||||
} else {
|
||||
bytes.writeUInt16BE(40, 46);
|
||||
bytes.writeUInt16BE(2, 48);
|
||||
}
|
||||
write(19, 1068); // SHT_RELR
|
||||
write(2048, 1080);
|
||||
write(4, 1084);
|
||||
write(4, 1100);
|
||||
const target = await resolve(bytes);
|
||||
assert.equal(target.mips.sharedLoad?.status, "unavailable");
|
||||
assert.match(
|
||||
ghidraMipsUnsupportedReason(target) ?? "",
|
||||
/section relocation declarations/u,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
it("examines relocation records beyond a read chunk before deciding completeness", async () => {
|
||||
|
||||
Reference in new issue
Block a user