XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Security.Cryptography;
using System.Text.Json;
using Mono.Cecil;
using Mono.Cecil.Cil;

if (args.Length != 1) throw new ArgumentException("GcRuntimePatch <private obj/cosmos/ref/Cosmos.Kernel.Core.dll>");
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)));