fix(firmware): validate configured executables (#751)

This commit is contained in:
Kaoru0822 2026-10-06 10:03:55 -07:00 committed by GitHub
parent fb679b63c2
commit 9a4e6da5a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 101 additions and 6 deletions

View File

@ -0,0 +1,79 @@
import { chmod, mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it as test } from "vitest";
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
import { resolveFirmwareCommand } from "./FirmwareCommand.js";
const it = test.skipIf(process.platform !== "linux");
it("rejects a directory configured as the firmware engine executable", async () => {
const root = await createTestTempDirectory("rea-firmware-command-");
const command = join(root, "binwalk");
const limiter = await executableFixture(root, "prlimit");
await mkdir(command);
await expect(
resolveFirmwareCommand(
{
REA_BINWALK_COMMAND: command,
REA_FIRMWARE_PRLIMIT_COMMAND: limiter,
},
"binwalk",
"inspect_firmware_regions",
),
).rejects.toMatchObject({
_tag: "AnalysisCapabilityUnavailableError",
reason: expect.stringContaining(command),
});
});
it("classifies an unusable firmware engine as an unavailable capability", async () => {
const root = await createTestTempDirectory("rea-firmware-command-");
const command = join(root, "binwalk");
const limiter = await executableFixture(root, "prlimit");
await writeFile(command, "not executable", { mode: 0o600 });
await expect(
resolveFirmwareCommand(
{
REA_BINWALK_COMMAND: command,
REA_FIRMWARE_PRLIMIT_COMMAND: limiter,
},
"binwalk",
"inspect_firmware_regions",
),
).rejects.toMatchObject({
_tag: "AnalysisCapabilityUnavailableError",
reason: expect.stringContaining(command),
});
});
it("rejects a directory configured as the resource limiter executable", async () => {
const root = await createTestTempDirectory("rea-firmware-limiter-");
const command = await executableFixture(root, "binwalk");
const limiter = join(root, "prlimit");
await mkdir(limiter);
await expect(
resolveFirmwareCommand(
{
REA_BINWALK_COMMAND: command,
REA_FIRMWARE_PRLIMIT_COMMAND: limiter,
},
"binwalk",
"inspect_firmware_regions",
),
).rejects.toMatchObject({
_tag: "AnalysisCapabilityUnavailableError",
reason: expect.stringContaining(limiter),
});
});
const executableFixture = async (root: string, name: string) => {
const path = join(root, name);
await writeFile(path, "#!/bin/sh\n");
await chmod(path, 0o700);
return path;
};

View File

@ -1,5 +1,5 @@
import { randomUUID } from "node:crypto";
import { access, realpath } from "node:fs/promises";
import { access, realpath, stat } from "node:fs/promises";
import { constants } from "node:fs";
import { isAbsolute } from "node:path";
import {
@ -55,7 +55,19 @@ export const resolveFirmwareCommand = async (
`${variable} is unavailable: ${cause instanceof Error ? cause.message : String(cause)}`,
);
});
await access(command, constants.X_OK);
let sha256: string;
try {
await access(command, constants.R_OK | constants.X_OK);
if (!(await stat(command)).isFile())
throw new TypeError("Configured path is not a regular file");
sha256 = await hashFirmwareFile(command);
} catch (cause: unknown) {
throw new AnalysisCapabilityUnavailableError(
engine,
operation,
`${variable} is not a readable executable regular file: ${command}: ${cause instanceof Error ? cause.message : String(cause)}`,
);
}
const limiter =
environment.REA_FIRMWARE_PRLIMIT_COMMAND ?? "/usr/bin/prlimit";
if (!isAbsolute(limiter))
@ -64,14 +76,18 @@ export const resolveFirmwareCommand = async (
operation,
"REA_FIRMWARE_PRLIMIT_COMMAND must be absolute",
);
await access(limiter, constants.X_OK).catch(() => {
try {
await access(limiter, constants.X_OK);
if (!(await stat(limiter)).isFile())
throw new TypeError("Configured path is not a regular file");
} catch (cause: unknown) {
throw new AnalysisCapabilityUnavailableError(
engine,
operation,
`Resource limiter unavailable: ${limiter}; provide util-linux prlimit`,
`Resource limiter is not an executable regular file: ${limiter}: ${cause instanceof Error ? cause.message : String(cause)}; provide util-linux prlimit`,
);
});
return { command, limiter, sha256: await hashFirmwareFile(command) };
}
return { command, limiter, sha256 };
};
/** Execute one bounded provider command and verify its owned descendants have stopped. */