fix(ghidra): refuse ambiguous universal Mach-O imports

This commit is contained in:
Kaoru0822 2026-10-06 05:00:53 -07:00
parent e2c23f3640
commit 6582b2433a
2 changed files with 45 additions and 2 deletions

View File

@ -208,6 +208,33 @@ describe("Ghidra provider", () => {
});
});
describe("Ghidra Mach-O slice support", () => {
it("refuses universal targets whose selected slice cannot be enforced", () => {
const ghidra = provider();
const universal: BinaryTarget = {
path: "/tmp/fixture",
sha256: "a".repeat(64),
kind: "executable",
format: "mach-o",
architecture: "arm64",
availableArchitectures: ["x86_64", "arm64"],
};
expect(ghidra.inspectTargetSupport(universal)).toMatchObject({
status: "unsupported",
code: "architecture_unsupported",
reason: expect.stringContaining("universal Mach-O"),
diagnostics: {
architecture: "arm64",
available_architectures: ["x86_64", "arm64"],
},
});
expect(
ghidra.inspectTargetSupport(executableTarget("mach-o", "arm64")),
).toMatchObject({ status: "supported" });
});
});
describe("Ghidra platform support", () => {
it("keeps Windows annotation mutation unavailable independently of native controls", () => {
const ghidra = provider({ ...installationHost(), platform: "win32" });

View File

@ -15,7 +15,11 @@ import {
import type { AppConfig } from "../config.js";
import type { AnalysisProfileCommitment } from "../domain/analysisProfile.js";
import type { BinaryTarget } from "../domain/binaryTarget.js";
import { jsonObjectSchema, jsonValueSchema } from "../domain/jsonValue.js";
import {
jsonObjectSchema,
jsonValueSchema,
type JsonValue,
} from "../domain/jsonValue.js";
import {
nativeLoadImageObservationSchema,
nativeLoadImageSchema,
@ -144,6 +148,10 @@ export class GhidraProvider implements AnalysisProviderCandidate {
target_kind: target.kind,
target_format: target.format,
architecture: target.architecture ?? null,
available_architectures:
target.kind === "executable"
? [...target.availableArchitectures]
: null,
executable_role: target.executableRole ?? null,
managed: target.managed ?? null,
};
@ -156,6 +164,14 @@ export class GhidraProvider implements AnalysisProviderCandidate {
};
if (hostPlatform === "win32")
return inspectWindowsP0TargetSupport(target, diagnostics);
if (target.format === "mach-o" && target.availableArchitectures.length > 1)
return {
status: "unsupported",
code: "architecture_unsupported",
reason:
"Ghidra v1 cannot enforce the selected architecture when importing a universal Mach-O; analyze a thinned Mach-O slice instead.",
diagnostics,
};
if (!SUPPORTED_ARCHITECTURES.has(target.architecture))
return {
status: "unsupported",
@ -381,7 +397,7 @@ export class GhidraProvider implements AnalysisProviderCandidate {
const inspectWindowsP0TargetSupport = (
target: BinaryTarget,
diagnostics: Readonly<Record<string, string | boolean | null>>,
diagnostics: Readonly<Record<string, JsonValue>>,
): ProviderTargetSupport => {
if (target.format !== "pe")
return {