fix(firmware): admit caller-selected source directly

This commit is contained in:
morluto committed 2026-10-27 09:55:01 +08:00
1 parent a905a71e31
commit c1e0f531e6
2 files changed
+124 -9

No files matched your search

+3 -9
View File
@@ -1,7 +1,7 @@
import { safeParseUtf8Json } from "../domain/safeJson.js";
import { createHash } from "node:crypto";
import { createWriteStream } from "node:fs";
import { chmod, lstat, opendir, readlink, realpath } from "node:fs/promises";
import { chmod, lstat, opendir, readlink } from "node:fs/promises";
import { isAbsolute, join, relative, sep } from "node:path";
import { Readable, Transform } from "node:stream";
import { pipeline } from "node:stream/promises";
@@ -113,17 +113,10 @@ export class FirmwareFileAccess {
async #snapshot(request: FirmwareRequest, root: string, signal: AbortSignal) {
const sourcePath = absoluteCallerPath(request.input.path);
const source = await realpath(sourcePath).catch((cause: unknown) => {
throw firmwareSourceAdmissionFailure(
request.operation,
sourcePath,
cause,
);
});
let sourceAdmitted = false;
const fullPath = join(root, "firmware.bin");
const copied = await withArtifactRegularFile(
source,
sourcePath,
this.#resources,
signal,
async ({ handle, initial: stat }) => {
@@ -150,6 +143,7 @@ export class FirmwareFileAccess {
);
return { size, sha256: hash.digest("hex") };
},
"follow",
).catch((cause: unknown) => {
// Destination writes and reads after admission retain their own failure.
throw sourceAdmitted
@@ -0,0 +1,121 @@
import { createHash } from "node:crypto";
import {
mkdir,
mkdtemp,
readFile,
rm,
symlink,
writeFile,
} from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, expect, it } from "vitest";
import { firmwareRequestSchema } from "../domain/firmware/firmwareAnalysis.js";
import { FirmwareFileAccess } from "./FirmwareFiles.js";
const roots: string[] = [];
afterEach(async () => {
await Promise.all(
roots.splice(0).map((root) => rm(root, { recursive: true, force: true })),
);
});
const workspace = async () => {
const root = await mkdtemp(join(tmpdir(), "rea-firmware-source-"));
roots.push(root);
const staging = join(root, "stage");
await mkdir(staging);
return { root, staging };
};
it("honors cancellation before source admission without creating a snapshot", async () => {
const { root, staging } = await workspace();
const path = join(root, "firmware");
await writeFile(path, "firmware");
const request = firmwareRequestSchema.parse({
operation: "inspect_firmware_regions",
input: { path },
});
const cancellation = new AbortController();
cancellation.abort(new Error("cancel source admission"));
const files = new FirmwareFileAccess();
try {
await expect(
files.snapshot(request, staging, cancellation.signal),
).rejects.toMatchObject({ reason: "cancelled" });
await expect(readFile(join(staging, "firmware.bin"))).rejects.toMatchObject(
{ code: "ENOENT" },
);
} finally {
await files.close();
}
});
it.skipIf(process.platform === "win32")(
"rejects file/.. traversal before creating a firmware snapshot",
async () => {
const { root, staging } = await workspace();
await writeFile(join(root, "blocker"), "regular file");
await writeFile(join(root, "firmware"), "decoy firmware");
const path = `${root}/blocker/../firmware`;
await expect(readFile(path)).rejects.toMatchObject({ code: "ENOTDIR" });
const request = firmwareRequestSchema.parse({
operation: "inspect_firmware_regions",
input: { path },
});
const files = new FirmwareFileAccess();
try {
await expect(
files.snapshot(request, staging, new AbortController().signal),
).rejects.toMatchObject({ _tag: "AnalysisInputError" });
await expect(
readFile(join(staging, "firmware.bin")),
).rejects.toMatchObject({ code: "ENOENT" });
} finally {
await files.close();
}
},
);
// POSIX parent traversal and symlink creation require host filesystem support;
// Windows does not guarantee either traversal semantics or symlink privileges.
it.skipIf(process.platform === "win32").each(["parent", "final"] as const)(
"snapshots the filesystem-selected %s symlink target and preserves its selected path",
async (kind) => {
const { root, staging } = await workspace();
await mkdir(join(root, "physical", "child"), { recursive: true });
const bytes = Buffer.from("selected firmware bytes");
await writeFile(join(root, "physical", "firmware"), bytes);
await writeFile(join(root, "firmware"), "lexical decoy");
await symlink(join(root, "physical", "child"), join(root, "link"), "dir");
await symlink(
join(root, "physical", "firmware"),
join(root, "alias"),
"file",
);
const path =
kind === "parent" ? `${root}/link/../firmware` : join(root, "alias");
const request = firmwareRequestSchema.parse({
operation: "inspect_firmware_regions",
input: { path },
});
const files = new FirmwareFileAccess();
try {
const snapshot = await files.snapshot(
request,
staging,
new AbortController().signal,
);
const sha256 = createHash("sha256").update(bytes).digest("hex");
expect(snapshot.subject).toEqual({ path, sha256, format: "file" });
expect(snapshot.selection).toEqual({
offset: 0,
length: bytes.length,
sha256,
});
expect((await readFile(snapshot.inputPath)).equals(bytes)).toBe(true);
} finally {
await files.close();
}
},
);