fix(artifacts): reject contradictory checksum representations
This commit is contained in:
1 parent
3664a4a57e
commit
d9a39e5b48
3 files changed
+78
No files matched your search
@@ -335,6 +335,7 @@ export class CpioArtifactReader implements ArtifactReader {
|
||||
"format",
|
||||
"cpio trailer declares member data",
|
||||
);
|
||||
await drain(this.#verified(source, header, raw));
|
||||
await source.finish();
|
||||
yield* this.#unresolvedLinks();
|
||||
return;
|
||||
|
||||
@@ -3,6 +3,7 @@ import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { buffer } from "node:stream/consumers";
|
||||
import { Readable } from "node:stream";
|
||||
import { gunzipSync, gzipSync } from "node:zlib";
|
||||
import { expect, it } from "vitest";
|
||||
import { ArtifactDecodedBudget } from "./ArtifactDecodedBudget.js";
|
||||
import { CpioArtifactReader } from "./CpioArtifactReader.js";
|
||||
@@ -233,3 +234,64 @@ it("does not expose a partial inventory when a previous TOC load failed", async
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects a TOC checksum when the fixed header declares none", async () => {
|
||||
const bytes = Buffer.from(
|
||||
xarArchive([{ name: "a", data: Buffer.from("ok") }]),
|
||||
);
|
||||
bytes.writeUInt32BE(0, 24);
|
||||
await withReader(bytes, async (reader) => {
|
||||
await expect(
|
||||
(async () => {
|
||||
for await (const entry of reader.entries()) void entry;
|
||||
})(),
|
||||
).rejects.toMatchObject({
|
||||
reason: "format",
|
||||
message: expect.stringContaining("declares no TOC checksum"),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it.each(["", "nothex", "a".repeat(63)])(
|
||||
"rejects malformed checksum text %j before applying integrity policy",
|
||||
async (digest) => {
|
||||
const bytes = rewriteXarToc(
|
||||
xarArchive([{ name: "a", data: Buffer.from("ok") }]),
|
||||
(xml) =>
|
||||
xml.replace(
|
||||
/<extracted-checksum style="sha1">[^<]*<\/extracted-checksum>/u,
|
||||
`<extracted-checksum style="sha256">${digest}</extracted-checksum>`,
|
||||
),
|
||||
);
|
||||
await withReader(bytes, async (reader) => {
|
||||
await expect(
|
||||
(async () => {
|
||||
for await (const entry of reader.entries()) void entry;
|
||||
})(),
|
||||
).rejects.toMatchObject({
|
||||
reason: "format",
|
||||
message: "xar extracted-checksum has malformed sha256 digest text",
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it("rejects a CRC trailer whose declared checksum is not empty-data zero", async () => {
|
||||
const raw = gunzipSync(gzipCpio([], "crc"));
|
||||
raw.write("00000001", 102, "ascii");
|
||||
const reader = new CpioArtifactReader(async () =>
|
||||
Readable.from([gzipSync(raw)]),
|
||||
);
|
||||
try {
|
||||
await expect(
|
||||
(async () => {
|
||||
for await (const entry of reader.entries()) void entry;
|
||||
})(),
|
||||
).rejects.toMatchObject({
|
||||
reason: "integrity",
|
||||
message: "cpio CRC disagrees with content: TRAILER!!!",
|
||||
});
|
||||
} finally {
|
||||
await reader.close();
|
||||
}
|
||||
});
|
||||
@@ -101,6 +101,16 @@ const parseChecksum = (
|
||||
const value = (element.textContent ?? "").trim().toLowerCase();
|
||||
if (CHECKSUM_ALGORITHMS.get(style) === undefined)
|
||||
return { unsupported: style || "(missing style)", value };
|
||||
const expected = DIGEST_BYTES.get(style);
|
||||
if (
|
||||
expected === undefined ||
|
||||
value.length !== expected * 2 ||
|
||||
!/^[0-9a-f]+$/u.test(value)
|
||||
)
|
||||
throw new ArtifactReaderFailure(
|
||||
"format",
|
||||
`xar ${tag} has malformed ${style} digest text`,
|
||||
);
|
||||
return { algorithm: style, value };
|
||||
};
|
||||
|
||||
@@ -529,6 +539,11 @@ export class XarArtifactReader implements ArtifactReader {
|
||||
`xar header declares unsupported TOC checksum algorithm ${headerAlg}`,
|
||||
);
|
||||
const checksum = childElement(toc, "checksum");
|
||||
if (expectedStyle === null && checksum !== undefined)
|
||||
throw new ArtifactReaderFailure(
|
||||
"format",
|
||||
"xar header declares no TOC checksum but the TOC supplies one",
|
||||
);
|
||||
if (checksum === undefined) {
|
||||
if (headerAlg !== 0)
|
||||
throw new ArtifactReaderFailure(
|
||||
|
||||
Reference in new issue
Block a user