using System.Security.Cryptography; using System.Text.Json; using Mono.Cecil; using Mono.Cecil.Cil; if (args.Length != 1) throw new ArgumentException("GcRuntimePatch "); string runtimePath = Path.GetFullPath(args[0]); string? projectRoot = Path.GetDirectoryName(runtimePath); while (projectRoot is not null && !File.Exists(Path.Combine(projectRoot, "XFESystem.Kernel.csproj"))) projectRoot = Path.GetDirectoryName(projectRoot); if (projectRoot is null || Path.GetFileName(runtimePath) != "Cosmos.Kernel.Core.dll" || !runtimePath.StartsWith(Path.Combine(projectRoot, "obj") + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) || !Path.GetDirectoryName(runtimePath)!.EndsWith(Path.Combine("cosmos", "ref"), StringComparison.OrdinalIgnoreCase)) throw new ArgumentException("Only a project-local obj/cosmos/ref runtime copy may be patched."); for (string? path = runtimePath; path is not null && !path.Equals(projectRoot, StringComparison.OrdinalIgnoreCase); path = Path.GetDirectoryName(path)) if ((File.GetAttributes(path) & FileAttributes.ReparsePoint) != 0) throw new ArgumentException("The private copy cannot be reached through a symbolic link or junction."); string before = Hash(runtimePath); const string pinnedOriginalSha256 = "5d63cc0687931c69f0cb24740f02172e86b9e7664074d2f7b08fcf1a405c062e"; string receiptPath = runtimePath + ".XfeGc.json"; using var runtime = AssemblyDefinition.ReadAssembly(runtimePath, new ReaderParameters { InMemory = true }); if (runtime.Name.Name != "Cosmos.Kernel.Core" || runtime.Name.Version != new Version(3, 0, 94, 0)) throw new InvalidOperationException("This patch only supports the pinned Cosmos.Kernel.Core 3.0.94 assembly."); if (runtime.MainModule.Types.Single(type => type.FullName == "Cosmos.Kernel.Core.Runtime.ExceptionHandling.ExceptionHelper").Methods.Any(method => method.Name == "XfeTraceFirstExceptionTypesV1")) { if (!File.Exists(receiptPath)) throw new InvalidOperationException("An EH patch without its verification receipt is not trusted."); using var parsed = JsonDocument.Parse(File.ReadAllText(receiptPath)); if (parsed.RootElement.GetProperty("AfterSha256").GetString() != before || parsed.RootElement.GetProperty("EhCatchTrackingLimit").GetInt32() != EhRuntimePatch.Limit || parsed.RootElement.GetProperty("OriginalPinnedSha256").GetString() != pinnedOriginalSha256) throw new InvalidOperationException("The private runtime differs from its GC/EH verification receipt."); } var gc = runtime.MainModule.Types.Single(t => t.FullName == "Cosmos.Kernel.Core.Memory.GarbageCollector.GarbageCollector"); var target = gc.Methods.Single(m => m.Name == "PreciseScanFrameChain" && m.IsStatic && m.HasBody); var scan = gc.Methods.Single(m => m.Name == "ScanMemoryRange" && m.IsStatic && m.Parameters.Count == 2); const string helperName = "XfeScanPreciseTailFallbackV1"; var existing = gc.Methods.Where(m => m.Name == helperName).ToArray(); bool alreadyPatched = existing.Length != 0; if (alreadyPatched) { var hooks = target.Body.Instructions.Where(i => i.Operand is MethodReference method && method.FullName == existing[0].FullName).ToArray(); var helper = existing[0]; if (existing.Length != 1 || hooks.Length != 2 || !helper.HasBody || helper.Parameters.Count != 2 || helper.Parameters.Any(p => p.ParameterType.MetadataType != MetadataType.UIntPtr) || helper.Body.Instructions.Count != 9 || helper.Body.Instructions[1].OpCode != OpCodes.Brfalse || helper.Body.Instructions[4].OpCode != OpCodes.Bge_Un || helper.Body.Instructions[7].Operand is not MethodReference guardedScan || guardedScan.FullName != scan.FullName || hooks.Any(i => i.Next?.OpCode != OpCodes.Ret || i.Previous?.OpCode != OpCodes.Ldarg_2 || i.Previous.Previous?.OpCode != OpCodes.Ldloc || i.Previous.Previous.Operand is not VariableDefinition v || v.Index != 2)) throw new InvalidOperationException("An unexpected GC tail fallback patch already exists."); } else { // Exact pinned IL shape: the two truncating exits are 0x64 and 0x94. // All other exits already completed a conservative fallback, or stop after RunFrame did so. if (target.Body.CodeSize != 149 || target.Body.Instructions.Count != 75 || target.Body.Variables.Count != 6 || target.Body.Variables[2].VariableType.MetadataType != MetadataType.UIntPtr || target.Parameters.Count != 3 || target.Parameters[2].ParameterType.MetadataType != MetadataType.UIntPtr || !target.Body.Instructions.Any(i => i.Offset == 0x8d && i.OpCode == OpCodes.Ldc_I4 && Equals(i.Operand, 256))) throw new InvalidOperationException("Pinned precise stack scanner IL changed; refusing to guess an insertion point."); var invalidExit = target.Body.Instructions.Single(i => i.Offset == 0x64); var limitExit = target.Body.Instructions.Single(i => i.Offset == 0x94); if (invalidExit.OpCode != OpCodes.Ret || limitExit.OpCode != OpCodes.Ret || limitExit != target.Body.Instructions[^1] || target.Body.Instructions.Single(i => i.Offset == 0x65).OpCode != OpCodes.Ldloc_S) throw new InvalidOperationException("Pinned truncation exits changed."); var helper = new MethodDefinition(helperName, MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig, runtime.MainModule.TypeSystem.Void); helper.Parameters.Add(new ParameterDefinition("lastTrustedSp", ParameterAttributes.None, runtime.MainModule.TypeSystem.UIntPtr)); helper.Parameters.Add(new ParameterDefinition("stackEnd", ParameterAttributes.None, runtime.MainModule.TypeSystem.UIntPtr)); gc.Methods.Add(helper); var body = helper.Body.GetILProcessor(); var end = body.Create(OpCodes.Ret); body.Append(body.Create(OpCodes.Ldarg_0)); body.Append(body.Create(OpCodes.Brfalse, end)); body.Append(body.Create(OpCodes.Ldarg_0)); body.Append(body.Create(OpCodes.Ldarg_1)); body.Append(body.Create(OpCodes.Bge_Un, end)); body.Append(body.Create(OpCodes.Ldarg_0)); body.Append(body.Create(OpCodes.Ldarg_1)); body.Append(body.Create(OpCodes.Call, scan)); body.Append(end); helper.Body.MaxStackSize = 2; var il = target.Body.GetILProcessor(); foreach (var exit in new[] { invalidExit, limitExit }) { var first = il.Create(OpCodes.Ldloc, target.Body.Variables[2]); // Incoming branches used to target the ret directly. Redirect them to the fallback, // otherwise insertion alone would repair only fallthrough and leave invalid-CFI exits unscanned. foreach (var instruction in target.Body.Instructions) { if (ReferenceEquals(instruction.Operand, exit)) instruction.Operand = first; else if (instruction.Operand is Instruction[] table) for (int i = 0; i < table.Length; i++) if (ReferenceEquals(table[i], exit)) table[i] = first; } il.InsertBefore(exit, first); il.InsertBefore(exit, il.Create(OpCodes.Ldarg_2)); il.InsertBefore(exit, il.Create(OpCodes.Call, helper)); } target.Body.MaxStackSize = Math.Max(2, target.Body.MaxStackSize); // Added instructions can put short branch destinations out of their signed-byte range. foreach (var instruction in target.Body.Instructions) instruction.OpCode = instruction.OpCode.Code switch { Code.Br_S => OpCodes.Br, Code.Brfalse_S => OpCodes.Brfalse, Code.Brtrue_S => OpCodes.Brtrue, Code.Bne_Un_S => OpCodes.Bne_Un, Code.Bge_Un_S => OpCodes.Bge_Un, Code.Ble_Un_S => OpCodes.Ble_Un, Code.Blt_Un_S => OpCodes.Blt_Un, Code.Bgt_Un_S => OpCodes.Bgt_Un, Code.Blt_S => OpCodes.Blt, _ => instruction.OpCode }; } bool ehAlreadyPatched = EhRuntimePatch.Apply(runtime); bool threadStackAlreadyPatched = ThreadStackRuntimePatch.Apply(runtime); bool allocationAlreadyPatched = AllocationRuntimePatch.Apply(runtime); bool funcletEhAlreadyPatched = FuncletEhRuntimePatch.Apply(runtime); bool threadEhAlreadyPatched = ThreadEhRuntimePatch.Apply(runtime); bool frozenRangeAlreadyPatched = FrozenRangeRuntimePatch.Apply(runtime); bool gcMemoryAlreadyPatched = GcMemoryRuntimePatch.Apply(runtime); bool serialAlreadyPatched = SerialRuntimePatch.Apply(runtime); bool earlyBootConsoleAlreadyPatched = EarlyBootConsoleRuntimePatch.Apply(runtime); bool periodicSchedulerLogAlreadyPatched = PeriodicSchedulerLogPatch.Apply(runtime); // A stale receipt may accompany the official file after the Cosmos patcher restores it. // Trust that exact pinned file independently; retain stable provenance on repeat invocations. // Unknown files still undergo both shape checks before rejection, and cannot be partially written. if (!alreadyPatched && before != pinnedOriginalSha256) throw new InvalidOperationException("The unpatched private runtime is not the pinned original assembly."); if (alreadyPatched && !ehAlreadyPatched) { if (!File.Exists(receiptPath)) throw new InvalidOperationException("A previous GC patch needs its original verification receipt."); using var previous = JsonDocument.Parse(File.ReadAllText(receiptPath)); if (previous.RootElement.GetProperty("AfterSha256").GetString() != before || previous.RootElement.GetProperty("BeforeSha256").GetString() != pinnedOriginalSha256) throw new InvalidOperationException("The previous GC patch is not a verified pinned-origin private copy."); } if (!alreadyPatched || !ehAlreadyPatched || !allocationAlreadyPatched || !threadEhAlreadyPatched || !funcletEhAlreadyPatched || !threadStackAlreadyPatched || !gcMemoryAlreadyPatched || !frozenRangeAlreadyPatched || !serialAlreadyPatched || !earlyBootConsoleAlreadyPatched || !periodicSchedulerLogAlreadyPatched) { var temporary = runtimePath + ".XfeGc.tmp"; runtime.Write(temporary); File.Move(temporary, runtimePath, true); } var receipt = new { Kind = "ProjectLocalPreciseGcTailFallbackV1", RuntimePath = runtimePath, OriginalPinnedSha256 = pinnedOriginalSha256, BeforeSha256 = pinnedOriginalSha256, InputSha256 = before, AfterSha256 = Hash(runtimePath), AlreadyPatched = alreadyPatched, PinnedVersion = "3.0.94", TruncationExitsPatched = 2, LimitFrames = 256, PreciseScanPreserved = true, MarkOverflowRecoveryPreserved = true, GlobalPackageCacheModified = false, Fallback = "ScanMemoryRange(lastTrustedSp, threadStackEnd) only when lastTrustedSp != 0 && lastTrustedSp < threadStackEnd", RootCauseProven = false , EhCatchTrackingLimit = EhRuntimePatch.Limit, EhTrackerArrays = 3, EhOverflowFailFast = true, EhAlreadyPatched = ehAlreadyPatched, EhFirstDistinctTypeTraceLimit = EhRuntimePatch.TraceLimit, EhTraceIncludesUserMessage = false, EhTraceTypeIdentity = "Allocation-free EEType header + known exception category; duplicate types do not consume trace entries", AllocationGuardCount = 2, AllocationAlreadyPatched = allocationAlreadyPatched, ManagedAllocationGuardAfterIrqRestore = true, PreGcAllocationGuardBeforeMemSet = true, AllocationFailureAction = "Allocation-free FailFast: halt the entire guest; no recovery or process isolation guarantee", AllocationFailureRecoverySupported = false, AllocationFailureProcessIsolationSupported = false, FatalLogAndStopMasksInterrupts = true, FatalLogAndStopSingleCpuOnly = true , ThreadEhContextVersion = 1, ThreadEhStateFields = 8, ThreadEhArrayCount = 4, ThreadEhSwitchHook = "PerCpuState.set_CurrentThread", ThreadEhSwitchAllocates = false, ThreadEhSingleCpuOnly = true, ThreadEhAlreadyPatched = threadEhAlreadyPatched, RawThreadStackAllocationGuard = true, RawThreadStackAlreadyPatched = threadStackAlreadyPatched, RawThreadStackAllocationFailureHaltsGuest = true, RawPhysicalPageCountExports = true, RawThreadStackCollectAndRetryOnce = true, RawLargestFreeRunDiagnosticMasksInterrupts = true, GcStopTheWorldWithInterruptsMasked = true, ConcurrentGcSupported = false , EhFuncletRootResolution = true, EhFuncletRootResolutionAlreadyPatched = funcletEhAlreadyPatched, GcMetadataLookupContractChanged = false , CompletedGcSnapshotLeafExports = 4, CompletedGcSnapshotReadOnly = true, GcMemoryAlreadyPatched = gcMemoryAlreadyPatched , DependentHandleCountReadOnlyExport = true , FrozenUpdateAcceptsAbsoluteEndAddresses = true, FrozenUpdateNormalizesByteCounts = true, FrozenUpdateValidatesUnsignedRange = true, FrozenRangeAlreadyPatched = frozenRangeAlreadyPatched , SerialFinitePolling = true, SerialPollLimit = SerialRuntimePatch.PollLimit, SerialAlreadyPatched = serialAlreadyPatched, SerialMissingStatus = "0xFF", SerialFailureDisablesOutputForThisBoot = true, SerialNewHardwareProbeWrites = false, SerialInitializationPreserved = true, SerialCounterExports = 4, EarlyBootConsoleAlreadyPatched = earlyBootConsoleAlreadyPatched, EarlyBootConsoleLeafExports = 2, EarlyBootConsoleChangesSystemStart = false, PeriodicSchedulerLogAlreadyPatched = periodicSchedulerLogAlreadyPatched, PeriodicSchedulerLogSuppressed = true, PeriodicSchedulerLogChangedInstructions = 1, PeriodicSchedulerOriginalOnTickSha256 = PeriodicSchedulerLogPatch.OriginalMethodSha256, SchedulerTickCounterAndAccountingPreserved = true, SchedulerPreemptionPreserved = false, SchedulerPassBasedPreemptionPreserved = true, SchedulerForcedTimesliceAdjusted = true, SchedulerForcedTimesliceNanoseconds = PeriodicSchedulerLogPatch.ForcedTimesliceNanoseconds, SchedulerTimesliceChangedInstructionIndex = PeriodicSchedulerLogPatch.TimesliceInstructionIndex, SchedulerStrideAccountingDivisorNanoseconds = 10_000_000, SchedulerTimeslicePolicy = "Terminal actual elapsed >= 1 ms forces runnable-thread rotation; 10 ms Stride weights and real elapsed accounting unchanged", PhysicalBootAcceptancePassed = false }; File.WriteAllText(receiptPath + ".tmp", JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true })); File.Move(receiptPath + ".tmp", receiptPath, true); Console.WriteLine("XFE precise GC tail fallback ready; native regression still required."); Console.WriteLine("XFE active EH catch tracking limit 4096 ready; native deep-rethrow regression still required."); Console.WriteLine("XFE allocation failure guards ready; out of memory halts the entire guest without allocation or recovery."); Console.WriteLine("XFE bounded serial output ready; absence or stuck UART disables diagnostics, never waits forever."); Console.WriteLine("XFE scheduler periodic debug output skipped; explicit 1 ms forced rotation with real elapsed accounting and 10 ms Stride weight divisor."); static string Hash(string path) => Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(path)));