Skip to content

[codex] add windows minifilter overlay backend#1

Merged
mizuamedesu merged 120 commits into
masterfrom
codex/windows-minifilter-overlay
Jun 17, 2026
Merged

[codex] add windows minifilter overlay backend#1
mizuamedesu merged 120 commits into
masterfrom
codex/windows-minifilter-overlay

Conversation

@mizuamedesu

Copy link
Copy Markdown
Member

Summary

Adds a Windows path-preserving overlay backend based on a minifilter driver and a user-mode launcher/control helper.

  • Adds agent-minifilterctl, which launches processes suspended, registers PID/env lower/upper/whiteout roots with the filter, assigns the process to a Job Object, then resumes it.
  • Adds a WDK minifilter scaffold under drivers/windows-minifilter with process-tree env inheritance, create redirect, write copy-up, delete whiteouts, and rename-to-upper behavior.
  • Makes Windows default to the minifilter overlay backend, while keeping AGENT_WINDOWS_BLOCK_CLONE=1 as a compatibility fallback for CI and driverless machines.
  • Adds packaging/install updates and a Windows minifilter smoke script for elevated WDK machines.

Validation

  • cargo fmt --all -- --check
  • cargo check --workspace
  • cargo check -p agent-core -p agentctl -p agent-forkd -p agent-minifilterctl --target x86_64-pc-windows-msvc
  • cargo test -p agent-core -p agentctl

Notes

The Windows real-machine smoke script is included as scripts/windows-minifilter-smoke.ps1, but SSH to the provided host timed out from this environment, so the WDK driver load/smoke still needs to be run on the Windows machine.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update: added directory listing merge support in the minifilter path. The post directory callback now rewrites lower query results by removing whiteout/upper-shadowed entries and appending upper entries; the Windows smoke script now verifies listing behavior. Re-ran local checks: cargo fmt --all -- --check, cargo check --workspace, cargo check -p agent-core -p agentctl -p agent-forkd -p agent-minifilterctl --target x86_64-pc-windows-msvc, cargo test -p agent-core -p agentctl. Windows host SSH still times out at 100.123.154.79:22, so WDK load/smoke remains pending on the real machine.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update: fixed a kernel-safety issue in the minifilter driver. The callbacks now snapshot the registered env roots under the env-list lock and perform name resolution / FltCreateFile / ZwReadFile / ZwWriteFile work after releasing the lock. This avoids doing filesystem work while holding the FAST_MUTEX. Validation rerun: cargo fmt --all -- --check, cargo check --workspace, cargo check -p agent-core -p agentctl -p agent-forkd -p agent-minifilterctl --target x86_64-pc-windows-msvc, cargo test -p agent-core -p agentctl. Windows SSH to 100.123.154.79:22 still times out, so WDK driver build/load smoke is still pending.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Windows minifilter follow-up status:

  • Added WDK/MSBuild bridge setup so CI and local smoke can build the driver even when WDK 26100 installs its build files under Windows Kits rather than registering the VS platform toolset.
  • Fixed the driver package project so agentfs.sys builds successfully on the Windows host.
  • Added INF SourceDisks* metadata and CI inf2cat validation; the PR check Windows minifilter / build Rust helpers and WDK driver is now green and uploads agentfs.sys, agentfs.pdb, agentfs.inf, and agentfs.cat.
  • On the Windows host agent@100.93.230.32, the smoke now reaches: Rust helper build -> WDK driver build -> catalog generation -> self-signing -> driver store add -> service registration.
  • The remaining runtime blocker on that host is Secure Boot/code-integrity policy: fltmc load agentfs fails with 0x80070241 after service registration, and bcdedit /set testsigning on is rejected because Secure Boot is enabled. The driver cannot be loaded there without disabling Secure Boot/testsigning policy or using a production-trusted driver signing path.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update after e0abe0f:

  • Added explicit Secure Boot/test-signing diagnostics to scripts/windows-minifilter-smoke.ps1 and documented the signing requirement.
  • Re-ran the real Windows smoke on agent@100.93.230.32: Rust helpers, WDK driver build, inf2cat, signing, pnputil, and service registration all succeeded.
  • fltmc load agentfs still fails on that host with 0x80070241 because Secure Boot is enabled and test-signing is not active, so runtime overlay verification remains blocked until the host boots with test-signing allowed or the driver is production/attestation signed.
  • GitHub Actions run 27555600499 passed and uploaded the driver artifacts.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update after 074c094:

  • Fixed a directory enumeration bug in the minifilter merge path: upper-layer entries are no longer appended again after the lower directory query has already reached STATUS_NO_MORE_FILES for the same scan sequence. This avoids repeatedly returning upper-only names during dir/ls-style enumeration.
  • Verified on agent@100.93.230.32 that the updated driver still builds with WDK, passes inf2cat, signs, installs to the driver store, and reaches the same Secure Boot load gate.
  • GitHub Actions run 27556220537 passed and uploaded driver artifacts.

Runtime overlay verification is still blocked by the host's Secure Boot/test-signing policy, not by build/package failures.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update after b6f9794:

  • Fixed delete -> recreate semantics in the minifilter redirect path. A whiteout now continues to hide reads/open-only attempts, but create-capable write opens remove the whiteout and create a fresh upper entry instead of copying the deleted lower file back.
  • Extended the Windows smoke script with a delete-and-recreate case so a loadable test-signing environment will verify that host content remains unchanged, the recreated file lands in upper, and no stale whiteout remains.
  • Re-ran the smoke on agent@100.93.230.32: Rust helpers, WDK driver build, inf2cat, signing, pnputil, and service registration still succeed. Runtime execution remains blocked at fltmc load by SecureBoot=True TestSigning=off.
  • GitHub Actions run 27556917892 passed and uploaded driver artifacts.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update after 651282a:

  • Tightened directory enumeration merging so upper-layer entries are appended only after the lower directory query reaches STATUS_NO_MORE_FILES. This avoids returning the same upper-only names on every successful lower page when a directory listing spans multiple query calls.
  • Pass the original query FileName/search pattern through to the upper-layer ZwQueryDirectoryFile call, so filtered directory queries merge matching upper names instead of all upper names.
  • Re-ran the smoke on agent@100.93.230.32: Rust helpers, WDK driver build, inf2cat, signing, pnputil, and service registration still succeed. Runtime execution remains blocked at fltmc load by SecureBoot=True TestSigning=off.
  • GitHub Actions run 27557488303 passed and uploaded driver artifacts.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update after b9b2b53:

  • Added per-directory-handle merge state for directory enumeration. The minifilter now remembers when upper-layer entries have already been appended for a FileObject, resets that state on restart/pattern queries, and removes it on IRP_MJ_CLEANUP.
  • This prevents repeated upper-only entries after the lower directory has already reached STATUS_NO_MORE_FILES on subsequent query calls for the same handle.
  • Re-ran the smoke on agent@100.93.230.32: Rust helpers, WDK driver build, inf2cat, signing, pnputil, and service registration still succeed. Runtime execution remains blocked at fltmc load by SecureBoot=True TestSigning=off.
  • GitHub Actions run 27558163175 passed and uploaded driver artifacts.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update after 40804d6:

  • Fixed directory copy-up handling in the minifilter redirect path. When a lower path is a directory and the request has write/create intent, the driver now creates the corresponding upper directory tree instead of trying to copy it as a file.
  • Extended the smoke script to exercise re-opening/recreating an existing lower directory before writing beneath it.
  • Re-ran the smoke on agent@100.93.230.32: Rust helpers, WDK driver build, inf2cat, signing, pnputil, and service registration still succeed. Runtime execution remains blocked at fltmc load by SecureBoot=True TestSigning=off.
  • GitHub Actions run 27558724057 passed and uploaded driver artifacts.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update after 1116322:

  • Fixed upper-layer rename handling by using ZwSetInformationFile(FileRenameInformation) for paths that already exist in upper, instead of copy/delete. This lets upper-only directory trees move in place with their contents preserved.
  • Added a smoke case that creates nested\created\more\new.txt, renames nested\created to nested\renamed, and verifies the renamed upper tree content plus absence of the old source directory.
  • Re-ran the smoke on agent@100.93.230.32: Rust helpers, WDK driver build, inf2cat, signing, pnputil, and service registration still succeed. Runtime execution remains blocked at fltmc load by SecureBoot=True TestSigning=off.
  • GitHub Actions run 27559317065 passed and uploaded driver artifacts.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update after e69f70b:

  • Added recursive lower-directory copy-up for minifilter rename. When a lower-only directory is renamed inside the overlay, the driver now enumerates the lower subtree and copies files/directories into the target upper tree before creating the source whiteout.
  • Extended the smoke script with a lower-only directory tree rename case: move-lower\inside\lower-file.txt -> moved-lower\inside\lower-file.txt, with host content unchanged and a whiteout for the source directory.
  • Re-ran the smoke on agent@100.93.230.32: Rust helpers, WDK driver build, inf2cat, signing, pnputil, and service registration still succeed. Runtime execution remains blocked at fltmc load by SecureBoot=True TestSigning=off.
  • GitHub Actions run 27559921069 passed and uploaded driver artifacts.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update after 116aee8:

  • Preserved mixed upper+lower directory rename semantics in the minifilter path: if an upper directory already exists for the source, the driver renames that upper tree and then copies lower-only children into the renamed upper target without overwriting upper-modified files.
  • Extended the Windows smoke script to cover the mixed directory case: host lower file remains unchanged, upper-modified file survives the rename, lower-only child is copied into upper, and the source whiteout is created.
  • Re-ran the smoke script on the real Windows host agent@100.93.230.32. Rust helpers, WDK driver build, inf2cat, test signing, pnputil install, and service registration all succeed. Runtime verification is still blocked at fltmc load because SecureBoot=True and TestSigning=off reject the locally test-signed driver.
  • GitHub Actions run passed and uploaded driver artifacts: https://github.com/IPA-CyberLab/IPA-RS-IsolatedAgent/actions/runs/27560525867

@mizuamedesu

Copy link
Copy Markdown
Member Author

Update after 58bbda3:

  • Fixed rename-to-deleted-target behavior in the minifilter path. A successful overlay rename now clears the target whiteout so the renamed upper entry is visible instead of remaining hidden by an older delete marker.
  • Extended the Windows smoke script with a regression case that deletes a lower file, renames an upper-created file onto that deleted name, verifies the host lower file is unchanged, verifies the upper target contains the renamed data, and verifies the target whiteout is removed.
  • Re-ran the smoke script on the real Windows host agent@100.93.230.32. Rust helpers, WDK driver build, inf2cat, test signing, pnputil install, and service registration still succeed. Runtime verification remains blocked at fltmc load because SecureBoot=True and TestSigning=off reject the locally test-signed driver.
  • GitHub Actions passed and uploaded driver artifacts: https://github.com/IPA-CyberLab/IPA-RS-IsolatedAgent/actions/runs/27560996845

@mizuamedesu

Copy link
Copy Markdown
Member Author

Added and pushed 782dda7 (Fail closed on env snapshot errors).

What changed:

  • AgentFsSnapshotEnvForProcess now preserves clone/allocation failures instead of collapsing them into STATUS_NOT_FOUND.
  • Pre-create, set-information, directory-control, and filesystem-control callbacks now pass through only when no env is registered for the process. If an env exists but snapshotting fails, the callback completes with that error instead of falling through to the host path.
  • This makes the overlay fail closed for registered processes, avoiding accidental host writes if env snapshot allocation fails.

Validation:

Remaining blocker is unchanged: fltmc load agentfs fails with 0x80070241 because the Windows host has SecureBoot=True and TestSigning=off; the local test certificate driver cannot be loaded until test signing is enabled before boot or the driver is production/attestation signed.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Added and pushed 3897e9e (Fail closed on child env clone errors).

What changed:

  • Child process env inheritance now fails closed if cloning the parent env fails in AgentFsProcessNotify.
  • When a parent process is registered but the child env allocation/clone fails, the process creation callback sets CreateInfo->CreationStatus to the failure status instead of allowing the child to start unregistered.
  • This avoids a child process escaping the overlay and writing to host paths if env inheritance cannot be established.

Validation:

Remaining blocker is unchanged: fltmc load agentfs fails with 0x80070241 because the Windows host has SecureBoot=True and TestSigning=off; the local test certificate driver cannot be loaded until test signing is enabled before boot or the driver is production/attestation signed.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Added and pushed d00277a (Fail closed on directory merge setup errors).

What changed:

  • Directory enumeration now fails closed if the overlay merge setup cannot be built for a registered process.
  • Failures in name lookup, name parsing, merge context allocation, or lower/upper/whiteout path construction now complete the directory query with an error instead of falling through to the underlying directory enumeration.
  • This avoids returning lower-only or upper-only listings when the host+upper+whiteout merge cannot be prepared.

Validation:

Remaining blocker is unchanged: fltmc load agentfs fails with 0x80070241 because the Windows host has SecureBoot=True and TestSigning=off; the local test certificate driver cannot be loaded until test signing is enabled before boot or the driver is production/attestation signed.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Windows minifilter update: pushed c0fdc2c (Fail closed on name resolution errors). This makes registered-process create, set-information, and reparse FSCTL paths fail closed when Filter Manager name lookup/parse fails instead of passing the operation through to the host path.\n\nValidation:\n- Local Windows host build/sign/install path reached the known load blocker: Rust helpers OK, WDK driver build OK, inf2cat OK, signtool OK, pnputil OK, then fltmc load agentfs failed because SecureBoot=True and TestSigning=off for the local test certificate.\n- GitHub Actions Windows minifilter run passed: https://github.com/IPA-CyberLab/IPA-RS-IsolatedAgent/actions/runs/27600538048\n\nCurrent blocker remains runtime driver loading on agent@100.93.230.32 due to Secure Boot blocking the locally test-signed driver. I did not change boot/test-signing settings.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Windows minifilter update: pushed 10ba641 (Fail closed on redirect selection errors). After a registered process path is confirmed to be under the managed source root, PreCreate now completes with the redirect-selection error instead of passing through to the host path. This keeps copy-on-write isolation intact on internal redirect failures.\n\nValidation:\n- Local Windows host: Rust helpers OK, WDK driver build OK, inf2cat OK, signtool OK, pnputil OK; runtime load still reaches the known blocker at fltmc load agentfs because SecureBoot=True and TestSigning=off for the local test certificate.\n- GitHub Actions Windows minifilter run passed: https://github.com/IPA-CyberLab/IPA-RS-IsolatedAgent/actions/runs/27601043346\n\nI did not change boot, Secure Boot, or test-signing settings.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Windows minifilter update: pushed fb4dc30 (Fail closed on directory hide errors). Directory enumeration now propagates errors from whiteout/upper hide checks and upper merge opening instead of treating failures as visible entries or a successful empty merge. This reduces lower-entry leaks when merge bookkeeping fails.\n\nValidation:\n- Local Windows host: Rust helpers OK, WDK driver build OK, inf2cat OK, signtool OK, pnputil OK; runtime load still reaches the known blocker at fltmc load agentfs because SecureBoot=True and TestSigning=off for the local test certificate.\n- GitHub Actions Windows minifilter run passed: https://github.com/IPA-CyberLab/IPA-RS-IsolatedAgent/actions/runs/27601423806\n\nI did not change boot, Secure Boot, or test-signing settings.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Windows minifilter update: pushed 9273604 (Fail closed on delete overlay errors). Managed source delete handling now completes with the overlay operation error if upper deletion or whiteout path construction fails, instead of passing the delete through to the host path. This keeps delete isolation intact on internal overlay failures.\n\nValidation:\n- Local Windows host: Rust helpers OK, WDK driver build OK, inf2cat OK, signtool OK, pnputil OK; runtime load still reaches the known blocker at fltmc load agentfs because SecureBoot=True and TestSigning=off for the local test certificate.\n- GitHub Actions Windows minifilter run passed: https://github.com/IPA-CyberLab/IPA-RS-IsolatedAgent/actions/runs/27601823594\n\nI did not change boot, Secure Boot, or test-signing settings.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Windows minifilter update: pushed e3ceffd (Preserve visible path conversion errors). AgentFsVisiblePathFromName now only falls back from upper-root classification to lower-root classification when the upper path simply does not match. Other conversion failures, such as allocation errors, are preserved instead of being masked as a lower lookup miss.\n\nValidation:\n- Local Windows host: Rust helpers OK, WDK driver build OK, inf2cat OK, signtool OK, pnputil OK; runtime load still reaches the known blocker at fltmc load agentfs because SecureBoot=True and TestSigning=off for the local test certificate.\n- GitHub Actions Windows minifilter run passed: https://github.com/IPA-CyberLab/IPA-RS-IsolatedAgent/actions/runs/27602168400\n\nI did not change boot, Secure Boot, or test-signing settings.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Windows minifilter update: pushed 190086a (Fail closed on visible path errors). PreSetInformation and PreFileSystemControl now pass through only when visible-path classification returns STATUS_NOT_FOUND. Other classification failures are completed with the error instead of being treated as unmanaged paths, preventing internal lookup/allocation failures from escaping to host operations.\n\nValidation:\n- Local Windows host: Rust helpers OK, WDK driver build OK, inf2cat OK, signtool OK, pnputil OK; runtime load still reaches the known blocker at fltmc load agentfs because SecureBoot=True and TestSigning=off for the local test certificate.\n- GitHub Actions Windows minifilter run passed: https://github.com/IPA-CyberLab/IPA-RS-IsolatedAgent/actions/runs/27602747599\n\nI did not change boot, Secure Boot, or test-signing settings.

@mizuamedesu

Copy link
Copy Markdown
Member Author

Windows minifilter update: pushed d419607 (Fail closed on directory state errors). Directory merge state updates now return status. If the driver cannot record the upper merge state or single-entry cursor, the directory query fails closed instead of returning a successful result that could repeat or mis-merge upper entries on subsequent calls.\n\nValidation:\n- Local Windows host: Rust helpers OK, WDK driver build OK, inf2cat OK, signtool OK, pnputil OK; runtime load still reaches the known blocker at fltmc load agentfs because SecureBoot=True and TestSigning=off for the local test certificate.\n- GitHub Actions Windows minifilter run passed: https://github.com/IPA-CyberLab/IPA-RS-IsolatedAgent/actions/runs/27603197941\n\nI did not change boot, Secure Boot, or test-signing settings.

@mizuamedesu mizuamedesu merged commit 227f77f into master Jun 17, 2026
1 check passed
@mizuamedesu mizuamedesu deleted the codex/windows-minifilter-overlay branch June 20, 2026 05:23
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.

1 participant