fix(elf): classify compressed note sections as unsupported

This commit is contained in:
morluto committed 2026-10-24 02:35:21 +08:00
1 parent 66671e8748
commit 9fb8c114a0
4 files changed
+57

No files matched your search

+6
View File
@@ -58,5 +58,11 @@ numbering (`PN_XNUM`, including a section count stored when `e_shnum` is 0) is
unsupported and returns an unsupported-target outcome rather than invalid-input
recovery.
`SHF_COMPRESSED` note sections return an unsupported-target outcome before
their compression bytes are interpreted as note records. This workflow reports
note locations as original file ranges and does not yet represent decoded note
coordinates. Inspect a separately decompressed copy when those notes are needed;
retain the original artifact for provenance.
This workflow does not execute the image or verify GNU build-id uniqueness
against package catalogs.
+29
View File
@@ -103,6 +103,35 @@ it("reads the same notes from an SHT_NOTE section including its name", () => {
).toBe(true);
});
it.each([
[32, true],
[32, false],
[64, true],
[64, false],
] as const)(
"refuses compressed ELF%i %s-endian note sections before interpreting codec bytes",
(bits, little) => {
const bytes = elfNoteFixture({ bits, little, ownership: "section" });
expect(parse(bytes).entries.length).toBeGreaterThan(0);
const shoff =
bits === 64
? Number(little ? bytes.readBigUInt64LE(40) : bytes.readBigUInt64BE(40))
: little
? bytes.readUInt32LE(32)
: bytes.readUInt32BE(32);
const flags =
shoff + (bits === 64 ? 64 : 40) + 8 + (bits === 64 && !little ? 4 : 0);
if (little) bytes.writeUInt32LE(0x800, flags);
else bytes.writeUInt32BE(0x800, flags);
expect(() => parse(bytes)).toThrow(
expect.objectContaining({
kind: "unsupported",
message: expect.stringContaining("Compressed ELF note sections"),
}),
);
},
);
it.each([
[32, true],
[64, false],
+7
View File
@@ -415,6 +415,13 @@ export const parseElfNotes = (
for (let index = 0; index < shnum; index += 1) {
const at = shoff + index * shentsize;
if (reader.u32(at + 4) !== SHT_NOTE) continue;
// Note locations are file ranges. Decoded section coordinates need a
// separate provenance contract before compressed notes can be emitted.
if ((reader.u32(at + 8 + (wide && !reader.little ? 4 : 0)) & 0x800) !== 0)
throw new BinaryFormatFailure(
"unsupported",
"Compressed ELF note sections are outside this parser's file-range coverage; inspect a separately decompressed copy.",
);
const nameOffset = reader.u32(at);
const fileOffset = reader.word(at + (wide ? 24 : 16));
const fileSize = reader.word(at + (wide ? 32 : 20));
+15
View File
@@ -32,6 +32,21 @@ const inspect = async (
};
describe("ELF note provider failures", () => {
it("projects compressed note sections as unsupported rather than malformed input", async () => {
const root = await createTestTempDirectory("rea-compressed-notes-");
const path = join(root, "compressed.o");
const bytes = elfNoteFixture({ ownership: "section" });
const section = Number(bytes.readBigUInt64LE(40)) + 64;
bytes.writeBigUInt64LE(0x800n, section + 8);
await writeFile(path, bytes);
const result = await inspect(path);
if (result.ok)
throw new Error("Expected compressed notes to be unsupported");
expect(projectAnalysisError(result.error)).toMatchObject({
code: "unsupported_target",
message: expect.stringContaining("Compressed ELF note sections"),
});
});
it("reports a note table past the end of the file as invalid input", async () => {
const root = await createTestTempDirectory("rea-elf-note-past-end-");
const path = join(root, "program");