mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-02 20:42:29 +01:00
Merge pull request #22863 from hrydgard/adhoc-buffer-checks
sceNetAdhoc: Check the game's ad hoc buffers by their full length
This commit is contained in:
3 files changed
+59
-37
No files matched your search
@@ -921,19 +921,6 @@ template<auto func> void WrapI_ICI(MIPSState *mips) {
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<auto func> 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<int(int, void *, void *, void *, void *, u32, int), func>(mips, PARAM(0), ptr(PARAM(1)), ptr(PARAM(2)), ptr(PARAM(3)), ptr(PARAM(4)), PARAM(5), PARAM(6) );
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<auto func> 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<int(int, const char *, u32, void *, int, int, int), func>(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<auto func> void WrapI_VUI(MIPSState *mips) {
|
||||
u32 retval = HLECall<int(void *, u32, int), func>(mips, Memory::GetPointerWriteOrException(PARAM(0)), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
|
||||
+41
-16
@@ -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)
|
||||
@@ -3065,7 +3066,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
|
||||
@@ -3127,7 +3128,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
|
||||
@@ -3286,7 +3287,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 };
|
||||
@@ -3527,7 +3528,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
|
||||
@@ -3614,7 +3615,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
|
||||
@@ -4321,7 +4322,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
|
||||
@@ -4377,7 +4378,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
|
||||
@@ -4681,7 +4682,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);
|
||||
}
|
||||
|
||||
@@ -4839,13 +4840,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>, "sceNetAdhocInit", 'x', "" },
|
||||
{0XA62C6F57, &WrapI_V<sceNetAdhocTerm>, "sceNetAdhocTerm", 'i', "" },
|
||||
{0X0AD043ED, &WrapI_C<sceNetAdhocctlConnect>, "sceNetAdhocctlConnect", 'i', "s" },
|
||||
{0X6F92741B, &WrapI_CIIU<sceNetAdhocPdpCreate>, "sceNetAdhocPdpCreate", 'i', "siix" },
|
||||
{0XABED3790, &WrapI_ICUVIII<sceNetAdhocPdpSend>, "sceNetAdhocPdpSend", 'i', "isxpiii" },
|
||||
{0XDFE53E03, &WrapI_IVVVVUI<sceNetAdhocPdpRecv>, "sceNetAdhocPdpRecv", 'i', "ippppxi" },
|
||||
{0XABED3790, &WrapI_IUUUUUU<sceNetAdhocPdpSendSyscall>, "sceNetAdhocPdpSend", 'i', "ixxxiii" },
|
||||
{0XDFE53E03, &WrapI_IUUUUUU<sceNetAdhocPdpRecvSyscall>, "sceNetAdhocPdpRecv", 'i', "ixxxxxi" },
|
||||
{0X7F27BB5E, &WrapI_II<sceNetAdhocPdpDelete>, "sceNetAdhocPdpDelete", 'i', "ii" },
|
||||
{0XC7C1FC57, &WrapI_UU<sceNetAdhocGetPdpStat>, "sceNetAdhocGetPdpStat", 'i', "xx" },
|
||||
{0X157E6225, &WrapI_II<sceNetAdhocPtpClose>, "sceNetAdhocPtpClose", 'i', "ii" },
|
||||
@@ -4900,7 +4919,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
|
||||
@@ -4964,13 +4983,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) {
|
||||
@@ -5059,14 +5081,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)
|
||||
|
||||
@@ -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<std::recursive_mutex> peer_guard(peerlock);
|
||||
|
||||
Reference in new issue
Block a user