mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
refactor(firmware): centralize audited tool requirements
This commit is contained in:
1 parent
572d0c2340
commit
99be47a9a3
6 files changed
+67
-68
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import { DEFAULT_CALL_RELATIONSHIP_DIRECTION } from "../contracts/enhancedInputs.js";
|
||||
import { FIRMWARE_TOOL_REQUIREMENTS } from "../contracts/firmware/firmwareToolRequirements.js";
|
||||
import { CALL_RELATIONSHIP_TRAVERSALS } from "./CallRelationshipTraversal.js";
|
||||
import { NATIVE_DISPATCH_METADATA_SOURCES } from "./native/NativeDispatchMetadataInspection.js";
|
||||
import { NATIVE_UI_ACTION_OPERATIONS } from "./native/NativeUiActionTrace.js";
|
||||
@@ -541,6 +542,7 @@ const workflowAvailabilityFor = ({
|
||||
"On Linux x64, set absolute REA_PWNTOOLS_PYTHON to caller-supplied Python with pwntools 4.15.0. No active binary target is required.",
|
||||
);
|
||||
if (kind === "firmware-provider") {
|
||||
const { binwalk, unblob } = FIRMWARE_TOOL_REQUIREMENTS;
|
||||
const inspection = name === "inspect_firmware_regions";
|
||||
return hostRestrictedAvailability(
|
||||
policy,
|
||||
@@ -548,7 +550,7 @@ const workflowAvailabilityFor = ({
|
||||
inspection
|
||||
? policy.firmwareInspectionEnabled
|
||||
: policy.firmwareExtractionEnabled,
|
||||
"On Linux, provide an absolute REA_BINWALK_COMMAND (Binwalk 3.1.x, verified with 3.1.0) or REA_UNBLOB_COMMAND (Unblob 26.6.x, verified with 26.6.4) path and util-linux prlimit. Extraction also requires the selected format’s external extractor.",
|
||||
`On Linux, provide an absolute ${binwalk.commandEnvironment} (${binwalk.name} ${binwalk.line}, verified with ${binwalk.version}) or ${unblob.commandEnvironment} (${unblob.name} ${unblob.line}, verified with ${unblob.version}) path and util-linux prlimit. Extraction also requires the selected format’s external extractor.`,
|
||||
);
|
||||
}
|
||||
if (kind === "android-provider")
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
import type { ToolContract } from "../toolContractTypes.js";
|
||||
import { evidenceResultOf } from "../toolOutputSchemaPrimitives.js";
|
||||
import { toolContractMetadata } from "../toolEffects.js";
|
||||
import { FIRMWARE_TOOL_REQUIREMENTS } from "./firmwareToolRequirements.js";
|
||||
|
||||
/** Explicit local firmware observations and extraction, backed by caller-supplied tools. */
|
||||
export const FIRMWARE_TOOL_CONTRACTS = [
|
||||
@@ -12,8 +13,7 @@ export const FIRMWARE_TOOL_CONTRACTS = [
|
||||
name: "inspect_firmware_regions",
|
||||
...toolContractMetadata("inspect_firmware_regions"),
|
||||
kind: "firmware-provider",
|
||||
description:
|
||||
"Inspect signature candidates in a local firmware file with Binwalk 3.1.x (verified with 3.1.0). Returns offsets, reported lengths, descriptions and raw confidence values. Length validation and runtime addresses remain unknown. No extraction or target execution. Linux, caller-supplied tool and util-linux prlimit required; 128 MiB input limit, one worker. Adjust analysis_timeout_ms for the analysis wall-clock budget (default 120000); fixed per-process limits are unchanged.",
|
||||
description: `Inspect signature candidates in a local firmware file with ${FIRMWARE_TOOL_REQUIREMENTS.binwalk.requirement}. Returns offsets, reported lengths, descriptions and raw confidence values. Length validation and runtime addresses remain unknown. No extraction or target execution. Linux, caller-supplied tool and util-linux prlimit required; 128 MiB input limit, one worker. Adjust analysis_timeout_ms for the analysis wall-clock budget (default 120000); fixed per-process limits are unchanged.`,
|
||||
inputSchema: firmwareInputSchemas.inspect_firmware_regions,
|
||||
outputSchema: evidenceResultOf(
|
||||
firmwareResultSchemas.inspect_firmware_regions,
|
||||
@@ -29,8 +29,7 @@ export const FIRMWARE_TOOL_CONTRACTS = [
|
||||
name: "extract_firmware",
|
||||
...toolContractMetadata("extract_firmware"),
|
||||
kind: "firmware-provider",
|
||||
description:
|
||||
"Extract caller-selected firmware bytes with Unblob 26.6.x (verified with 26.6.4) into an absent output directory. Returns verified child paths/digests, task derivations, unknown chunks, extraction diagnostics and explicit extraction_gaps rows naming unextracted regions, missing extractor dependencies and a continuation_id referencing shared extraction_continuations recovery instructions. Preserves the default sandbox; publishes regular files only. Linux, caller-supplied tool, format-specific extractors and util-linux prlimit required. No mounts or extracted-code execution. Select a returned native file with open_binary for Ghidra analysis; decompressed offsets are not original-file addresses.",
|
||||
description: `Extract caller-selected firmware bytes with ${FIRMWARE_TOOL_REQUIREMENTS.unblob.requirement} into an absent output directory. Returns verified child paths/digests, task derivations, unknown chunks, extraction diagnostics and explicit extraction_gaps rows naming unextracted regions, missing extractor dependencies and a continuation_id referencing shared extraction_continuations recovery instructions. Preserves the default sandbox; publishes regular files only. Linux, caller-supplied tool, format-specific extractors and util-linux prlimit required. No mounts or extracted-code execution. Select a returned native file with open_binary for Ghidra analysis; decompressed offsets are not original-file addresses.`,
|
||||
inputSchema: firmwareInputSchemas.extract_firmware,
|
||||
outputSchema: evidenceResultOf(firmwareResultSchemas.extract_firmware),
|
||||
examples: [
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/** Derive public support facts from one audited, stable release number. */
|
||||
const defineToolRequirement = (release: {
|
||||
readonly name: string;
|
||||
readonly commandEnvironment: string;
|
||||
readonly version: readonly [number, number, number];
|
||||
readonly revision: string;
|
||||
readonly repository: string;
|
||||
}) => {
|
||||
const [major, minor, patch] = release.version;
|
||||
const version = `${major}.${minor}.${patch}`;
|
||||
const line = `${major}.${minor}.x`;
|
||||
return {
|
||||
...release,
|
||||
version,
|
||||
major,
|
||||
minor,
|
||||
line,
|
||||
requirement: `${release.name} ${line} (verified with ${version})`,
|
||||
} as const;
|
||||
};
|
||||
|
||||
/** Audited report compatibility; installed tool identity is observed separately. */
|
||||
export const FIRMWARE_TOOL_REQUIREMENTS = {
|
||||
binwalk: defineToolRequirement({
|
||||
name: "Binwalk",
|
||||
commandEnvironment: "REA_BINWALK_COMMAND",
|
||||
version: [3, 1, 0],
|
||||
revision: "4fdab3d464d97b68e0af9088df3f9e2e1545b21c",
|
||||
repository: "https://github.com/ReFirmLabs/binwalk",
|
||||
}),
|
||||
unblob: defineToolRequirement({
|
||||
name: "Unblob",
|
||||
commandEnvironment: "REA_UNBLOB_COMMAND",
|
||||
version: [26, 6, 4],
|
||||
revision: "1fcc7a0a584a70a96c31f5a276c20944d199a089",
|
||||
repository: "https://github.com/onekey-sec/unblob",
|
||||
}),
|
||||
} as const;
|
||||
|
||||
/** Caller-supplied firmware engine selected by the operation. */
|
||||
export type FirmwareEngineName = keyof typeof FIRMWARE_TOOL_REQUIREMENTS;
|
||||
@@ -1,4 +1,8 @@
|
||||
import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
|
||||
import {
|
||||
FIRMWARE_TOOL_REQUIREMENTS,
|
||||
type FirmwareEngineName,
|
||||
} from "../contracts/firmware/firmwareToolRequirements.js";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { access, realpath, stat } from "node:fs/promises";
|
||||
import { constants } from "node:fs";
|
||||
@@ -73,13 +77,12 @@ export const firmwareHostSupported = (platform: NodeJS.Platform): boolean =>
|
||||
/** Resolve explicitly supplied executable paths; never install or search for engines. */
|
||||
export const resolveFirmwareCommand = async (
|
||||
environment: Readonly<Record<string, string | undefined>>,
|
||||
engine: "binwalk" | "unblob",
|
||||
engine: FirmwareEngineName,
|
||||
operation: string,
|
||||
files: FirmwareFileAccess,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
const variable =
|
||||
engine === "binwalk" ? "REA_BINWALK_COMMAND" : "REA_UNBLOB_COMMAND";
|
||||
const variable = FIRMWARE_TOOL_REQUIREMENTS[engine].commandEnvironment;
|
||||
const configured = environment[variable];
|
||||
if (
|
||||
!firmwareHostSupported(process.platform) ||
|
||||
|
||||
@@ -1,30 +1,17 @@
|
||||
import { BOUNDED_PRODUCER_LIMITS } from "../process/LinuxResourceLimits.js";
|
||||
|
||||
/** Audited upstream sources; installed tool bytes are fingerprinted separately. */
|
||||
export const FIRMWARE_RELEASES = {
|
||||
binwalk: {
|
||||
version: "3.1.0",
|
||||
revision: "4fdab3d464d97b68e0af9088df3f9e2e1545b21c",
|
||||
repository: "https://github.com/ReFirmLabs/binwalk",
|
||||
},
|
||||
unblob: {
|
||||
version: "26.6.4",
|
||||
revision: "1fcc7a0a584a70a96c31f5a276c20944d199a089",
|
||||
repository: "https://github.com/onekey-sec/unblob",
|
||||
},
|
||||
} as const;
|
||||
import { FIRMWARE_TOOL_REQUIREMENTS } from "../contracts/firmware/firmwareToolRequirements.js";
|
||||
|
||||
/** Catalog identity for the verified Binwalk release. Evidence replaces version with the observed banner. */
|
||||
export const BINWALK_PROVIDER_IDENTITY = {
|
||||
id: "binwalk",
|
||||
name: "Binwalk",
|
||||
version: FIRMWARE_RELEASES.binwalk.version,
|
||||
name: FIRMWARE_TOOL_REQUIREMENTS.binwalk.name,
|
||||
version: FIRMWARE_TOOL_REQUIREMENTS.binwalk.version,
|
||||
} as const;
|
||||
/** Catalog identity for explicit firmware extraction. */
|
||||
export const UNBLOB_PROVIDER_IDENTITY = {
|
||||
id: "unblob",
|
||||
name: "Unblob",
|
||||
version: FIRMWARE_RELEASES.unblob.version,
|
||||
name: FIRMWARE_TOOL_REQUIREMENTS.unblob.name,
|
||||
version: FIRMWARE_TOOL_REQUIREMENTS.unblob.version,
|
||||
} as const;
|
||||
|
||||
/** Resource policy for this Linux integration, not a claim of aggregate containment. */
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { FIRMWARE_RELEASES } from "./FirmwareRelease.js";
|
||||
|
||||
/** Caller-supplied firmware engine selected by the operation. */
|
||||
export type FirmwareEngineName = keyof typeof FIRMWARE_RELEASES;
|
||||
import {
|
||||
FIRMWARE_TOOL_REQUIREMENTS,
|
||||
type FirmwareEngineName,
|
||||
} from "../contracts/firmware/firmwareToolRequirements.js";
|
||||
|
||||
interface ReleaseNumber {
|
||||
readonly major: number;
|
||||
readonly minor: number;
|
||||
readonly patch: number;
|
||||
readonly suffix: string;
|
||||
readonly token: string;
|
||||
}
|
||||
|
||||
@@ -21,37 +19,7 @@ const parseToken = (token: string): ReleaseNumber | undefined => {
|
||||
const patch = Number(match[3]);
|
||||
if (![major, minor, patch].every((part) => Number.isSafeInteger(part)))
|
||||
return undefined;
|
||||
const suffix = match[4] ?? "";
|
||||
return { major, minor, patch, suffix, token };
|
||||
};
|
||||
|
||||
const verifiedRelease = (engine: FirmwareEngineName): ReleaseNumber => {
|
||||
const parsed = parseToken(FIRMWARE_RELEASES[engine].version);
|
||||
if (parsed === undefined || parsed.suffix !== "")
|
||||
throw new Error(
|
||||
`FIRMWARE_RELEASES.${engine}.version is not a release number`,
|
||||
);
|
||||
return parsed;
|
||||
};
|
||||
|
||||
/** Caller-facing engine name. */
|
||||
export const firmwareEngineLabel = (engine: FirmwareEngineName): string => {
|
||||
switch (engine) {
|
||||
case "binwalk":
|
||||
return "Binwalk";
|
||||
case "unblob":
|
||||
return "Unblob";
|
||||
default: {
|
||||
const unreachable: never = engine;
|
||||
return unreachable;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** Release line accepted for one engine, such as `Binwalk 3.1.x`. */
|
||||
export const firmwareReleaseLine = (engine: FirmwareEngineName): string => {
|
||||
const verified = verifiedRelease(engine);
|
||||
return `${firmwareEngineLabel(engine)} ${String(verified.major)}.${String(verified.minor)}.x`;
|
||||
return { major, minor, token };
|
||||
};
|
||||
|
||||
/** Admission of one observed `--version` banner. */
|
||||
@@ -75,8 +43,8 @@ export const admitFirmwareVersion = (
|
||||
): FirmwareVersionAdmission => {
|
||||
const token = versionToken(engine, banner);
|
||||
const parsed = token === undefined ? undefined : parseToken(token);
|
||||
const verified = verifiedRelease(engine);
|
||||
const accepted = `accepted releases are ${firmwareReleaseLine(engine)} (verified with ${verified.token})`;
|
||||
const verified = FIRMWARE_TOOL_REQUIREMENTS[engine];
|
||||
const accepted = `accepted releases are ${verified.requirement}`;
|
||||
if (parsed === undefined)
|
||||
return {
|
||||
status: "unresolved",
|
||||
@@ -87,13 +55,12 @@ export const admitFirmwareVersion = (
|
||||
status: "unsupported",
|
||||
message: `Unsupported tool version ${banner}; ${accepted}.`,
|
||||
};
|
||||
if (parsed.token === verified.token)
|
||||
if (parsed.token === verified.version)
|
||||
return { status: "verified", version: parsed.token };
|
||||
const line = `${String(verified.major)}.${String(verified.minor)}.x`;
|
||||
return {
|
||||
status: "compatible",
|
||||
version: parsed.token,
|
||||
limitation: `This session uses ${firmwareEngineLabel(engine)} ${parsed.token}. The report parser is verified against ${verified.token}; other ${line} builds are accepted and the observed version is reported.`,
|
||||
limitation: `This session uses ${verified.name} ${parsed.token}. The report parser is verified against ${verified.version}; other ${verified.line} builds are accepted and the observed version is reported.`,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user