fix(pe): classify valid DOS targets as unsupported (#7530)

fix(pe): classify confirmed DOS targets as unsupported

Signed-off-by: Rudy Celekli <rudy@gradiahq.com>
This commit is contained in:
Rudy Mizrahi Celekli authored and GitHub committed 2026-11-05 17:31:35 +08:00
1 parent 6fceda83d5
commit 21ad5b1f67
5 files changed
+115 -2

No files matched your search

+10
View File
@@ -1,3 +1,4 @@
import { BinaryFormatFailure } from "../metadata/BinaryContainer.js";
import {
projectStableArtifactFailure,
stableArtifactInputRecovery,
@@ -21,6 +22,7 @@ import {
AnalysisCancelledError,
AnalysisInputError,
AnalysisResourceConstraintError,
AnalysisUnsupportedTargetError,
} from "../../domain/analysisErrorCore.js";
import {
MAX_INSPECT_PE_CERTIFICATE_ENTRIES,
@@ -123,6 +125,14 @@ const peCertificatesFailurePrimary = (
input: InspectPeCertificatesInput,
) => {
const { cause, origin } = facts;
if (cause instanceof BinaryFormatFailure && cause.kind === "unsupported")
return new AnalysisUnsupportedTargetError(
OPERATION,
input.path,
cause.message,
{ cause },
);
if (
origin === "owned-or-classified" &&
cause instanceof ArtifactReaderFailure &&
+9 -2
View File
@@ -6,7 +6,8 @@ import {
readPeResourceEntryFacts,
readPeResourceNameFacts,
} from "./PeResourceTreeFacts.js";
import { observeMzWindowsHeader } from "../../domain/dosMz.js";
import { parseMzHeaderEvidence } from "../../domain/dosMz.js";
import { BinaryFormatFailure } from "../metadata/BinaryContainer.js";
import { readPeCoffHeader } from "../../domain/peCoffHeader.js";
import { readPeSectionHeader } from "../../domain/peSectionHeader.js";
import { ArtifactReaderFailure } from "../../artifacts/ArtifactReader.js";
@@ -91,7 +92,13 @@ const intersectsResource = (
export const readPeHeaders = (bytes: Buffer, fileSize = bytes.length) => {
requirePeRange(bytes, 0, 64);
if (bytes.readUInt16LE(0) !== 0x5a4d) peFailure("Expected an MZ PE image.");
const observed = observeMzWindowsHeader(bytes, fileSize);
const evidence = parseMzHeaderEvidence(bytes, fileSize);
const observed = evidence.windowsHeader;
if (observed.state === "absent" && evidence.dos.ok)
throw new BinaryFormatFailure(
"unsupported",
"DOS MZ images do not contain PE resource or certificate tables",
);
if (observed.state === "candidate" || observed.state === "signature-needed")
requirePeRange(bytes, observed.offset, 24);
if (observed.state !== "declared" || observed.signature !== "PE")
+10
View File
@@ -1,3 +1,4 @@
import { BinaryFormatFailure } from "../metadata/BinaryContainer.js";
import {
projectStableArtifactFailure,
stableArtifactInputRecovery,
@@ -22,6 +23,7 @@ import {
AnalysisCancelledError,
AnalysisInputError,
AnalysisResourceConstraintError,
AnalysisUnsupportedTargetError,
} from "../../domain/analysisErrorCore.js";
import {
MAX_INSPECT_PE_DIRECTORY_ENTRIES,
@@ -104,6 +106,14 @@ const peResourcesFailurePrimary = (
) => {
const { cause, origin } = facts;
const operation = "inspect_pe_resources";
if (cause instanceof BinaryFormatFailure && cause.kind === "unsupported")
return new AnalysisUnsupportedTargetError(
operation,
input.path,
cause.message,
{ cause },
);
if (
origin === "owned-or-classified" &&
cause instanceof ArtifactReaderFailure &&
@@ -0,0 +1,46 @@
import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it } from "vitest";
import { dosMz } from "../../domain/binaryTarget.fixture.js";
import { inspectPeResourcesInputSchema } from "../../domain/native/peResources.js";
import { inspectPeCertificatesInputSchema } from "../../domain/native/peCertificates.js";
import { projectAnalysisError } from "../../domain/analysisErrorProjection.js";
import { createTestTempDirectory } from "../../../tests/fixtures/temporaryDirectory.js";
import { PeResourcesProvider } from "./PeResourcesProvider.js";
import { PeCertificatesProvider } from "./PeCertificatesProvider.js";
it.each(["resources", "certificates"] as const)(
"classifies a valid DOS target as unsupported for PE %s",
async (operation) => {
const root = await createTestTempDirectory("rea-pe-dos-classification-");
const path = join(root, "program.exe");
const bytes = dosMz(1024);
await writeFile(path, bytes);
const provider =
operation === "resources"
? new PeResourcesProvider()
: new PeCertificatesProvider();
const input =
operation === "resources"
? inspectPeResourcesInputSchema.parse({ path })
: inspectPeCertificatesInputSchema.parse({ path });
try {
const result = await provider.inspect(input);
if (result.ok) throw new Error("Expected unsupported target");
expect(projectAnalysisError(result.error)).toMatchObject({
code: "unsupported_target",
category: "unsupported_target",
});
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
await writeFile(path, Buffer.from("MZ"));
const malformed = await provider.inspect(input);
if (malformed.ok) throw new Error("Expected malformed input");
expect(projectAnalysisError(malformed.error)).toMatchObject({
code: "invalid_request",
category: "invalid_input",
});
} finally {
await provider.close();
}
},
);
@@ -0,0 +1,40 @@
import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { dosMz } from "../../../src/domain/binaryTarget.fixture.js";
import { connectLocalToolsMcp } from "../../fixtures/localToolsMcp.js";
import { parseMcpToolError } from "../../fixtures/mcpToolError.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
cliTest.for(["CLI", "stdio MCP"] as const)(
"reports DOS as unsupported for PE resources and certificates through %s",
async (surface, { cli }) => {
const root = await createTestTempDirectory("rea-pe-dos-public-");
const path = join(root, "dos.exe");
const bytes = dosMz(1024);
await writeFile(path, bytes);
const mcp =
surface === "stdio MCP" ? await connectLocalToolsMcp() : undefined;
for (const operation of ["resources", "certificates"] as const) {
let error: unknown;
if (surface === "CLI") {
const response = await cli.run({
arguments: [`inspect-pe-${operation}`, path, "--json"],
});
expect(response.exitCode).toBe(1);
error = response.json;
} else {
const response = await mcp!.call(`inspect_pe_${operation}`, { path });
expect(response.isError).toBe(true);
error = parseMcpToolError(response).error;
}
expect(error).toMatchObject({
code: "unsupported_target",
category: "unsupported_target",
});
expect(JSON.stringify(error)).not.toContain("inspect_input_contract");
expect(Buffer.compare(await readFile(path), bytes)).toBe(0);
}
},
);