HLE: Check more guest buffers by their full length, and an empty insert

Calls that checked one byte of a game's buffer and then wrote or read the
whole thing, or trusted a negative length:
- sceNetEtherNtostr/Strton, the apctl BSS descriptor calls, GetState and
  sceNetGetDropRate.
- sceNpAuthGetTicket wrote its whole ticket whatever the length; it's
  now built locally and written once the buffer is known to hold it.
  sceNpAuthGetTicketParam checked its limits after copying, and walked
  ticket params past the ticket's end.
- sceNp2's communication ID and passphrase, a negative maxServerIds, and
  an unchecked unknown1Ptr.
- sceParseUri's work area and scheme string, sceParseHttp's negative
  header length and value address, and ReadVariableSizedStruct's size.
- sceKernelCreateLwMutex initialized the work area without checking it
  at all, and the other LwMutex calls checked one byte of it.
- sceNetAdhocctlGetScanInfo cleared the length the game gave, of a
  buffer checked by one byte (or any length, negative ones included).

Also: a game mode join inserted at begin() + 1 into a possibly empty
list of players.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-31 11:26:03 +01:00
1 parent c0e750726f
commit 0a778a13ff
9 files changed
+127 -67

No files matched your search

+5 -4
View File
@@ -40,10 +40,11 @@ std::string getHeaderString(std::istringstream &headers) {
// FIXME: Is it allowed for fieldName to be null/0 or empty string ? JPCSP seems to ignore it
static int sceParseHttpResponseHeader(u32 headerAddr, int headerLength, const char *fieldName, u32 valueAddr, u32 valueLengthAddr) {
if (!Memory::IsValidRange(headerAddr, headerLength))
if (headerLength < 0 || !Memory::IsValidRange(headerAddr, headerLength))
return hleLogError(Log::sceNet, -1, "invalid arg");
if (!Memory::IsValidRange(valueLengthAddr, 4))
// The value's address gets written to valueAddr.
if (!Memory::IsValidRange(valueLengthAddr, 4) || !Memory::IsValidRange(valueAddr, 4))
return hleLogError(Log::sceNet, -1, "invalid arg");
// FIXME: Not sure whether valueAddr can be null or not (in case the game just need to get the size to allocate the value buffer first)
@@ -53,7 +54,7 @@ static int sceParseHttpResponseHeader(u32 headerAddr, int headerLength, const ch
std::string field = fieldName ? fieldName : "";
field = StripSpaces(field);
std::string headers(Memory::GetCharPointer(headerAddr), headerLength);
std::string headers = headerLength > 0 ? std::string(Memory::GetCharPointerUnchecked(headerAddr), headerLength) : std::string();
std::istringstream hdrs(headers);
u32 addr = 0;
u32 len = 0;
@@ -108,7 +109,7 @@ static int sceParseHttpStatusLine(MIPSState *mips, u32 headerAddr, u32 headerLen
if (!Memory::IsValidRange(headerAddr, headerLength))
return hleLogError(Log::sceNet, -1, "invalid arg");
std::string headers(Memory::GetCharPointer(headerAddr), headerLength);
std::string headers = headerLength > 0 ? std::string(Memory::GetCharPointerUnchecked(headerAddr), headerLength) : std::string();
// Get first line from header, line ending can be '\n' or '\r'
std::istringstream hdr(headers);
std::string line;