Skip to content

fix: stabilize managed idalib IDB lifecycle on Windows - #44

Open
DGJK2301 wants to merge 3 commits into
MeroZemory:mainfrom
DGJK2301:fix/idalib-idb-lifecycle
Open

fix: stabilize managed idalib IDB lifecycle on Windows#44
DGJK2301 wants to merge 3 commits into
MeroZemory:mainfrom
DGJK2301:fix/idalib-idb-lifecycle

Conversation

@DGJK2301

@DGJK2301 DGJK2301 commented Sep 4, 2026

Copy link
Copy Markdown

Summary

  • prefer bind-tested IPv6 loopback for managed idalib workers on Windows, with an explicit IPv4 fallback when IPv6 is unavailable
  • preserve canonical module identity when reopening packed .i64/.idb files and fail closed if metadata cannot be established
  • add a per-process authenticated shutdown RPC so hidden Windows workers can pack and close databases instead of being force-killed
  • emit valid bracketed IPv6 URLs and validate IPv6 Host/Origin headers
  • pack headless databases with DBFL_KILL | DBFL_COMP, while retaining save-on-close as the data-preserving fallback
  • distinguish Windows Application Control WinError 4551 from a missing idapro package and retain the underlying detail for other import failures

Why

On the affected Windows host, fresh IPv4 loopback connections were intermittently reset even for a minimal standard-library HTTP server, while the IPv6 loopback control completed 100/100 requests. Separately, CREATE_NO_WINDOW workers could not reliably receive CTRL_BREAK_EVENT, leaving loose .id0/.id1/.id2/.nam/.til files and a stale packed IDB.

The shutdown token is generated per worker, passed only through the child environment, removed before serving, and excluded from request logs.

The same host also exposed a misleading diagnostic: Windows Application Control can block an unsigned idalib.dll with WinError 4551 while idapro is installed correctly. The worker now reports that policy failure instead of advising a pointless package reinstall.

Verification

  • python -m pytest -q: 446 passed, 9 skipped
  • scoped Ruff: passed
  • py_compile: passed
  • git diff --check: passed
  • real packed-IDB reopen: 100/100 pings and 20/20 metadata reads
  • real IDB identity: 131,197 functions, queue empty, original binary SHA-256 preserved
  • post-fix real protocol audit: packed IDB opened on ::1, analysis settled twice, searches/xrefs completed, and authenticated shutdown exited cleanly
  • clean shutdown leaves only the source binary and one packed .i64; no worker remains

@codex Please review this PR for correctness, Windows process lifecycle safety, transport compatibility, diagnostic accuracy, and test coverage.

Copilot AI lite review requested due to automatic review settings September 4, 2026 14:45
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T16:24:04.571621Z 35fbdc1 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes Windows worker shutdown/persistence and transport behavior in ways that are hard to fully validate without real Windows + IDA runtime verification.

Pull request overview

This PR hardens the Windows managed-idalib worker lifecycle by switching to a more reliable loopback transport, preserving canonical IDB identity when reopening packed databases, and adding an authenticated shutdown path so hidden workers can pack/close databases instead of being force-killed.

Changes:

  • Prefer IPv6 loopback (::1) for managed workers on Windows when bind-tested, with IPv4 fallback, and ensure bracketed IPv6 base URLs (http://[::1]:port).
  • Add an authenticated shutdown JSON-RPC method (ida-multi-mcp/shutdown) to let the manager request a clean worker stop, enabling packed-save + close rather than abrupt termination.
  • Retry/fail-closed behavior around canonical module metadata for IDB inputs to avoid registering an instance under an ambiguous/non-canonical identity; extend tests around all of the above.
File summaries
File Description
tests/test_idalib_worker_download_url.py Adds IPv6 URL bracketing, packed-close behavior tests, and shutdown RPC token enforcement tests for the worker.
tests/test_idalib_manager.py Adds tests for IPv6 port binding, Windows loopback host preference, shutdown request success parsing, metadata retry/fail-closed, and graceful termination behavior.
tests/test_http_ipv6.py Adds unit tests for IPv6 Host header parsing and IPv6 HTTP server-class selection.
src/ida_multi_mcp/vendor/zeromcp/mcp.py Adds IPv6-capable HTTP server classes, robust Host parsing via urlparse, and selects IPv6 server classes when hosting on ::1.
src/ida_multi_mcp/idalib_worker.py Implements bracketed origin construction, authenticated shutdown RPC registration, and packed-save-on-close with fallback to save-on-close.
src/ida_multi_mcp/idalib_manager.py Implements Windows IPv6 loopback preference, per-worker shutdown tokens passed via env, shutdown RPC request helper, and IDB canonical-metadata retry/fail-closed logic.
src/ida_multi_mcp/ida_mcp/zeromcp/mcp.py Mirrors the IPv6 server-class + Host parsing improvements for the HTTP transport copy.
src/ida_multi_mcp/ida_mcp/http.py Extends strict Origin/Host validation to accept bracketed IPv6 loopback.
Review details
  • Files reviewed: 7/8 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 290cc46eb2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +394 to +396
requested = _request_worker_shutdown(host, port, shutdown_token)
try:
proc.wait(timeout=_WORKER_SHUTDOWN_TIMEOUT if requested else 5)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Let queued shutdown RPCs wait for active IDA calls

When idalib_close runs concurrently with a long IDA request, the worker's non-threaded HTTPServer cannot process the shutdown POST until that request completes; meanwhile _request_worker_shutdown times out after 10 seconds, and this false branch waits only 5 more seconds before entering the signal/kill fallback. Since routed calls may run for up to 300 seconds and CTRL_BREAK_EVENT is unreliable for these hidden Windows workers, closing a busy session can still reach TerminateProcess, bypassing the new packed close and risking stale or loose IDB files. The shutdown path needs to wait for the queued RPC for at least the supported in-flight request duration or use an independently serviced shutdown channel.

Useful? React with 👍 / 👎.

@DGJK2301

DGJK2301 commented Sep 4, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 17a46470f8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

module_name = None
attempts = _IDB_METADATA_QUERY_ATTEMPTS if is_idb_input else 1
for attempt in range(attempts):
metadata = query_binary_metadata(selected_host, port, timeout=5.0)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid fixed five-second metadata reads for valid IDBs

When an .i64/.idb references a large original binary or resides on slow storage, idb_metadata_resource() reads the entire input file and computes multiple hashes before returning its module name (api_resources.py:46-55), so this five-second timeout can expire despite a healthy worker. Because the worker uses the non-threaded HTTP server, each timed-out request continues running while the next retry queues; after four such attempts module_name remains unset and spawn_session terminates an otherwise valid session. Fetch canonical identity through a lightweight resource or let the in-progress metadata request complete instead of retrying it with this short timeout.

Useful? React with 👍 / 👎.

# Create server with deferred binding
assert issubclass(request_handler, McpHttpRequestHandler)
self._http_server = (ThreadingHTTPServer if background else HTTPServer)(
self._http_server = _http_server_class(host, background)(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 Badge Bracket IPv6 hosts in advertised server URLs

When the newly supported host="::1" path is used, serve() still prints http://::1:<port>/mcp and http://::1:<port>/sse at lines 413-414. Those are malformed URLs because an IPv6 literal in a URL authority must be bracketed, so anyone using these startup diagnostics receives unusable endpoints even though the server bound successfully; format the displayed host as [::1] just as _http_origin() now does.

Useful? React with 👍 / 👎.

@DGJK2301

DGJK2301 commented Sep 4, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 35fbdc1102

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/architecture.md
- **id** — 4-char instance identifier (k7m2, px3a, etc.)
- **pid** — Process ID of the IDA Pro instance
- **host** — Always 127.0.0.1 (localhost)
- **host** — Loopback only: Windows managed workers prefer `::1` after a

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add an absolute update date to the architecture document

This commit modifies the architecture documentation without adding an absolute Last updated date, so readers cannot determine when the newly documented Windows transport behavior became current. Add the commit’s update date near the document header as required for every modified document.

AGENTS.md reference: AGENTS.md:L9-L12

Useful? React with 👍 / 👎.

Comment thread docs/architecture.md
Comment on lines +16 to +18
- **host** — Loopback only: Windows managed workers prefer `::1` after a
successful bind probe and otherwise use `127.0.0.1`; all other platforms use
`127.0.0.1`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Link the new transport behavior to its implementation

The new Windows IPv6-preference behavior is documented without references to the affected code paths, leaving maintainers unable to trace this architectural statement to _preferred_loopback_host() and the IPv6 ZeroMCP server selection. Add links to the relevant implementation files/functions alongside this behavior.

AGENTS.md reference: AGENTS.md:L14-L16

Useful? React with 👍 / 👎.

)

self._processes[instance_id] = proc
self._shutdown_tokens[instance_id] = shutdown_token

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove shutdown tokens when status detects a dead worker

When idalib_status detects a crashed worker, get_status() deletes the process entry and unregisters the instance but never removes the corresponding entry from the newly added _shutdown_tokens mapping. Repeated worker crashes followed by status checks therefore retain an unbounded number of per-process secrets for the lifetime of the router; mirror the cleanup already performed by list_sessions().

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants