mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-29 06:00:58 +08:00
[CPU] Reject context transfers to unmapped guest addresses (#273)
This commit is contained in:
@@ -1768,14 +1768,16 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
frameAddress = 0;
|
frameAddress = 0;
|
||||||
transferStub = 0;
|
transferStub = 0;
|
||||||
error = null;
|
error = null;
|
||||||
if (target.Rip < 65536 || target.Rsp == 0)
|
if (ActiveCpuContext is not { } activeContext)
|
||||||
{
|
{
|
||||||
error = $"invalid guest context transfer target rip=0x{target.Rip:X16} rsp=0x{target.Rsp:X16}";
|
error = "guest context transfer without an active CPU context";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (target.Rsp < sizeof(ulong) ||
|
if (!TryValidateGuestContextTransferTarget(activeContext.Memory, target, out error))
|
||||||
ActiveCpuContext is not { } activeContext ||
|
{
|
||||||
!activeContext.TryWriteUInt64(target.Rsp - sizeof(ulong), target.Rip))
|
return false;
|
||||||
|
}
|
||||||
|
if (!activeContext.TryWriteUInt64(target.Rsp - sizeof(ulong), target.Rip))
|
||||||
{
|
{
|
||||||
error = $"guest context transfer slot is not writable at 0x{target.Rsp - sizeof(ulong):X16}";
|
error = $"guest context transfer slot is not writable at 0x{target.Rsp - sizeof(ulong):X16}";
|
||||||
return false;
|
return false;
|
||||||
@@ -1819,6 +1821,30 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool TryValidateGuestContextTransferTarget(
|
||||||
|
ICpuMemory memory,
|
||||||
|
in GuestCpuContinuation target,
|
||||||
|
out string? error)
|
||||||
|
{
|
||||||
|
if (target.Rip < 65536 || target.Rsp < sizeof(ulong))
|
||||||
|
{
|
||||||
|
error = $"invalid guest context transfer target rip=0x{target.Rip:X16} rsp=0x{target.Rsp:X16}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<byte> ripProbe = stackalloc byte[1];
|
||||||
|
if (!memory.TryRead(target.Rip, ripProbe))
|
||||||
|
{
|
||||||
|
error =
|
||||||
|
$"guest context transfer target rip=0x{target.Rip:X16} is not mapped guest memory " +
|
||||||
|
$"(rsp=0x{target.Rsp:X16})";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private unsafe nint GetOrCreateGuestContextTransferStub()
|
private unsafe nint GetOrCreateGuestContextTransferStub()
|
||||||
{
|
{
|
||||||
if (Volatile.Read(ref _guestContextTransferStub) != 0)
|
if (Volatile.Read(ref _guestContextTransferStub) != 0)
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
<PackageReference Include="Iced" />
|
<PackageReference Include="Iced" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<InternalsVisibleTo Include="SharpEmu.Libs.Tests" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<NoWarn>$(NoWarn);1591</NoWarn>
|
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
using SharpEmu.Core.Cpu.Native;
|
||||||
|
using SharpEmu.HLE;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace SharpEmu.Libs.Tests.Cpu;
|
||||||
|
|
||||||
|
public sealed class GuestContextTransferValidationTests
|
||||||
|
{
|
||||||
|
private const ulong MemoryBase = 0x1_0000_0000;
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MappedGuestInstructionPointer_IsAccepted()
|
||||||
|
{
|
||||||
|
var memory = new FakeCpuMemory(MemoryBase, 0x1000);
|
||||||
|
var continuation = CreateContinuation(MemoryBase + 0x100, MemoryBase + 0x800);
|
||||||
|
|
||||||
|
Assert.True(DirectExecutionBackend.TryValidateGuestContextTransferTarget(
|
||||||
|
memory,
|
||||||
|
continuation,
|
||||||
|
out var error));
|
||||||
|
Assert.Null(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void UnmappedGuestInstructionPointer_IsRejected()
|
||||||
|
{
|
||||||
|
var memory = new FakeCpuMemory(MemoryBase, 0x1000);
|
||||||
|
var continuation = CreateContinuation(MemoryBase + 0x2000, MemoryBase + 0x800);
|
||||||
|
|
||||||
|
Assert.False(DirectExecutionBackend.TryValidateGuestContextTransferTarget(
|
||||||
|
memory,
|
||||||
|
continuation,
|
||||||
|
out var error));
|
||||||
|
Assert.Contains("not mapped guest memory", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(0UL, MemoryBase + 0x800)]
|
||||||
|
[InlineData(MemoryBase + 0x100, 0UL)]
|
||||||
|
public void InvalidInstructionOrStackPointer_IsRejected(ulong rip, ulong rsp)
|
||||||
|
{
|
||||||
|
var memory = new FakeCpuMemory(MemoryBase, 0x1000);
|
||||||
|
var continuation = CreateContinuation(rip, rsp);
|
||||||
|
|
||||||
|
Assert.False(DirectExecutionBackend.TryValidateGuestContextTransferTarget(
|
||||||
|
memory,
|
||||||
|
continuation,
|
||||||
|
out var error));
|
||||||
|
Assert.Contains("invalid guest context transfer target", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GuestCpuContinuation CreateContinuation(ulong rip, ulong rsp) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Rip = rip,
|
||||||
|
Rsp = rsp,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user