Repository navigation
feat(ghidra): disable named auto-analyzers via REA_GHIDRA_DISABLED_ANALYZERS - #1800
Open
akushonkamen wants to merge 2 commits into
Open
akushonkamen wants to merge 2 commits into
akushonkamen wants to merge 2 commits into
Conversation
…ALYZERS Default auto-analysis can stall in a single analyzer, such as ObjcMessageAnalyzer on a Swift/Objective-C arm64 Mach-O, and a caller had no way around it: the headless launcher passed -preScript only for DOS COM preparation and seed files, and the analysis profile always recorded analyzer_preset "ghidra-default" (morluto#1783). REA_GHIDRA_DISABLED_ANALYZERS now names comma-separated Ghidra auto-analyzers that a pre-analysis script disables before default auto-analysis, following the same packaged pre-script precedent. The analysis profile records the override in analyzer_preset and analysis_options, and a session refuses to open when its committed profile and the setting differ, so snapshots and Evidence stay bound to the analysis that actually ran. Validation: new tests for the setting parser, launcher argv injection and ordering, and profile recording plus fail-closed profile binding; existing launcher, DOS COM, seeds, language-override, and Ghidra MCP evidence coverage rerun green (314 src/ghidra module tests, 54 ghidra boundary tests, check:fast, verify:test-discovery, generated-file checks). Real Ghidra was not exercised: this machine has no Ghidra installation; the stall reproduction and the disable-one-analyzer control come from the issue report's out-of-repo analyzeHeadless runs on Ghidra 12.1.4.
…ndows verifier The caller-cwd shadowing verifier enumerated exactly the bridge scripts the launcher passes as arguments, but missed the new ReaGhidraAnalysisOptions.java preScript, leaving the new script outside the shadowing coverage and the caller-cwd preservation assertion. Sorting the list is required, not cosmetic: the assertion compares readdir(callerDirectory).sort() against it, so the pre-sort order introduced in 162f9bf and af88184 could never match on any platform (reproduced with a local readdir+sort probe; the lane itself requires a Windows x64 host and was not run here). Also documents the 120-character single-name limit next to the 32-name cap in the installation guide.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
2 tasks done
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1783. Ghidra's default auto-analysis can stall indefinitely in a single analyzer (
ObjcMessageAnalyzeron a 1.85 MB Swift/ObjC arm64 Mach-O), and REA gave the caller no way to skip it and no record of what ran: the analysis profile always saidanalyzer_preset: "ghidra-default". This addsREA_GHIDRA_DISABLED_ANALYZERS, a comma-separated list of exact analyzer names that are disabled via a pre-analysis script before default auto-analysis, recorded in the analysis profile so snapshots and Evidence stay bound to the analysis that actually ran.Problem and expected behavior
src/ghidra/GhidraLauncher.ts'sghidraHeadlessArgumentsonly injected-preScriptfor the DOS COM loader branch and seed files — there was no channel for analyzer options (verified onmain@ce845ba4: interface 371–386, argv builder 388–468; the DOS COM-preScriptsits at what is now 446–449 after unrelated main-side churn, content unchanged), andsrc/ghidra/GhidraAnalysisProfile.ts:152hardcodesanalyzer_preset: "ghidra-default"with no configurable analyzer field. The issue's out-of-REA controls show the same binary analyzing to completion in 76 s with one analyzer turned off, versus a 300 s analysis timeout with defaults — so a supported skip is the fix. Expected: a caller can name analyzers to disable for a session, and the profile records the override.Change and scope
bridge/ghidra/ReaGhidraAnalysisOptions.java(modeled on the existingReaGhidraPrepareComprecedent): requires exactly one comma-separated argument and callssetAnalysisOption(currentProgram, "<name>", "false")for each name.src/config/ghidraDisabledAnalyzers.tsparsesREA_GHIDRA_DISABLED_ANALYZERS: comma-separated, blank entries dropped, at most 32 names of at most 120 chars, each matching^[A-Za-z0-9][A-Za-z0-9 ._-]*$(a name can neither start with-nor contain a comma — Ghidra's headless parser would eat those as its own options). Anything else fails config admission.src/config/environment.ts:43→src/config/parseConfig.ts:91-93→src/config/types.ts:17→src/ghidra/GhidraProvider.ts:195→src/ghidra/GhidraProviderClient.ts→src/ghidra/GhidraLauncher.ts:468-475, where the-preScriptis injected after the seed script and before the post-analysis repair/bridge postScripts.analyzer_preset: "ghidra-default+disabled:<names>"plus structuredanalysis_options.disabled_analyzers(src/ghidra/GhidraAnalysisProfile.ts). Mirroring the language-override binding,ghidraProfileDisabledAnalyzersreads the commitment back and a session fails closed (refuses to open) when its committed profile and the active setting disagree.docs/installation.mddocuments the setting, its name rules, and that disabling an analyzer skips the facts it would have produced.Contract and boundary impact
src/ghidra/GhidraLauncher.ts,src/ghidra/GhidraAnalysisProfile.ts).bridge/ghidra/ReaGhidraAnalysisOptions.java(added topackage.jsonfiles and the packaged-Windows verifier manifest); no change to existing scripts.analyzer_preset: "ghidra-default+disabled:<names>"andanalysis_options.disabled_analyzers, and session open fails closed on profile/setting mismatch, so snapshots stay bound to the analysis that ran.-scriptPath; no new processes or cleanup paths.package.jsonships the new bridge file;docs/installation.mddocuments the setting. No committed generated outputs change.Evidence and regression coverage
src/config/ghidraDisabledAnalyzers.tscovered by newsrc/ghidra/GhidraDisabledAnalyzers.test.ts(10 tests: parsing, limits, name rules).tests/boundary/providers/ghidra/ghidraLauncher.test.ts: argv injection, ordering after seed / before-postScript, byte-identical argv when unset (3 new tests).src/ghidra/GhidraProvider.behavior.test.ts: profile recording, fail-closed binding, end-to-end provider threading (3 new tests).scripts/verify-packaged-ghidra-windows.mjscovers the new pre-script in the packaged Windows verifier manifest (second commit).main@40d9c7b8(7 commits advanced since the branch pointce845ba4, clean rebase), the red state was reproduced by restoring all non-test source files toorigin/mainwhile keeping the new tests, then:timeout 300 npx vitest run tests/boundary/providers/ghidra/ghidraLauncher.test.ts— 3 failed | 16 passed | 1 skipped.timeout 300 npx vitest run src/ghidra/GhidraDisabledAnalyzers.test.ts—Error: Cannot find module '../config/ghidraDisabledAnalyzers.js'.timeout 300 npx vitest run src/ghidra/GhidraProvider.behavior.test.ts -t "disabled analyzer"— 3 failed | 40 skipped.All pass with the fix restored (numbers under Validation performed).
REA_GHIDRA_DISABLED_ANALYZERS="Objective-C Message Analyzer"the session's profile carriesanalyzer_preset: "ghidra-default+disabled:Objective-C Message Analyzer".which analyzeHeadless→ not found; no~/ghidra*,/opt/ghidra*,/Applications/ghidra*;GHIDRA_INSTALL_DIRempty), so the Ghidra 12.1.4 stall reproduction and the disable-one-analyzer 76 s control come from the issue report's out-of-REAanalyzeHeadlessruns, as stated in the commit message.For evidence-bearing changes:
Validation performed
Rebased onto
origin/main@40d9c7b8(branch pointce845ba4), then, on macOS arm64 / Node 24.14.0 — red state first as listed above, then with the fix restored:timeout 300 npx vitest run tests/boundary/providers/ghidra/ghidraLauncher.test.ts— 19 passed | 1 skipped.timeout 300 npx vitest run src/ghidra/GhidraDisabledAnalyzers.test.ts— 10 passed.timeout 300 npx vitest run src/ghidra/GhidraProvider.behavior.test.ts— 43 passed (full file, incl. the 3 new tests).timeout 300 npx vitest run src/ghidra/GhidraDosComLoadImage.test.ts— 13 passed.timeout 300 npx vitest run src/config.test.ts src/ghidra/GhidraLanguageOverride.test.ts src/ghidra/GhidraAnalysisSeeds.test.ts src/ghidra/GhidraLauncherEnvironment.test.ts— 76 passed.timeout 300 npx vitest run tests/boundary/providers/ghidra/— 54 passed | 1 skipped.timeout 300 npx vitest run tests/boundary/mcp/ghidraEvidenceMcp.test.ts— 4 passed.timeout 570 npx vitest run src/ghidra/— 17 files, 314 passed.npm run check:fast— 2 successful (turbo typecheck + lint, lint includesverify:module-boundaries).npm run verify:test-discovery— "Discovered all 823 test files exactly once."npm run build:cached— exit 0; thennode scripts/check-doc-facts.mjs— exit 0.node scripts/generate-package-metadata.mjs --check,node scripts/generate-skill-metadata.mjs --check,node scripts/generate-product-catalog.mjs --check,node scripts/generate-completion-ledger.mjs --check,node scripts/generate-error-schema.mjs --check— each exit 0. (completion-ledger's first run failed on the git-ignoreddocs/verification/managed-conformance-manifest.json;npm run docs:generateregenerated it, after which the check passes. Working tree stayed clean.)npm run verify:ghidra(real Ghidra e2e) — not run: no Ghidra installation on this machine (see Remaining proof gaps).Compatibility, safety, and release
"ghidra-default"as before.setAnalysisOptionin a pre-script) outside REA. Unit/boundary coverage covers everything REA adds around it.bridge/ghidra/ReaGhidraAnalysisOptions.javaadded to the packaged file list and the packaged-Windows verifier manifest.-scriptPath; no shell interpolation, no new scripts sourced from user paths, no change to process cleanup.Review checklist
type(scope): outcome.Disclosure: this contribution is prepared with AI assistance (Claude), reviewed and verified by me (same disclosure as the issue claim comment).