mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-02 12:32:03 +01:00
sceNetResolver: Don't fault on a NULL address, and check arguments
sceNetResolverStartNtoA with a NULL address pointer wrote to address 0 and stopped the game. From pspautotests net/inet/offline, recorded on a PSP: a NULL name or address gives INVALID_PTR, an empty name 0x80410418, a NULL buffer in Create INVALID_PTR, and Stop with nothing running ALREADY_STOPPED (the check was inverted). PollAsync and WaitAsync check the resolver ID, and PollAsync its status pointer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0904b47639
commit
8a48a157d4
1 file changed
+38
-2
@@ -85,6 +85,17 @@ static int sceNetResolverTerm() {
|
||||
|
||||
// TODO: Add DoState, store the ID gen and active resolvers.
|
||||
|
||||
// Checked after the resolver ID (pspautotests net/inet/offline).
|
||||
static int CheckNtoAArgs(u32 hostnamePtr, u32 inAddrPtr) {
|
||||
if (!Memory::IsValidAddress(hostnamePtr) || !Memory::IsValidRange(inAddrPtr, 4)) {
|
||||
return SCE_NET_RESOLVER_ERROR_INVALID_PTR;
|
||||
}
|
||||
if (Memory::ReadUnchecked_U8(hostnamePtr) == 0) {
|
||||
return 0x80410418; // An empty name.
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Note: timeouts are in seconds
|
||||
static int NetResolver_StartNtoA(NetResolver *resolver, u32 hostnamePtr, u32 inAddrPtr, int timeout, int retry) {
|
||||
std::string hostname = std::string(safe_string(Memory::GetCharPointer(hostnamePtr)));
|
||||
@@ -133,6 +144,10 @@ static int sceNetResolverStartNtoA(int resolverId, u32 hostnamePtr, u32 inAddrPt
|
||||
return hleLogError(Log::sceNet, SCE_NET_RESOLVER_ERROR_BAD_ID, "Bad Resolver Id: %i", resolverId);
|
||||
}
|
||||
|
||||
if (int error = CheckNtoAArgs(hostnamePtr, inAddrPtr)) {
|
||||
return hleLogError(Log::sceNet, error);
|
||||
}
|
||||
|
||||
for (int attempt = 0; attempt < retry; ++attempt) {
|
||||
const int status = NetResolver_StartNtoA(&iter->second, hostnamePtr, inAddrPtr, timeout, retry);
|
||||
if (status >= 0) {
|
||||
@@ -152,6 +167,10 @@ static int sceNetResolverStartNtoAAsync(int resolverId, u32 hostnamePtr, u32 inA
|
||||
return hleLogError(Log::sceNet, SCE_NET_RESOLVER_ERROR_BAD_ID, "Bad Resolver Id: %i", resolverId);
|
||||
}
|
||||
|
||||
if (int error = CheckNtoAArgs(hostnamePtr, inAddrPtr)) {
|
||||
return hleLogError(Log::sceNet, error);
|
||||
}
|
||||
|
||||
const int status = NetResolver_StartNtoA(&iter->second, hostnamePtr, inAddrPtr, timeout, retry);
|
||||
return hleLogDebugOrError(Log::sceNet, status);
|
||||
}
|
||||
@@ -161,6 +180,14 @@ static int sceNetResolverPollAsync(int resolverId, u32 unknown) {
|
||||
return hleLogError(Log::sceNet, SCE_NET_RESOLVER_ERROR_STOPPED, "Resolver subsystem not running");
|
||||
}
|
||||
|
||||
// pspautotests net/inet/offline
|
||||
if (g_netResolvers.find(resolverId) == g_netResolvers.end()) {
|
||||
return hleLogError(Log::sceNet, SCE_NET_RESOLVER_ERROR_BAD_ID, "Bad Resolver Id: %i", resolverId);
|
||||
}
|
||||
if (!Memory::IsValidRange(unknown, 4)) {
|
||||
return hleLogError(Log::sceNet, 0x80410419, "NULL status");
|
||||
}
|
||||
|
||||
// TODO: Implement after confirming that this returns the state of resolver.isRunning
|
||||
return hleLogError(Log::sceNet, 0, "UNIMPL");
|
||||
}
|
||||
@@ -170,6 +197,10 @@ static int sceNetResolverWaitAsync(int resolverId, u32 unknown) {
|
||||
return hleLogError(Log::sceNet, SCE_NET_RESOLVER_ERROR_STOPPED, "Resolver subsystem not running");
|
||||
}
|
||||
|
||||
if (g_netResolvers.find(resolverId) == g_netResolvers.end()) {
|
||||
return hleLogError(Log::sceNet, SCE_NET_RESOLVER_ERROR_BAD_ID, "Bad Resolver Id: %i", resolverId);
|
||||
}
|
||||
|
||||
// TODO: Implement after confirming that this blocks current thread until resolver.isRunning flips to false
|
||||
return hleLogError(Log::sceNet, 0, "UNIMPL");
|
||||
}
|
||||
@@ -193,7 +224,11 @@ static int sceNetResolverCreate(u32 resolverIdPtr, u32 bufferPtr, int bufferLen)
|
||||
if (!Memory::IsValidRange(resolverIdPtr, 4))
|
||||
return hleLogError(Log::sceNet, SCE_NET_RESOLVER_ERROR_INVALID_PTR, "Invalid Ptr: %08x", resolverIdPtr);
|
||||
|
||||
if (Memory::IsValidRange(bufferPtr, 4) && bufferLen < 1)
|
||||
// A buffer is required (pspautotests net/inet/offline).
|
||||
if (!Memory::IsValidAddress(bufferPtr))
|
||||
return hleLogError(Log::sceNet, SCE_NET_RESOLVER_ERROR_INVALID_PTR, "Invalid buffer: %08x", bufferPtr);
|
||||
|
||||
if (bufferLen < 1)
|
||||
return hleLogError(Log::sceNet, SCE_NET_RESOLVER_ERROR_INVALID_BUFLEN, "Invalid Buffer Length: %i", bufferLen);
|
||||
|
||||
// Outrun calls this without init. Something else must have initialized it, unclear what.
|
||||
@@ -223,7 +258,8 @@ static int sceNetResolverStop(u32 resolverId) {
|
||||
return hleLogError(Log::sceNet, SCE_NET_RESOLVER_ERROR_BAD_ID, "Bad Resolver Id: %i", resolverId);
|
||||
}
|
||||
|
||||
if (resolverIter->second.isRunning) {
|
||||
// Nothing to stop (pspautotests net/inet/offline).
|
||||
if (!resolverIter->second.isRunning) {
|
||||
return hleLogError(Log::sceNet, SCE_NET_RESOLVER_ERROR_ALREADY_STOPPED, "Resolver Already Stopped (Id: %i)", resolverId);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user