Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
739cf68e1a |
@@ -565,8 +565,11 @@ Java major range, 64-bit JDK bitness, and the presence of `javac`/`javac.exe`.
|
||||
It also checks that the reported JVM `os.arch` and `os.name` map to the same native decompiler
|
||||
directory validated for the host; unrecognized reported architectures or a
|
||||
non-host operating system are refused. LaunchSupport overrides of either
|
||||
property, including through helper-environment JVM option variables, are
|
||||
rejected at launch.
|
||||
property, including quoted helper-environment JVM options, are rejected at
|
||||
launch. Indirect JVM `@argument-file` options are also refused because their
|
||||
effective platform properties cannot be established before launch; provide
|
||||
explicit options instead. OS-name matching follows Ghidra's operating-system
|
||||
identifiers: macOS requires `Mac OS X`, not `Darwin` or a generic `mac*` alias.
|
||||
When Java is found through `PATH`, setup records its observed JDK home so GUI
|
||||
MCP clients do not depend on an incidental shell path. Setup shows every exact
|
||||
environment entry in its plan, writes only after approval, and never downloads,
|
||||
|
||||
@@ -1041,6 +1041,36 @@ describe("Ghidra JVM native directory admission", () => {
|
||||
});
|
||||
|
||||
describe("Ghidra JVM OS admission", () => {
|
||||
it.each([
|
||||
["Darwin", false],
|
||||
["macOS", false],
|
||||
["Macintosh", false],
|
||||
["Mac OS X", true],
|
||||
["MAC OS X 26", true],
|
||||
["JVM on Mac OS X", true],
|
||||
["Mac OS X / Windows", false],
|
||||
["Mac OS X / Linux", false],
|
||||
] as const)(
|
||||
"matches Ghidra's ordered OS-name predicate for %s (available=%s)",
|
||||
(osName, available) => {
|
||||
const result = inspectGhidraInstallation(
|
||||
{
|
||||
environment: {},
|
||||
installDir: INSTALL,
|
||||
platform: "darwin",
|
||||
architecture: "arm64",
|
||||
},
|
||||
host({ probeJava: () => ({ ...JAVA, osArch: "aarch64", osName }) }),
|
||||
);
|
||||
expect(result.status).toBe(available ? "available" : "unavailable");
|
||||
expect(projectGhidraDoctorInspection(result).available).toBe(available);
|
||||
expect(result.javaOsName).toBe(osName);
|
||||
expect(
|
||||
result.checks.find(({ name }) => name === "native_decompiler"),
|
||||
).toMatchObject({ status: available ? "passed" : "failed" });
|
||||
},
|
||||
);
|
||||
|
||||
it("rejects a successful Java probe that omits os.name", () => {
|
||||
const { osName: _observedOsName, ...withoutOsName } = JAVA;
|
||||
const result = inspectGhidraInstallation(
|
||||
|
||||
@@ -741,11 +741,17 @@ const jvmOsNameMatchesPlatform = (
|
||||
osName: string,
|
||||
): boolean => {
|
||||
const normalized = osName.toLowerCase();
|
||||
if (platform === "win32") return normalized.startsWith("windows");
|
||||
if (platform === "darwin")
|
||||
return normalized.startsWith("mac") || normalized.startsWith("darwin");
|
||||
if (platform === "linux") return normalized.startsWith("linux");
|
||||
return false;
|
||||
// Ghidra 12.1.4 OperatingSystem.findCurrentOperatingSystem uses ordered,
|
||||
// case-insensitive substring matching, not Node's platform names or broad
|
||||
// mac*/Darwin aliases. Preserve that order for names containing several tags.
|
||||
const selected = normalized.includes("windows")
|
||||
? "win32"
|
||||
: normalized.includes("linux")
|
||||
? "linux"
|
||||
: normalized.includes("mac os x")
|
||||
? "darwin"
|
||||
: undefined;
|
||||
return selected === platform;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,13 @@ const jvmEnvironmentArguments = (value: string): readonly string[] => {
|
||||
};
|
||||
|
||||
const rejectJvmPlatformOverrides = (arguments_: readonly string[]): void => {
|
||||
// Indirect options can change the JVM platform after this admission check.
|
||||
// Do not read arbitrary, mutable argument files and pretend their contents
|
||||
// establish the later launch; require explicit inspectable options instead.
|
||||
if (arguments_.some((argument) => argument.startsWith("@")))
|
||||
throw new Error(
|
||||
"Ghidra LaunchSupport may not supply JVM argument files; their effective platform properties cannot be validated before launch.",
|
||||
);
|
||||
if (
|
||||
arguments_.some((argument) => /^-Dos\.(?:arch|name)(?:=|$)/u.test(argument))
|
||||
)
|
||||
@@ -113,7 +120,8 @@ export const ghidraJavaLaunch = async (options: {
|
||||
// The merged environment becomes the analysis JVM's environment, and the
|
||||
// JVM applies these options variables automatically. An injected
|
||||
// -Dos.arch/-Dos.name there selects an unvalidated native directory without
|
||||
// appearing in vmArguments, so reject the effective values as well.
|
||||
// appearing in vmArguments, so reject the effective values as well. Argument
|
||||
// files are refused because their expanded options are not established here.
|
||||
for (const key of [
|
||||
"JAVA_TOOL_OPTIONS",
|
||||
"_JAVA_OPTIONS",
|
||||
|
||||
@@ -273,6 +273,22 @@ describe.skipIf(process.platform === "win32")(
|
||||
expect(analysisArguments).toHaveLength(1);
|
||||
});
|
||||
|
||||
it.each(["@options", '"@options with spaces"'])(
|
||||
"refuses indirect JVM options (%s) instead of assuming platform alignment",
|
||||
async (value) => {
|
||||
const { session, launcher, analysisArguments } = await fixture(
|
||||
`env-injection:JDK_JAVA_OPTIONS=${value}`,
|
||||
);
|
||||
const launched = await launcher.launch(session);
|
||||
expect(launched.ok).toBe(false);
|
||||
expect(analysisArguments).toEqual([]);
|
||||
if (launched.ok) throw new Error("Expected an argument-file refusal");
|
||||
expect(launched.error.cause).toMatchObject({
|
||||
message: expect.stringContaining("may not supply JVM argument files"),
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it("bounds retained UTF-8 warnings and reports original byte counts", async () => {
|
||||
const { session, launcher } = await fixture("large");
|
||||
const launched = await launcher.launch(session);
|
||||
|
||||
Reference in New Issue
Block a user