fix(elf): classify compressed note sections as unsupported
This commit is contained in:
1 parent
66671e8748
commit
9fb8c114a0
4 files changed
+57
No files matched your search
@@ -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.
|
||||
@@ -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],
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in new issue
Block a user