fix(native): clarify Mach-O offset origins and reject partial ELF tables

Expose the selected Mach-O slice and its container offset, derive that identity once, and map entrypoint and nonempty segment Evidence to container coordinates. Reject relocation sections whose byte length is not divisible by the entry size instead of silently accepting a floored count.

Validation: native parser and selected-architecture boundaries, actual public CLI and stdio MCP on a compiled universal Mach-O, and a pyelftools 0.33 malformed-table probe. Full Linux pwntools bridge verification was unavailable on this host.

Refs #1973
This commit is contained in:
morluto committed 2026-10-12 06:29:19 +08:00
1 parent 0677468877
commit 8bd5ba2d23
7 files changed
+154 -57

No files matched your search

+23
View File
@@ -662,6 +662,16 @@ try {
bytes.writeBigUInt64LE(8n, header + 56);
return [`undersized-entry-${type}`, bytes, "invalid_input"];
});
const nonintegralSymbolEntries = ["SHT_SYMTAB", "SHT_DYNSYM"].map((type) => {
const section = protectedReport.sections.find((item) => item.type === type);
assert.notEqual(section, undefined);
const bytes = Buffer.from(sectionBearingBytes);
const header = Number(BigInt(section.header_location.offset));
const size = bytes.readBigUInt64LE(header + 32);
assert.ok(size + 1n <= BigInt(bytes.length) - BigInt(section.offset));
bytes.writeBigUInt64LE(size + 1n, header + 32);
return [`nonintegral-entry-count-${type}`, bytes, "invalid_input"];
});
const relocationSection = relocatable.sections.find(
(item) => item.type === "SHT_RELA",
);
@@ -677,6 +687,17 @@ try {
bytes.writeBigUInt64LE(8n, header + 56);
return [`undersized-entry-${type}`, bytes, "invalid_input"];
});
const nonintegralRelocationEntries = [
["RELA", 4, 24],
["REL", 9, 16],
].map(([type, sectionType, entrySize]) => {
const bytes = Buffer.from(object);
const header = Number(BigInt(relocationSection.header_location.offset));
bytes.writeUInt32LE(sectionType, header + 4);
bytes.writeBigUInt64LE(BigInt(entrySize + 1), header + 32);
bytes.writeBigUInt64LE(BigInt(entrySize), header + 56);
return [`nonintegral-entry-count-${type}`, bytes, "invalid_input"];
});
const invalidRelocationReferences = [
["missing-symbol-table", relocatable.sections.length + 100],
["wrong-symbol-table-kind", 1],
@@ -1066,7 +1087,9 @@ try {
],
...zeroSymbolEntries,
...undersizedSymbolEntries,
...nonintegralSymbolEntries,
...undersizedRelocationEntries,
...nonintegralRelocationEntries,
...invalidRelocationReferences,
["unterminated-dynamic-segment", shortDynamic, "invalid_input"],
["unterminated-interpreter", unterminatedInterpreter, "invalid_input"],