mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-23 03:16:22 +08:00
[Kernel] Preserve socket descriptors after failed connect (#343)
Keep ownership of a socket descriptor with the guest when connect fails, and route generic close calls through the socket table. Add a deterministic regression test for the failure and close sequence. Signed-off-by: missatjuhvdk1 <177474143+missatjuhvdk1@users.noreply.github.com> Co-authored-by: missatjuhvdk1 <177474143+missatjuhvdk1@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
81633f6d5a
commit
ecbb0db9be
@@ -1966,6 +1966,12 @@ public static partial class KernelMemoryCompatExports
|
|||||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (KernelSocketCompatExports.TryCloseSocketFd(fd))
|
||||||
|
{
|
||||||
|
ctx[CpuRegister.Rax] = 0;
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
FileStream? stream;
|
FileStream? stream;
|
||||||
lock (_fdGate)
|
lock (_fdGate)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -160,7 +160,6 @@ internal static class KernelSocketCompatExports
|
|||||||
if (!TryParseGuestSockaddrIn(sockaddrAddress, addrlen, ctx, out var ipAddress, out var port))
|
if (!TryParseGuestSockaddrIn(sockaddrAddress, addrlen, ctx, out var ipAddress, out var port))
|
||||||
{
|
{
|
||||||
LogNet($"connect sockaddr parse failed: fd={fd} addr=0x{sockaddrAddress:X} len={addrlen}");
|
LogNet($"connect sockaddr parse failed: fd={fd} addr=0x{sockaddrAddress:X} len={addrlen}");
|
||||||
RemoveEmulatedSocketFd(fd);
|
|
||||||
ctx[CpuRegister.Rax] = unchecked((ulong)0xFFFFFFFFFFFFFFFF);
|
ctx[CpuRegister.Rax] = unchecked((ulong)0xFFFFFFFFFFFFFFFF);
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
}
|
}
|
||||||
@@ -174,7 +173,6 @@ internal static class KernelSocketCompatExports
|
|||||||
if (!IsGuestTcpOutboundAllowed(ipAddress, redirectApplied))
|
if (!IsGuestTcpOutboundAllowed(ipAddress, redirectApplied))
|
||||||
{
|
{
|
||||||
LogNet($"connect denied by outbound policy: fd={fd} ip={ipAddress} port={port}");
|
LogNet($"connect denied by outbound policy: fd={fd} ip={ipAddress} port={port}");
|
||||||
RemoveEmulatedSocketFd(fd);
|
|
||||||
ctx[CpuRegister.Rax] = unchecked((ulong)0xFFFFFFFFFFFFFFFF);
|
ctx[CpuRegister.Rax] = unchecked((ulong)0xFFFFFFFFFFFFFFFF);
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
}
|
}
|
||||||
@@ -182,7 +180,6 @@ internal static class KernelSocketCompatExports
|
|||||||
if (!TryEstablishHostTcpConnection(ipAddress, port, out var client, out var stream))
|
if (!TryEstablishHostTcpConnection(ipAddress, port, out var client, out var stream))
|
||||||
{
|
{
|
||||||
LogNet($"connect failed: fd={fd} ip={ipAddress} port={port}");
|
LogNet($"connect failed: fd={fd} ip={ipAddress} port={port}");
|
||||||
RemoveEmulatedSocketFd(fd);
|
|
||||||
ctx[CpuRegister.Rax] = unchecked((ulong)0xFFFFFFFFFFFFFFFF);
|
ctx[CpuRegister.Rax] = unchecked((ulong)0xFFFFFFFFFFFFFFFF);
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
}
|
}
|
||||||
@@ -418,17 +415,6 @@ internal static class KernelSocketCompatExports
|
|||||||
state.Connected = false;
|
state.Connected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RemoveEmulatedSocketFd(int fd)
|
|
||||||
{
|
|
||||||
lock (Gate)
|
|
||||||
{
|
|
||||||
if (Sockets.Remove(fd, out var socketState))
|
|
||||||
{
|
|
||||||
DisposeEmulatedSocket(socketState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void LogNet(string message)
|
private static void LogNet(string message)
|
||||||
{
|
{
|
||||||
if (string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_NET"), "1", StringComparison.Ordinal))
|
if (string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_NET"), "1", StringComparison.Ordinal))
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
using SharpEmu.HLE;
|
||||||
|
using SharpEmu.Libs.Kernel;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace SharpEmu.Libs.Tests.Kernel;
|
||||||
|
|
||||||
|
public sealed class KernelSocketCompatExportsTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Connect_InvalidSockaddrLeavesFdOpenForGuestClose()
|
||||||
|
{
|
||||||
|
const ulong memoryBase = 0x0000_7FFF_3000_0000;
|
||||||
|
var context = new CpuContext(new FakeCpuMemory(memoryBase, 0x1000), Generation.Gen5);
|
||||||
|
context[CpuRegister.Rdi] = 2;
|
||||||
|
context[CpuRegister.Rsi] = 1;
|
||||||
|
context[CpuRegister.Rdx] = 6;
|
||||||
|
|
||||||
|
Assert.Equal(0, KernelSocketCompatExports.Socket(context));
|
||||||
|
Assert.NotEqual(ulong.MaxValue, context[CpuRegister.Rax]);
|
||||||
|
var guestFd = checked((int)context[CpuRegister.Rax]);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
context[CpuRegister.Rdi] = unchecked((ulong)guestFd);
|
||||||
|
context[CpuRegister.Rsi] = memoryBase;
|
||||||
|
context[CpuRegister.Rdx] = 0;
|
||||||
|
|
||||||
|
Assert.Equal(0, KernelSocketCompatExports.Connect(context));
|
||||||
|
Assert.Equal(ulong.MaxValue, context[CpuRegister.Rax]);
|
||||||
|
|
||||||
|
context[CpuRegister.Rdi] = unchecked((ulong)guestFd);
|
||||||
|
Assert.Equal(
|
||||||
|
(int)OrbisGen2Result.ORBIS_GEN2_OK,
|
||||||
|
KernelMemoryCompatExports.PosixClose(context));
|
||||||
|
Assert.Equal(0UL, context[CpuRegister.Rax]);
|
||||||
|
|
||||||
|
context[CpuRegister.Rdi] = unchecked((ulong)guestFd);
|
||||||
|
Assert.Equal(
|
||||||
|
(int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND,
|
||||||
|
KernelMemoryCompatExports.PosixClose(context));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
KernelSocketCompatExports.TryCloseSocketFd(guestFd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user