Ad hoc, PMP: Bound guest-sized buffers and lists

- Game mode master and replica data was copied by the game's size after
  checking one byte, into host buffers allocated by that size (up to 2 GB).
  If the copy failed, the uninitialized buffer was sent to peers.
- sceNetAdhocctlCreateEnterGameMode read up to 16 member MACs after checking
  one byte.
- sceNetAdhocMatchingCreate allocated and cleared the game's receive buffer
  size on the host with no upper bound. Cap it at 1 MB.
- PMP video walked its block descriptors with only the first one checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-11-05 17:21:36 +01:00
1 parent 917607d8fa
commit f4b99a6a99
3 files changed
+14 -2

No files matched your search

+3
View File
@@ -962,6 +962,9 @@ static bool decodePmpVideo(PSPPointer<SceMpegRingBuffer> ringbuffer, u32 pmpctxA
// joint all blocks into H264Frames
for (int i = 0; i < pmp_nBlocks; i++){
auto lli = PSPPointer<SceMpegLLI>::Create(pmp_videoSource);
// Each block descriptor is in game memory, after the first.
if (!lli.IsValid())
break;
// add source block into pmpframes
const uint8_t *ptr = Memory::GetPointerRangeOrException(lli->pSrc, lli->iSize);
if (ptr)
+6 -2
View File
@@ -3391,6 +3391,9 @@ int NetAdhocctl_CreateEnterGameMode(const char* group_name, int game_type, int n
if (game_type < ADHOCCTL_GAMETYPE_1A || game_type > ADHOCCTL_GAMETYPE_2A || num_members < 2 || num_members > 16 || (game_type == ADHOCCTL_GAMETYPE_1A && num_members > 4))
return SCE_NET_ADHOCCTL_ERROR_INVALID_ARG;
// The whole member list is read below.
if (!Memory::IsValidRange(membersAddr, num_members * (u32)sizeof(SceNetEtherAddr)))
return SCE_NET_ADHOCCTL_ERROR_INVALID_ARG;
// In a normal group, it reports ALREADY_CONNECTED through the handlers and stays in it
// (pspautotests net/adhoc/gamemode).
@@ -4615,7 +4618,8 @@ static int sceNetAdhocGameModeCreateMaster(MIPSState *mips, u32 dataAddr, int si
if (!netAdhocGameModeEntered)
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_NOT_ENTER_GAMEMODE, "not enter gamemode");
if (size < 0 || !Memory::IsValidAddress(dataAddr))
// The data is copied (and the buffers are sized) by size.
if (size < 0 || !Memory::IsValidAddress(dataAddr) || !Memory::IsValidRange(dataAddr, (u32)size))
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_INVALID_ARG, "invalid arg");
// pspautotests net/adhoc/pair/gamemode
@@ -4672,7 +4676,7 @@ static int sceNetAdhocGameModeCreateReplica(MIPSState *mips, const char *mac, u3
if (!netAdhocGameModeEntered)
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_NOT_ENTER_GAMEMODE, "not enter gamemode");
if (mac == nullptr || size < 0 || !Memory::IsValidAddress(dataAddr))
if (mac == nullptr || size < 0 || !Memory::IsValidAddress(dataAddr) || !Memory::IsValidRange(dataAddr, (u32)size))
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_INVALID_ARG, "invalid arg");
const SceNetEtherAddr &replicaMac = *(const SceNetEtherAddr *)mac;
+5
View File
@@ -1576,6 +1576,11 @@ static int sceNetAdhocMatchingCreate(MIPSState *mips, int mode, int maxnum, int
// Invalid Receive Buffer Size
return hleLogError(Log::sceNet, SCE_NET_ADHOC_MATCHING_ERROR_RXBUF_TOO_SHORT, "adhoc matching rxbuf too short");
}
// We allocate (and clear) this on the host. The PSP takes it from the library's small heap, and
// no packet is anywhere near this big.
if (rxbuflen > 1024 * 1024) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_MATCHING_ERROR_NO_SPACE, "adhoc matching rxbuf too large");
}
if (mode < 1 || mode > 3) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_MATCHING_ERROR_INVALID_MODE, "adhoc matching invalid mode");