fix(managed): report malformed PE layouts as invalid input (#2194)

* fix(managed): report malformed PE layouts as invalid input

readManagedPeLayout raises ManagedReaderFailure for DOS, COFF and section
header failures such as section data past EOF. Those escaped the managed
inspectors, so ManagedStaticProvider wrapped them as ProviderAdapterError
and the CLI and MCP reported execution_failure with advice to run rea
doctor. Map format failures to an invalid_format input issue carrying the
reader's detail, as inspect-pe-resources and inspect-go-binary do.

Fixes #2191

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): route unmappable PE layouts through one input error

inspect-managed-native-boundaries caught a layout-level ManagedReaderFailure
itself and returned an empty malformed inspection with exit 0, while the
other managed operations now report the same bytes as invalid input. Let
the layout failure reach the provider's invalid_format mapping; metadata
failures after a readable layout still return malformed coverage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kaoru0822andClaude Opus 5.5 authored and GitHub committed 2026-10-12 06:53:26 -07:00
1 parent df2c08b546
commit 90e37f4152
3 files changed
+51 -9

No files matched your search

+2 -9
View File
@@ -121,15 +121,8 @@ export const inspectManagedNativeBoundariesBytes = (
bytes: Buffer,
target: BinaryTarget,
): ManagedNativeBoundaryInspection => {
let pe: ManagedPeLayout;
try {
pe = readManagedPeLayout(bytes);
} catch (cause: unknown) {
if (!(cause instanceof ManagedReaderFailure)) throw cause;
return emptyInspection(target, bytes, "malformed", {
issues: [cause.issue],
});
}
// An unmappable PE layout is invalid input for every managed operation.
const pe = readManagedPeLayout(bytes);
if (pe.cli === null)
return emptyInspection(
target,
+16
View File
@@ -22,6 +22,7 @@ import type { BinaryTarget } from "../domain/binaryTargetTypes.js";
import {
AnalysisCancelledError,
AnalysisCapabilityUnavailableError,
AnalysisInputError,
} from "../domain/analysisErrorCore.js";
import { EvidenceIntegrityError } from "../domain/evidenceErrors.js";
import { ProviderAdapterError } from "../domain/providerAdapterError.js";
@@ -38,6 +39,7 @@ import { inspectManagedArtifactBytes } from "./ManagedArtifactInspector.js";
import { inspectManagedMembersBytes } from "./ManagedMemberInspector.js";
import { inspectManagedNativeBoundariesBytes } from "./ManagedNativeBoundaryInspector.js";
import { RegularFileCleanupFailure } from "../application/RegularFileRead.js";
import { ManagedReaderFailure } from "./ManagedReaderFailure.js";
import {
hashManagedSource,
managedCleanupError,
@@ -135,6 +137,20 @@ class ManagedStaticClient implements AnalysisClient {
if (cause instanceof AnalysisError) return err(cause);
if (options?.signal?.aborted === true)
return err(new AnalysisCancelledError(operation));
// A PE header or section table the reader cannot map is malformed input.
if (
cause instanceof ManagedReaderFailure &&
cause.issue.code !== "resource-limit"
)
return err(
new AnalysisInputError(operation, { cause }, [
{
path: ["path"],
reason: "invalid_format",
message: `Selected artifact ${this.target.path}: ${cause.issue.detail}`,
},
]),
);
return err(
new ProviderAdapterError(MANAGED_STATIC_PROVIDER.id, operation, {
cause,
+33
View File
@@ -307,3 +307,36 @@ cliTest(
}
},
);
cliTest(
"managed CLI reports a section table past EOF as invalid input",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-managed-cli-sections-");
const path = join(root, "fixture.dll");
const bytes = buildManagedPeFixture();
const pe = bytes.readUInt32LE(0x3c);
const sections = pe + 24 + bytes.readUInt16LE(pe + 20);
bytes.writeUInt32LE(bytes.length + 0x1000, sections + 20);
await writeFile(path, bytes);
for (const command of [
"inspect-managed-artifact",
"inspect-managed-members",
"inspect-managed-native-boundaries",
]) {
const result = await cli.run({ arguments: [command, path, "--json"] });
expect(result.exitCode).toBe(1);
expect(result.json).toMatchObject({
code: "invalid_request",
details: {
issues: [
{
path: ["path"],
reason: "invalid_format",
message: expect.stringContaining("pe.section-data"),
},
],
},
});
}
},
);