diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index a29af02f21..cc6abb39d7 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -921,19 +921,6 @@ template void WrapI_ICI(MIPSState *mips) { RETURN(retval); } -template void WrapI_IVVVVUI(MIPSState *mips) { - // Any of the pointers may be NULL (sceNetAdhocPdpRecv takes NULL for the sender), so don't fault on it. - auto ptr = [](u32 addr) -> void * { return addr ? Memory::GetPointerWriteOrException(addr) : nullptr; }; - u32 retval = HLECall(mips, PARAM(0), ptr(PARAM(1)), ptr(PARAM(2)), ptr(PARAM(3)), ptr(PARAM(4)), PARAM(5), PARAM(6) ); - RETURN(retval); -} - -template void WrapI_ICUVIII(MIPSState *mips) { - // The buffer may be NULL (sceNetAdhocPdpSend with a length of 0 is fine with that), so don't fault on it. - u32 retval = HLECall(mips, PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3) ? Memory::GetPointerWriteOrException(PARAM(3)) : nullptr, PARAM(4), PARAM(5), PARAM(6)); - RETURN(retval); -} - template void WrapI_VUI(MIPSState *mips) { u32 retval = HLECall(mips, Memory::GetPointerWriteOrException(PARAM(0)), PARAM(1), PARAM(2)); RETURN(retval); diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index 9fd16d1292..9a06cbd400 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -2551,7 +2551,8 @@ int sceNetAdhocPollSocket(MIPSState *mips, u32 socketStructAddr, int count, int if (netAdhocInited) { SceNetAdhocPollSd * sds = NULL; - if (Memory::IsValidAddress(socketStructAddr)) sds = (SceNetAdhocPollSd *)Memory::GetPointerOrException(socketStructAddr); + const u64 sdsSize = (u64)std::max(count, 0) * sizeof(SceNetAdhocPollSd); + if (sdsSize <= 0x10000000 && Memory::IsValidRange(socketStructAddr, (u32)sdsSize)) sds = (SceNetAdhocPollSd *)Memory::GetPointerOrException(socketStructAddr); // Valid Arguments if (sds != NULL && count > 0) @@ -3062,7 +3063,7 @@ static int sceNetAdhocctlGetNameByAddr(MIPSState *mips, const char *mac, u32 nam if (netAdhocctlInited) { // Valid Arguments - if (mac != NULL && Memory::IsValidAddress(nameAddr)) + if (mac != NULL && Memory::IsValidRange(nameAddr, sizeof(SceNetAdhocctlNickname))) { SceNetAdhocctlNickname * nickname = (SceNetAdhocctlNickname *)Memory::GetPointerOrException(nameAddr); // Get Local MAC Address @@ -3124,7 +3125,7 @@ int sceNetAdhocctlGetPeerInfo(MIPSState *mips, const char *mac, int size, u32 pe SceNetEtherAddr * maddr = (SceNetEtherAddr *)mac; SceNetAdhocctlPeerInfoEmu * buf = NULL; - if (Memory::IsValidAddress(peerInfoAddr)) { + if (Memory::IsValidRange(peerInfoAddr, sizeof(SceNetAdhocctlPeerInfoEmu))) { buf = (SceNetAdhocctlPeerInfoEmu *)Memory::GetPointerOrException(peerInfoAddr); } // Library initialized @@ -3283,7 +3284,7 @@ int sceNetAdhocctlJoin(MIPSState *mips, u32 scanInfoAddr) { if (netAdhocctlInited) { // Valid Argument - if (Memory::IsValidAddress(scanInfoAddr)) + if (Memory::IsValidRange(scanInfoAddr, sizeof(SceNetAdhocctlScanInfoEmu))) { SceNetAdhocctlScanInfoEmu* sinfo = (SceNetAdhocctlScanInfoEmu*)Memory::GetPointerOrException(scanInfoAddr); char grpName[ADHOCCTL_GROUPNAME_LEN + 1] = { 0 }; @@ -3524,7 +3525,7 @@ static int sceNetAdhocGetPdpStat(MIPSState *mips, u32 structSize, u32 structAddr else if (buflen != NULL && buf != NULL) { // Figure out how many Sockets we will return - int count = *buflen / sizeof(SceNetAdhocPdpStat); + int count = Memory::ClampValidSizeAt(structAddr, std::max((s32)*buflen, 0)) / sizeof(SceNetAdhocPdpStat); if (count > socketcount) count = socketcount; // Copy Counter @@ -3611,7 +3612,7 @@ static int sceNetAdhocGetPtpStat(MIPSState *mips, u32 structSize, u32 structAddr // Status Returner Mode else if (buflen != NULL && buf != NULL) { // Figure out how many Sockets we will return - int count = *buflen / sizeof(SceNetAdhocPtpStat); + int count = Memory::ClampValidSizeAt(structAddr, std::max((s32)*buflen, 0)) / sizeof(SceNetAdhocPtpStat); if (count > socketcount) count = socketcount; // Copy Counter @@ -4318,7 +4319,7 @@ static int sceNetAdhocPtpSend(MIPSState *mips, int id, u32 dataAddr, u32 dataSiz if (*len == 0) { return hleLogDebug(Log::sceNet, 0, "nothing to send"); } - if (*len < 0 || data == NULL) { + if (*len < 0 || data == NULL || !Memory::IsValidRange(dataAddr, *len)) { return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_DATALEN, "invalid data length"); } // Valid Arguments @@ -4374,7 +4375,7 @@ static int sceNetAdhocPtpRecv(MIPSState *mips, int id, u32 dataAddr, u32 dataSiz // Library is initialized if (netAdhocInited) { // Valid Arguments - if (buf != NULL && len != NULL && *len > 0) { + if (buf != NULL && len != NULL && *len > 0 && Memory::IsValidRange(dataAddr, *len)) { // Valid Socket if (id > 0 && id <= MAX_SOCKET && adhocSockets[id - 1] != NULL) { // Cast Socket @@ -4678,7 +4679,7 @@ static int sceNetAdhocGameModeUpdateReplica(MIPSState *mips, int id, u32 infoAdd // Bomberman Panic Bomber is using 0/null on infoAddr, so i guess it's optional. GameModeUpdateInfo* gmuinfo = NULL; - if (Memory::IsValidAddress(infoAddr)) { + if (Memory::IsValidRange(infoAddr, sizeof(GameModeUpdateInfo))) { gmuinfo = (GameModeUpdateInfo*)Memory::GetPointerOrException(infoAddr); } @@ -4836,13 +4837,31 @@ void __NetTriggerCallbacks() hleNoLogVoid(); } +// The game's buffer, if all of it is valid memory, else NULL, which the calls treat as missing. +static void *GuestBuffer(u32 addr, int size) { + return Memory::IsValidRange(addr, std::max(size, 1)) ? Memory::GetPointerWriteUnchecked(addr) : nullptr; +} + +// The PDP syscalls check the game's buffers here, since game mode calls the functions with host ones. +static int sceNetAdhocPdpSendSyscall(MIPSState *mips, int id, u32 macAddr, u32 port, u32 dataAddr, u32 len, u32 timeout, u32 flag) { + void *data = dataAddr ? GuestBuffer(dataAddr, (int)len) : nullptr; + return sceNetAdhocPdpSend(mips, id, (const char *)GuestBuffer(macAddr, ETHER_ADDR_LEN), port, data, (int)len, (int)timeout, (int)flag); +} + +static int sceNetAdhocPdpRecvSyscall(MIPSState *mips, int id, u32 macAddr, u32 portAddr, u32 bufAddr, u32 lenAddr, u32 timeout, u32 flag) { + void *len = GuestBuffer(lenAddr, 4); + void *buf = GuestBuffer(bufAddr, len ? *(s32_le *)len : 0); + // NULL for the sender's MAC and port is fine. + return sceNetAdhocPdpRecv(mips, id, macAddr ? GuestBuffer(macAddr, ETHER_ADDR_LEN) : nullptr, portAddr ? GuestBuffer(portAddr, 2) : nullptr, buf, len, timeout, (int)flag); +} + const HLEFunction sceNetAdhoc[] = { {0XE1D621D7, &WrapU_V, "sceNetAdhocInit", 'x', "" }, {0XA62C6F57, &WrapI_V, "sceNetAdhocTerm", 'i', "" }, {0X0AD043ED, &WrapI_C, "sceNetAdhocctlConnect", 'i', "s" }, {0X6F92741B, &WrapI_CIIU, "sceNetAdhocPdpCreate", 'i', "siix" }, - {0XABED3790, &WrapI_ICUVIII, "sceNetAdhocPdpSend", 'i', "isxpiii" }, - {0XDFE53E03, &WrapI_IVVVVUI, "sceNetAdhocPdpRecv", 'i', "ippppxi" }, + {0XABED3790, &WrapI_IUUUUUU, "sceNetAdhocPdpSend", 'i', "ixxxiii" }, + {0XDFE53E03, &WrapI_IUUUUUU, "sceNetAdhocPdpRecv", 'i', "ixxxxxi" }, {0X7F27BB5E, &WrapI_II, "sceNetAdhocPdpDelete", 'i', "ii" }, {0XC7C1FC57, &WrapI_UU, "sceNetAdhocGetPdpStat", 'i', "xx" }, {0X157E6225, &WrapI_II, "sceNetAdhocPtpClose", 'i', "ii" }, @@ -4897,7 +4916,7 @@ static int sceNetAdhocctlGetGameModeInfo(u32 infoAddr) { if (!netAdhocctlInited) return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_NOT_INITIALIZED, "not initialized"); - if (!Memory::IsValidAddress(infoAddr)) + if (!Memory::IsValidRange(infoAddr, sizeof(SceNetAdhocctlGameModeInfo))) return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_INVALID_ARG, "invalid arg"); // pspautotests net/adhoc/gamemode @@ -4961,13 +4980,16 @@ static int sceNetAdhocctlGetPeerList(MIPSState *mips, u32 sizeAddr, u32 bufAddr) // Discovery Counter int discovered = 0; + // Only the part of the buffer that's valid memory. + const u32 validLen = Memory::ClampValidSizeAt(bufAddr, std::max((s32)*buflen, 0)); + // Calculate Request Count - int requestcount = *buflen / sizeof(SceNetAdhocctlPeerInfoEmu); + int requestcount = validLen / sizeof(SceNetAdhocctlPeerInfoEmu); // FIXME: When bufAddr is not null but buffer size is smaller than activePeers * sizeof(SceNetAdhocctlPeerInfoEmu), simply return buffer size = 0 without filling the buffer? // Clear Memory - memset(buf, 0, *buflen); + memset(buf, 0, validLen); // Minimum Arguments if (requestcount > 0) { @@ -5056,14 +5078,17 @@ static int sceNetAdhocctlGetAddrByName(MIPSState *mips, const char *nickName, u3 // Normal Information Mode else { + // Only the part of the buffer that's valid memory. + const u32 validLen = Memory::ClampValidSizeAt(bufAddr, std::max((s32)*buflen, 0)); + // Clear Memory - memset(buf, 0, *buflen); + memset(buf, 0, validLen); // Discovered Player Count int discovered = 0; // Calculate Requested Elements - int requestcount = *buflen / sizeof(SceNetAdhocctlPeerInfoEmu); + int requestcount = validLen / sizeof(SceNetAdhocctlPeerInfoEmu); // Minimum Space available if (requestcount > 0) diff --git a/Core/HLE/sceNetAdhocMatching.cpp b/Core/HLE/sceNetAdhocMatching.cpp index aa597fcc3c..fdce9166c2 100644 --- a/Core/HLE/sceNetAdhocMatching.cpp +++ b/Core/HLE/sceNetAdhocMatching.cpp @@ -1382,11 +1382,14 @@ int NetAdhocMatching_Stop(int matchingId) { // Stop fake PSP Thread. // kernelObjects may already been cleared early during a Shutdown, thus trying to access it may generates Warning/Error in the log - if (matchingThreads[item->matching_thid] > 0 && strcmp(__KernelGetThreadName(matchingThreads[item->matching_thid]), "ERROR") != 0) { - __KernelStopThread(matchingThreads[item->matching_thid], SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching stopped"); - __KernelDeleteThread(matchingThreads[item->matching_thid], SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching deleted"); + // A savestate load replaces the thread list but not the contexts, so the index may be past its end. + if (item->matching_thid >= 0 && item->matching_thid < (int)matchingThreads.size()) { + if (matchingThreads[item->matching_thid] > 0 && strcmp(__KernelGetThreadName(matchingThreads[item->matching_thid]), "ERROR") != 0) { + __KernelStopThread(matchingThreads[item->matching_thid], SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching stopped"); + __KernelDeleteThread(matchingThreads[item->matching_thid], SCE_KERNEL_ERROR_THREAD_TERMINATED, "AdhocMatching deleted"); + } + matchingThreads[item->matching_thid] = 0; } - matchingThreads[item->matching_thid] = 0; // Make sure nobody locking/using the socket item->socketlock->lock(); @@ -1721,6 +1724,9 @@ int NetAdhocMatching_Start(int matchingId, int evthPri, int evthPartitionId, int // Created and started without rescheduling, like adhocctl's thread: starting it through // sceKernelStartThread switched threads inside this call, and the game got the thread's ID back // instead of 0 (pspautotests net/adhoc/matching). + if (item->matching_thid >= (int)matchingThreads.size()) { + matchingThreads.resize(item->matching_thid + 1); + } matchingThreads[item->matching_thid] = __KernelCreateThread(thrname.c_str(), __KernelGetCurThreadModuleId(), matchingThreadHackAddr, evthPri, evthStack, PSP_THREAD_ATTR_USER, 0, true); //item->matchingThread = new HLEHelperThread(thrname.c_str(), "sceNetAdhocMatching", "__NetMatchingCallbacks", inthPri, inthStack); if (matchingThreads[item->matching_thid] > 0) { @@ -1823,7 +1829,7 @@ static int sceNetAdhocMatchingSelectTarget(MIPSState *mips, int matchingId, cons } void * opt = NULL; - if (Memory::IsValidAddress(optDataPtr)) opt = Memory::GetPointerWriteUnchecked(optDataPtr); + if (Memory::IsValidRange(optDataPtr, std::max(optLen, 1))) opt = Memory::GetPointerWriteUnchecked(optDataPtr); // Host Mode if (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT) { // Already Connected. Right after accepting, it's still in progress (pspautotests net/adhoc/pair/matching). @@ -1921,7 +1927,7 @@ int NetAdhocMatching_CancelTargetWithOpt(int matchingId, const char* macAddress, SceNetEtherAddr* target = (SceNetEtherAddr*)macAddress; void* opt = NULL; - if (Memory::IsValidAddress(optDataPtr)) opt = Memory::GetPointerWriteUnchecked(optDataPtr); + if (Memory::IsValidRange(optDataPtr, std::max(optLen, 1))) opt = Memory::GetPointerWriteUnchecked(optDataPtr); if (target == NULL || ((optLen != 0) && (optLen <= 0 || opt == NULL))) { // Invalid Arguments @@ -2183,8 +2189,12 @@ static int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) // Fix Oversize Request if ((*buflen) > available) *buflen = available; + // Only the part of the buffer that's valid memory (none if buf2 is NULL). + *buflen = Memory::ClampValidSizeAt(buf, *buflen); + // Clear Memory - memset(buf2, 0, *buflen); + if (buf2) + memset(buf2, 0, *buflen); // Calculate Requested Peer Count int requestedpeers = (*buflen) / sizeof(SceNetAdhocMatchingMemberInfoEmu); @@ -2354,7 +2364,7 @@ int sceNetAdhocMatchingSendData(MIPSState *mips, int matchingId, const char *mac } void* data = NULL; - if (Memory::IsValidAddress(dataAddr)) data = Memory::GetPointerWriteUnchecked(dataAddr); + if (Memory::IsValidRange(dataAddr, dataLen)) data = Memory::GetPointerWriteUnchecked(dataAddr); // Lock the peer std::lock_guard peer_guard(peerlock);