From 9337ac3e5edd42bb17f5e2ade6c2de02c7ef576d Mon Sep 17 00:00:00 2001 From: tanaka takashi Date: Thu, 13 Aug 2026 22:48:24 +0900 Subject: feat!: isolate privileged sandbox network operations per task Run agent-mcp with an explicit asInvoker manifest and move WFP and loopback mutations into a fixed requireAdministrator helper under the release admin directory. Add the Agent.Admin client and host projects with task-scoped runas launch, a logon-SID and Administrators-only local named pipe, remote-client rejection, mutual PID validation, strict versioned JSON framing, fixed network-only operations, and bounded messages. Delay ACL and network Task Resource application until the first process_run. Verify executable identity, managed entry points, DNS snapshots, and normal-token WRITE_DAC access before elevation; reuse the helper only within the Task and keep elevation failures terminal without policy replanning. Keep LPAC creation, executable approval, Job confinement, and ACL leases in the normal process. Make startup platform checks read-only, create the fixed Application Profile during apply, preserve dynamic WFP lifetime in the helper, and route persistent loopback recovery through the same elevated boundary. Update recovery journaling, localized elevation and IPC errors, audit events, release publishing, manifests, README guidance, Specifications, Design, implementation records, and requirement traceability for the on-demand elevation model. Add administrative-boundary, file-only no-elevation, elevation-terminal, lazy-resource, crash-recovery, manifest, IPC schema, and operational verification coverage. Verified Release build with zero warnings, Core 105/105, Planner 10/10, administrative boundary 4/4, elevated Windows suite 79/79, and published stdio/HTTP MCP E2E. --- .../Diagnostics/WindowsPlatformCheck.cs | 64 ++++++++++++---------- 1 file changed, 35 insertions(+), 29 deletions(-) (limited to 'src/Agent.Windows/Diagnostics/WindowsPlatformCheck.cs') diff --git a/src/Agent.Windows/Diagnostics/WindowsPlatformCheck.cs b/src/Agent.Windows/Diagnostics/WindowsPlatformCheck.cs index b8ca0ae..89a2106 100644 --- a/src/Agent.Windows/Diagnostics/WindowsPlatformCheck.cs +++ b/src/Agent.Windows/Diagnostics/WindowsPlatformCheck.cs @@ -1,50 +1,56 @@ using System.ComponentModel; -using System.Security.Principal; -using Agent.Windows.Network; +using System.Diagnostics; +using System.Reflection; using Agent.Windows.Security; +using Windows.Win32; +using Windows.Win32.NetworkManagement.WindowsFilteringPlatform; namespace Agent.Windows.Diagnostics; public sealed record WindowsPlatformCheckResult( - bool IsAdministrator, + bool PlatformSupported, + bool ApplicationProfileAvailable, bool BfeEngineOpen, - bool WfpWriteTransaction, - bool WfpFilterAddDelete, + bool HelperAvailable, + bool HelperVersionCompatible, int? ErrorCode, string? ErrorOperation) { - public bool Success => IsAdministrator && BfeEngineOpen && WfpWriteTransaction && WfpFilterAddDelete; + public bool Success => PlatformSupported && ApplicationProfileAvailable && BfeEngineOpen && HelperAvailable && HelperVersionCompatible; } public static class WindowsPlatformCheck { - public static WindowsPlatformCheckResult Run() + public static WindowsPlatformCheckResult Run(string helperPath) { - using WindowsIdentity identity = WindowsIdentity.GetCurrent(); - bool administrator = new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator); - bool open = false; - bool transaction = false; - bool filters = false; + bool platform = OperatingSystem.IsWindowsVersionAtLeast(10, 0, 26100); + bool profile = false; + bool bfe = false; + bool helper = File.Exists(helperPath); + bool version = false; try { - AppContainerProfile profile = AppContainerProfile.EnsureFixed(); - using WfpDynamicSession session = WfpDynamicSession.Open(); - open = true; - session.ProbeWriteTransaction(); - transaction = true; - IReadOnlyList ids = session.ApplyDefaultBlock(profile.Sid); - if (ids.Count != 2 || ids.Any(static id => id == 0)) throw new InvalidOperationException("WFP probe did not create both IPv4 and IPv6 filters."); - session.RemovePolicy(); - filters = true; - return new(administrator, open, transaction, filters, null, null); - } - catch (Win32Exception ex) - { - return new(administrator, open, transaction, filters, ex.NativeErrorCode, ex.Message); + _ = AppContainerProfile.DeriveFixed(); + profile = true; + using FwpmEngineClose0SafeHandle engine = OpenBfeReadOnly(); + bfe = true; + if (helper) + { + string current = Assembly.GetEntryAssembly()?.GetName().Version?.ToString(3) ?? ""; + string candidate = FileVersionInfo.GetVersionInfo(helperPath).FileVersion ?? ""; + version = candidate.StartsWith(current, StringComparison.Ordinal); + } + return new(platform, profile, bfe, helper, version, null, null); } + catch (Win32Exception ex) { return new(platform, profile, bfe, helper, version, ex.NativeErrorCode, ex.Message); } catch (Exception ex) when (ex is UnauthorizedAccessException or InvalidOperationException or IOException) - { - return new(administrator, open, transaction, filters, ex.HResult, ex.Message); - } + { return new(platform, profile, bfe, helper, version, ex.HResult, ex.Message); } + } + + private static FwpmEngineClose0SafeHandle OpenBfeReadOnly() + { + uint result = PInvoke.FwpmEngineOpen0(10, null, null, out FwpmEngineClose0SafeHandle engine); + if (result != 0) throw new Win32Exception(unchecked((int)result), $"FwpmEngineOpen0 failed with WFP/Win32 error 0x{result:X8}."); + return engine; } } -- cgit v1.2.3