mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-16 00:40:59 +00:00
core: implement coalesced writes for gettimeofday and set POSIX EFAULT (#70)
Follow-up task to enforce coalesced guest memory writes within the gettimeofday subsystem, removing remaining partial-write risks on virtual memory page boundaries. * sceKernelGettimeofday Hardening: Replaced consecutive isolated 8-byte scalar writes with a single 16-byte coalesced transaction buffer using stackalloc byte[16] and BinaryPrimitives. It preserves native Orbis semantics by returning ORBIS_GEN2_ERROR_MEMORY_FAULT on failure states without side-effect partial-writes. * POSIX gettimeofday Compliance: - Applied the identical single-transaction 16-byte write pattern for the timeval structure. - Implemented a single 8-byte coalesced zero-fill transaction for the deprecated/legacy timezone buffer (timezoneAddress != 0) using BinaryPrimitives.WriteInt32LittleEndian, aligning it with standard FreeBSD stub behavior. - Integrated proper TrySetErrno(ctx, Efault) tracking upon write failures. The method safely omits explicit manual Rax writes on error paths, allowing the import dispatcher to cleanly sign-extend the return -1 value to 0xFFFFFFFFFFFFFFFF. Out of scope: Subsystem clock and timeval validation is now fully complete; no further temporal partial-write vulnerabilities remain within the core runtime memory compat layers. Files: KernelRuntimeCompatExports.cs
This commit is contained in:
@@ -14,6 +14,7 @@ namespace SharpEmu.Libs.Kernel;
|
||||
|
||||
public static class KernelRuntimeCompatExports
|
||||
{
|
||||
private const int Efault = 14;
|
||||
private const ulong TlsErrnoOffset = 0x40;
|
||||
private const ulong TlsStackChkGuardBaseOffset = 0x800;
|
||||
private const ulong StackChkGuardFieldOffset = 0x10;
|
||||
@@ -226,8 +227,11 @@ public static class KernelRuntimeCompatExports
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var seconds = now.ToUnixTimeSeconds();
|
||||
var microseconds = (now.Ticks % TimeSpan.TicksPerSecond) / 10;
|
||||
if (!ctx.TryWriteUInt64(timeAddress, unchecked((ulong)seconds)) ||
|
||||
!ctx.TryWriteUInt64(timeAddress + sizeof(long), unchecked((ulong)microseconds)))
|
||||
|
||||
Span<byte> timevalBuffer = stackalloc byte[16];
|
||||
BinaryPrimitives.WriteInt64LittleEndian(timevalBuffer, seconds);
|
||||
BinaryPrimitives.WriteInt64LittleEndian(timevalBuffer[sizeof(long)..], microseconds);
|
||||
if (!ctx.Memory.TryWrite(timeAddress, timevalBuffer))
|
||||
{
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||
}
|
||||
@@ -249,18 +253,28 @@ public static class KernelRuntimeCompatExports
|
||||
var seconds = now.ToUnixTimeSeconds();
|
||||
var microseconds = (now.Ticks % TimeSpan.TicksPerSecond) / 10;
|
||||
|
||||
if (timeAddress != 0 &&
|
||||
(!ctx.TryWriteUInt64(timeAddress, unchecked((ulong)seconds)) ||
|
||||
!ctx.TryWriteUInt64(timeAddress + sizeof(long), unchecked((ulong)microseconds))))
|
||||
if (timeAddress != 0)
|
||||
{
|
||||
return -1;
|
||||
Span<byte> timevalBuffer = stackalloc byte[16];
|
||||
BinaryPrimitives.WriteInt64LittleEndian(timevalBuffer, seconds);
|
||||
BinaryPrimitives.WriteInt64LittleEndian(timevalBuffer[sizeof(long)..], microseconds);
|
||||
if (!ctx.Memory.TryWrite(timeAddress, timevalBuffer))
|
||||
{
|
||||
TrySetErrno(ctx, Efault);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (timezoneAddress != 0 &&
|
||||
(!ctx.TryWriteInt32(timezoneAddress, 0) ||
|
||||
!ctx.TryWriteInt32(timezoneAddress + sizeof(int), 0)))
|
||||
if (timezoneAddress != 0)
|
||||
{
|
||||
return -1;
|
||||
Span<byte> timezoneBuffer = stackalloc byte[8];
|
||||
BinaryPrimitives.WriteInt32LittleEndian(timezoneBuffer, 0);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(timezoneBuffer[sizeof(int)..], 0);
|
||||
if (!ctx.Memory.TryWrite(timezoneAddress, timezoneBuffer))
|
||||
{
|
||||
TrySetErrno(ctx, Efault);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ctx[CpuRegister.Rax] = 0;
|
||||
|
||||
Reference in New Issue
Block a user