mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-01 03:57:17 +01:00
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:
1 parent
c0e750726f
commit
0a778a13ff
9 files changed
+127
-67
No files matched your search
+5
-2
@@ -4,14 +4,17 @@
|
||||
|
||||
// Used in various places in the PSP OS.
|
||||
template<typename T> bool ReadVariableSizedStruct(u32 addr, T *out) {
|
||||
if (!Memory::IsValid4AlignedAddress(addr)) {
|
||||
return false;
|
||||
}
|
||||
int size = Memory::ReadUnchecked_U32(addr);
|
||||
if (!Memory::IsValid4AlignedRange(addr, size)) {
|
||||
if (size < 0 || !Memory::IsValid4AlignedRange(addr, size)) {
|
||||
return false;
|
||||
}
|
||||
memset(out, 0, sizeof(*out));
|
||||
// Only copy the right size to support different struct versions.
|
||||
// Let's add a debug assert in case we have a struct that is too small for the data.
|
||||
_dbg_assert_(sizeof(*out) >= size);
|
||||
Memory::Memcpy(out, addr, std::min(size, (int)sizeof(*out)));
|
||||
Memory::MemcpyUnchecked(out, addr, std::min(size, (int)sizeof(*out)));
|
||||
return true;
|
||||
}
|
||||
@@ -1762,7 +1762,8 @@ void friendFinderPoll() {
|
||||
gameModeMacs.push_back(*(SceNetEtherAddr *)adhocctl_event.connect.mac);
|
||||
}
|
||||
else {
|
||||
it = gameModeMacs.begin() + 1;
|
||||
// After the host, who's first - if the list has one yet.
|
||||
it = gameModeMacs.empty() ? gameModeMacs.end() : gameModeMacs.begin() + 1;
|
||||
gameModeMacs.insert(it, *(SceNetEtherAddr *)adhocctl_event.connect.mac);
|
||||
}
|
||||
|
||||
|
||||
@@ -609,6 +609,11 @@ int sceKernelCreateLwMutex(MIPSState *mips, u32 workareaPtr, const char *name, u
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_COUNT);
|
||||
}
|
||||
|
||||
auto workarea = PSPPointer<NativeLwMutexWorkarea>::Create(workareaPtr);
|
||||
if (!workarea.IsValid()) {
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "bad workarea");
|
||||
}
|
||||
|
||||
LwMutex *mutex = new LwMutex();
|
||||
SceUID id = kernelObjects.Create(mutex);
|
||||
mutex->nm.size = sizeof(mutex->nm);
|
||||
@@ -618,7 +623,6 @@ int sceKernelCreateLwMutex(MIPSState *mips, u32 workareaPtr, const char *name, u
|
||||
mutex->nm.uid = id;
|
||||
mutex->nm.workarea = workareaPtr;
|
||||
mutex->nm.initialCount = initialCount;
|
||||
auto workarea = PSPPointer<NativeLwMutexWorkarea>::Create(workareaPtr);
|
||||
workarea->init();
|
||||
workarea->lockLevel = initialCount;
|
||||
if (initialCount == 0)
|
||||
@@ -664,7 +668,7 @@ bool __KernelUnlockLwMutexForThread(LwMutex *mutex, T workarea, SceUID threadID,
|
||||
int sceKernelDeleteLwMutex(u32 workareaPtr) {
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelDeleteLwMutex(%08x)", workareaPtr);
|
||||
|
||||
if (!workareaPtr || !Memory::IsValidAddress(workareaPtr))
|
||||
if (!workareaPtr || !Memory::IsValidRange(workareaPtr, sizeof(NativeLwMutexWorkarea)))
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ILLEGAL_ADDR);
|
||||
|
||||
auto workarea = PSPPointer<NativeLwMutexWorkarea>::Create(workareaPtr);
|
||||
@@ -798,7 +802,7 @@ void __KernelLwMutexEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
}
|
||||
|
||||
int sceKernelTryLockLwMutex(u32 workareaPtr, int count) {
|
||||
if (!Memory::IsValidAddress(workareaPtr)) {
|
||||
if (!Memory::IsValidRange(workareaPtr, sizeof(NativeLwMutexWorkarea))) {
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ACCESS_ERROR, "Bad workarea pointer for LwMutex");
|
||||
}
|
||||
|
||||
@@ -816,7 +820,7 @@ int sceKernelTryLockLwMutex(u32 workareaPtr, int count) {
|
||||
}
|
||||
|
||||
int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count) {
|
||||
if (!Memory::IsValidAddress(workareaPtr)) {
|
||||
if (!Memory::IsValidRange(workareaPtr, sizeof(NativeLwMutexWorkarea))) {
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ACCESS_ERROR, "Bad workarea pointer for LwMutex");
|
||||
}
|
||||
|
||||
@@ -833,7 +837,7 @@ int sceKernelTryLockLwMutex_600(u32 workareaPtr, int count) {
|
||||
}
|
||||
|
||||
int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) {
|
||||
if (!Memory::IsValidAddress(workareaPtr)) {
|
||||
if (!Memory::IsValidRange(workareaPtr, sizeof(NativeLwMutexWorkarea))) {
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ACCESS_ERROR, "Bad workarea pointer for LwMutex");
|
||||
}
|
||||
|
||||
@@ -865,7 +869,7 @@ int sceKernelLockLwMutex(u32 workareaPtr, int count, u32 timeoutPtr) {
|
||||
}
|
||||
|
||||
int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) {
|
||||
if (!Memory::IsValidAddress(workareaPtr)) {
|
||||
if (!Memory::IsValidRange(workareaPtr, sizeof(NativeLwMutexWorkarea))) {
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ACCESS_ERROR, "Bad workarea pointer for LwMutex");
|
||||
}
|
||||
|
||||
@@ -897,7 +901,7 @@ int sceKernelLockLwMutexCB(u32 workareaPtr, int count, u32 timeoutPtr) {
|
||||
}
|
||||
|
||||
int sceKernelUnlockLwMutex(u32 workareaPtr, int count) {
|
||||
if (!Memory::IsValidAddress(workareaPtr)) {
|
||||
if (!Memory::IsValidRange(workareaPtr, sizeof(NativeLwMutexWorkarea))) {
|
||||
return hleLogError(Log::sceKernel, SCE_KERNEL_ERROR_ACCESS_ERROR, "Bad workarea pointer for LwMutex");
|
||||
}
|
||||
|
||||
|
||||
+26
-12
@@ -1145,12 +1145,13 @@ static u32 sceWlanGetSwitchState() {
|
||||
static void sceNetEtherNtostr(MIPSState *mips, u32 macPtr, u32 bufferPtr) {
|
||||
DEBUG_LOG(Log::sceNet, "sceNetEtherNtostr(%08x, %08x) at %08x", macPtr, bufferPtr, mips->pc);
|
||||
|
||||
if (Memory::IsValidAddress(bufferPtr) && Memory::IsValidAddress(macPtr)) {
|
||||
// "xx:xx:xx:xx:xx:xx" and a null.
|
||||
if (Memory::IsValidRange(bufferPtr, 18) && Memory::IsValidRange(macPtr, ETHER_ADDR_LEN)) {
|
||||
char *buffer = (char *)Memory::GetPointerWriteUnchecked(bufferPtr);
|
||||
const u8 *mac = Memory::GetPointerUnchecked(macPtr);
|
||||
|
||||
// MAC address is always 6 bytes / 48 bits.
|
||||
sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
snprintf(buffer, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
|
||||
VERBOSE_LOG(Log::sceNet, "sceNetEtherNtostr - [%s]", buffer);
|
||||
@@ -1173,9 +1174,9 @@ static int hex_to_digit(int c) {
|
||||
static void sceNetEtherStrton(u32 bufferPtr, u32 macPtr) {
|
||||
DEBUG_LOG(Log::sceNet, "sceNetEtherStrton(%08x, %08x)", bufferPtr, macPtr);
|
||||
|
||||
if (Memory::IsValidAddress(bufferPtr) && Memory::IsValidAddress(macPtr)) {
|
||||
if (Memory::IsValidNullTerminatedString(bufferPtr) && Memory::IsValidRange(macPtr, ETHER_ADDR_LEN)) {
|
||||
const char *buffer = (const char *)Memory::GetPointerUnchecked(bufferPtr);
|
||||
u8 *mac = Memory::GetPointerWriteOrException(macPtr);
|
||||
u8 *mac = Memory::GetPointerWriteUnchecked(macPtr);
|
||||
|
||||
// MAC address is always 6 pairs of hex digits.
|
||||
// TODO: Funny stuff happens if it's too short.
|
||||
@@ -1201,7 +1202,7 @@ static void sceNetEtherStrton(u32 bufferPtr, u32 macPtr) {
|
||||
}
|
||||
}
|
||||
|
||||
VERBOSE_LOG(Log::sceNet, "sceNetEtherStrton - [%s]", mac2str((SceNetEtherAddr*)Memory::GetPointerOrException(macPtr)).c_str());
|
||||
VERBOSE_LOG(Log::sceNet, "sceNetEtherStrton - [%s]", mac2str((const SceNetEtherAddr *)Memory::GetPointerUnchecked(macPtr)).c_str());
|
||||
// Seems to maybe kinda return the last value. Probably returns void.
|
||||
//return value;
|
||||
}
|
||||
@@ -1299,7 +1300,7 @@ static int sceNetApctlInit(MIPSState *mips, int stackSize, int initPriority) {
|
||||
userMemory.Free(apctlProdCodeAddr);
|
||||
}
|
||||
apctlProdCodeAddr = userMemory.Alloc(structsz, false, "ApctlAdhocId");
|
||||
SceNetAdhocctlAdhocId* prodCode = (SceNetAdhocctlAdhocId*)Memory::GetCharPointer(apctlProdCodeAddr);
|
||||
SceNetAdhocctlAdhocId* prodCode = Memory::IsValidRange(apctlProdCodeAddr, structsz) ? (SceNetAdhocctlAdhocId *)Memory::GetPointerWriteUnchecked(apctlProdCodeAddr) : nullptr;
|
||||
if (prodCode) {
|
||||
memset(prodCode, 0, structsz);
|
||||
// TODO: Use a 9-characters product id instead of disc id (ie. not null-terminated(VT_UTF8_SPE) and shouldn't be variable size?)
|
||||
@@ -1611,9 +1612,9 @@ static int sceNetApctlGetState(u32 pStateAddr) {
|
||||
}
|
||||
|
||||
// Valid Arguments
|
||||
if (Memory::IsValidAddress(pStateAddr)) {
|
||||
if (Memory::IsValid4AlignedAddress(pStateAddr)) {
|
||||
// Return Thread Status
|
||||
Memory::WriteOrException_U32(NetApctl_GetState(), pStateAddr);
|
||||
Memory::WriteUnchecked_U32(NetApctl_GetState(), pStateAddr);
|
||||
// Return Success
|
||||
return hleLogDebug(Log::sceNet, 0);
|
||||
}
|
||||
@@ -1652,7 +1653,10 @@ int NetApctl_GetBSSDescIDListUser(u32 sizeAddr, u32 bufAddr) {
|
||||
// Return size required
|
||||
Memory::WriteUnchecked_U32(entries * userInfoSize, sizeAddr);
|
||||
|
||||
if (bufAddr != 0 && Memory::IsValidAddress(sizeAddr)) {
|
||||
if (bufAddr != 0) {
|
||||
// Only write entries that fit in valid memory.
|
||||
if (size > 0)
|
||||
size = (int)Memory::ClampValidSizeAt(bufAddr, size);
|
||||
int offset = 0;
|
||||
for (int i = 0; i < entries; i++) {
|
||||
// Check if enough space available to write the next structure
|
||||
@@ -1683,7 +1687,15 @@ static int sceNetApctlGetBSSDescIDListUser(u32 sizeAddr, u32 bufAddr) {
|
||||
}
|
||||
|
||||
int NetApctl_GetBSSDescEntryUser(int entryId, int infoId, u32 resultAddr) {
|
||||
if (!Memory::IsValidAddress(resultAddr))
|
||||
u32 resultSize = 4;
|
||||
switch (infoId) {
|
||||
case PSP_NET_APCTL_DESC_IBSS: resultSize = ETHER_ADDR_LEN; break;
|
||||
case PSP_NET_APCTL_DESC_SSID_NAME: resultSize = APCTL_SSID_MAXLEN; break;
|
||||
case PSP_NET_APCTL_DESC_CHANNEL:
|
||||
case PSP_NET_APCTL_DESC_SIGNAL_STRENGTH: resultSize = 1; break;
|
||||
default: break;
|
||||
}
|
||||
if (!Memory::IsValidRange(resultAddr, resultSize))
|
||||
return hleLogError(Log::sceNet, -1, "apctl invalid arg"); // 0x8002013A or ERROR_NET_WLAN_INVALID_ARG ?
|
||||
|
||||
// Generate an SSID name
|
||||
@@ -1853,8 +1865,10 @@ static int sceNetUpnpGetNatInfo() {
|
||||
}
|
||||
|
||||
static int sceNetGetDropRate(u32 dropRateAddr, u32 dropDurationAddr) {
|
||||
Memory::WriteOrException_U32(netDropRate, dropRateAddr);
|
||||
Memory::WriteOrException_U32(netDropDuration, dropDurationAddr);
|
||||
if (Memory::IsValid4AlignedAddress(dropRateAddr))
|
||||
Memory::WriteUnchecked_U32(netDropRate, dropRateAddr);
|
||||
if (Memory::IsValid4AlignedAddress(dropDurationAddr))
|
||||
Memory::WriteUnchecked_U32(netDropDuration, dropDurationAddr);
|
||||
return hleLogInfo(Log::sceNet, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -2744,15 +2744,15 @@ int sceNetAdhocctlScan(MIPSState *mips) {
|
||||
|
||||
int sceNetAdhocctlGetScanInfo(MIPSState *mips, u32 sizeAddr, u32 bufAddr) {
|
||||
s32_le *buflen = NULL;
|
||||
if (Memory::IsValidAddress(sizeAddr)) {
|
||||
buflen = (s32_le *)Memory::GetPointerOrException(sizeAddr);
|
||||
if (Memory::IsValid4AlignedAddress(sizeAddr)) {
|
||||
buflen = (s32_le *)Memory::GetPointerWriteUnchecked(sizeAddr);
|
||||
}
|
||||
SceNetAdhocctlScanInfoEmu *buf = NULL;
|
||||
if (Memory::IsValidAddress(bufAddr)) {
|
||||
buf = (SceNetAdhocctlScanInfoEmu *)Memory::GetPointerOrException(bufAddr);
|
||||
}
|
||||
|
||||
INFO_LOG(Log::sceNet, "sceNetAdhocctlGetScanInfo([%08x]=%i, %08x) at %08x", sizeAddr, Memory::ReadUnchecked_U32(sizeAddr), bufAddr, mips->pc);
|
||||
INFO_LOG(Log::sceNet, "sceNetAdhocctlGetScanInfo([%08x]=%i, %08x) at %08x", sizeAddr, buflen ? (int)*buflen : 0, bufAddr, mips->pc);
|
||||
if (!g_Config.bEnableWlan) {
|
||||
return hleLogWarning(Log::sceNet, 0, "WLAN off");
|
||||
}
|
||||
@@ -2783,14 +2783,17 @@ int sceNetAdhocctlGetScanInfo(MIPSState *mips, u32 sizeAddr, u32 bufAddr) {
|
||||
}
|
||||
// Normal Information Mode
|
||||
else {
|
||||
// Only touch 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);
|
||||
|
||||
// Network Discovery Counter
|
||||
int discovered = 0;
|
||||
|
||||
// Count requested Networks
|
||||
int requestcount = *buflen / sizeof(SceNetAdhocctlScanInfoEmu);
|
||||
int requestcount = validLen / sizeof(SceNetAdhocctlScanInfoEmu);
|
||||
|
||||
// Minimum Argument Requirements
|
||||
if (requestcount > 0) {
|
||||
|
||||
+47
-20
@@ -168,24 +168,24 @@ static int sceNpTerm()
|
||||
|
||||
static int sceNpGetContentRatingFlag(u32 parentalControlAddr, u32 userAgeAddr)
|
||||
{
|
||||
if (!Memory::IsValidAddress(parentalControlAddr) || !Memory::IsValidAddress(userAgeAddr))
|
||||
if (!Memory::IsValid4AlignedAddress(parentalControlAddr) || !Memory::IsValid4AlignedAddress(userAgeAddr))
|
||||
return hleLogError(Log::sceNet, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg");
|
||||
|
||||
INFO_LOG(Log::sceNet, "%s - Parental Control: %d", __FUNCTION__, npParentalControl);
|
||||
INFO_LOG(Log::sceNet, "%s - User Age: %d", __FUNCTION__, npUserAge);
|
||||
|
||||
Memory::WriteOrException_U32(npParentalControl, parentalControlAddr);
|
||||
Memory::WriteOrException_U32(npUserAge, userAgeAddr);
|
||||
Memory::WriteUnchecked_U32(npParentalControl, parentalControlAddr);
|
||||
Memory::WriteUnchecked_U32(npUserAge, userAgeAddr);
|
||||
|
||||
return hleLogWarning(Log::sceNet, 0, "UNTESTED");
|
||||
}
|
||||
|
||||
static int sceNpGetChatRestrictionFlag(u32 flagAddr)
|
||||
{
|
||||
if (!Memory::IsValidAddress(flagAddr))
|
||||
if (!Memory::IsValid4AlignedAddress(flagAddr))
|
||||
return hleLogError(Log::sceNet, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg");
|
||||
|
||||
Memory::WriteOrException_U32(npChatRestriction, flagAddr);
|
||||
Memory::WriteUnchecked_U32(npChatRestriction, flagAddr);
|
||||
|
||||
return hleLogWarning(Log::sceNet, 0, "Chat restriction: %d", npChatRestriction);
|
||||
}
|
||||
@@ -276,7 +276,7 @@ static int sceNpGetUserProfile(u32 profilePtr)
|
||||
WARN_LOG(Log::sceNet, "UNTESTED %s(%08x)", __FUNCTION__, profilePtr);
|
||||
|
||||
auto profile = PSPPointer<SceNpUserInformation>::Create(profilePtr);
|
||||
if (!Memory::IsValidAddress(profilePtr))
|
||||
if (!profile.IsValid())
|
||||
return hleLogError(Log::sceNet, SCE_NP_ERROR_INVALID_ARGUMENT, "invalid arg");
|
||||
|
||||
profile.FillWithZero();
|
||||
@@ -361,13 +361,17 @@ int sceNpAuthCreateStartRequest(u32 paramAddr) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid arg");
|
||||
}
|
||||
|
||||
npServiceId = Memory::GetCharPointer(params.serviceIdAddr);
|
||||
// Missing fields in a short struct are zero.
|
||||
auto guestString = [](u32 addr) -> const char * {
|
||||
return Memory::IsValidNullTerminatedString(addr) ? Memory::GetCharPointerUnchecked(addr) : "";
|
||||
};
|
||||
npServiceId = guestString(params.serviceIdAddr);
|
||||
|
||||
INFO_LOG(Log::sceNet, "%s - Max Version: %u.%u", __FUNCTION__, params.version.major, params.version.minor);
|
||||
INFO_LOG(Log::sceNet, "%s - Service ID: %s", __FUNCTION__, Memory::GetCharPointer(params.serviceIdAddr));
|
||||
INFO_LOG(Log::sceNet, "%s - Entitlement ID: %s", __FUNCTION__, Memory::GetCharPointer(params.entitlementIdAddr));
|
||||
INFO_LOG(Log::sceNet, "%s - Service ID: %s", __FUNCTION__, npServiceId.c_str());
|
||||
INFO_LOG(Log::sceNet, "%s - Entitlement ID: %s", __FUNCTION__, guestString(params.entitlementIdAddr));
|
||||
INFO_LOG(Log::sceNet, "%s - Consumed Count: %d", __FUNCTION__, params.consumedCount);
|
||||
INFO_LOG(Log::sceNet, "%s - Cookie (size = %d): %s", __FUNCTION__, params.cookieSize, Memory::GetCharPointer(params.cookieAddr));
|
||||
INFO_LOG(Log::sceNet, "%s - Cookie (size = %d): %s", __FUNCTION__, params.cookieSize, guestString(params.cookieAddr));
|
||||
|
||||
u32 retval = 0;
|
||||
if (params.size >= 32 && params.ticketCbAddr != 0) {
|
||||
@@ -428,12 +432,13 @@ int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) {
|
||||
}
|
||||
|
||||
int result = length;
|
||||
Memory::Memset(bufferAddr, 0, length, "NpAuthGetTicket");
|
||||
// Built here, then copied once we know it fits.
|
||||
u8 staging[512]{};
|
||||
SceNpTicket ticket = {};
|
||||
// Dummy Login ticket returned as Login response. Dummy ticket contents were taken from https://www.psdevwiki.com/ps3/X-I-5-Ticket
|
||||
ticket.header.version = TICKET_VER_2_1;
|
||||
ticket.header.size = 0xF0; // size excluding the header
|
||||
u8* buf = Memory::GetPointerWriteOrException(bufferAddr + sizeof(ticket));
|
||||
u8 *buf = staging + sizeof(ticket);
|
||||
int ofs = 0;
|
||||
ofs += writeTicketParam(buf, PARAM_TYPE_STRING_ASCII, "\x4c\x47\x56\x3b\x81\x39\x4a\x22\xd8\x6b\xc1\x57\x71\x6e\xfd\xb8\xab\x63\xcc\x51", 20); // 20 random letters, token key or SceNpSignature?
|
||||
ofs += writeTicketU32Param(buf + ofs, PARAM_TYPE_INT, 0x0100); // a flags?
|
||||
@@ -446,7 +451,9 @@ int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) {
|
||||
ofs += writeTicketStringParam(buf + ofs, PARAM_TYPE_STRING, npOnlineId.c_str(), 32); // username (pre-cut to 16 chars)
|
||||
ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, npCountryCode, 4); // SceNpCountryCode ? ie. "fr" + 00 02
|
||||
ofs += writeTicketStringParam(buf + ofs, PARAM_TYPE_STRING, npRegionCode, 4); // 2-char code? related to country/lang code? ie. "c9" + 00 00
|
||||
ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, npServiceId.c_str(), 24);
|
||||
std::string serviceId = npServiceId;
|
||||
serviceId.resize(24, '\0');
|
||||
ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, serviceId.c_str(), 24);
|
||||
int status = 0;
|
||||
if (npParentalControl == PARENTAL_CONTROL_ENABLED) {
|
||||
status |= STATUS_ACCOUNT_PARENTAL_CONTROL_ENABLED;
|
||||
@@ -457,14 +464,22 @@ int sceNpAuthGetTicket(u32 requestId, u32 bufferAddr, u32 length) {
|
||||
ofs += writeTicketParam(buf + ofs, PARAM_TYPE_NULL);
|
||||
ticket.section.type = SECTION_TYPE_BODY;
|
||||
ticket.section.size = ofs;
|
||||
Memory::Memcpy(bufferAddr, &ticket, sizeof(SceNpTicket), "NpAuthGetTicket");
|
||||
memcpy(staging, &ticket, sizeof(SceNpTicket));
|
||||
SceNpTicketSection footer = { SECTION_TYPE_FOOTER, 32 }; // footer section? ie. 32-bytes on version 2.1 containing 4-chars ASCII + 20-chars ASCII
|
||||
Memory::Memcpy(bufferAddr + sizeof(ticket) + ofs, &footer, sizeof(SceNpTicketSection), "NpAuthGetTicket");
|
||||
memcpy(buf + ofs, &footer, sizeof(SceNpTicketSection));
|
||||
ofs += sizeof(footer);
|
||||
ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "\x34\xcd\x3c\xa9", 4);
|
||||
ofs += writeTicketParam(buf + ofs, PARAM_TYPE_STRING_ASCII, "\x3a\x4b\x42\x66\x92\xda\x6b\x7c\xb7\x4c\xe8\xd9\x4f\x2b\x77\x15\x91\xb8\xa4\xa9", 20); // 20 random letters, token key or SceNpSignature?
|
||||
// includes Language list?
|
||||
Memory::Memset(bufferAddr + sizeof(ticket) + ofs, 0, 36);
|
||||
// includes Language list? (36 zero bytes, staging is zeroed)
|
||||
const u32 total = (u32)sizeof(ticket) + ofs + 36;
|
||||
_dbg_assert_(total <= sizeof(staging));
|
||||
|
||||
// The whole ticket gets written, even if length is shorter.
|
||||
if (!Memory::IsValidRange(bufferAddr, std::max(length, total))) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_AUTH_ERROR_INVALID_ARGUMENT, "invalid buffer");
|
||||
}
|
||||
Memory::Memset(bufferAddr, 0, length, "NpAuthGetTicket");
|
||||
Memory::Memcpy(bufferAddr, staging, total, "NpAuthGetTicket");
|
||||
|
||||
result = ticket.header.size + sizeof(ticket.header); // dummy ticket is 248 bytes
|
||||
|
||||
@@ -512,20 +527,32 @@ int sceNpAuthDestroyRequest(int requestId)
|
||||
int sceNpAuthGetTicketParam(u32 ticketBufPtr, int ticketLen, int paramNum, u32 bufferPtr)
|
||||
{
|
||||
const u32 PARAM_BUFFER_MAX_SIZE = 256;
|
||||
if (!Memory::IsValidRange(bufferPtr, PARAM_BUFFER_MAX_SIZE)) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_MANAGER_ERROR_INVALID_ARGUMENT, "invalid buffer");
|
||||
}
|
||||
Memory::Memset(bufferPtr, 0, PARAM_BUFFER_MAX_SIZE); // JPCSP: This clear is always done, even when an error is returned
|
||||
if (paramNum < 0 || paramNum >= NUMBER_PARAMETERS) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_MANAGER_ERROR_INVALID_ARGUMENT);
|
||||
}
|
||||
if (ticketLen < (int)sizeof(SceNpTicket) || !Memory::IsValidRange(ticketBufPtr, ticketLen)) {
|
||||
return hleLogError(Log::sceNet, SCE_NP_MANAGER_ERROR_INVALID_ARGUMENT, "invalid ticket");
|
||||
}
|
||||
|
||||
SceNpTicket* ticket = (SceNpTicket*)Memory::GetPointerOrException(ticketBufPtr);
|
||||
const SceNpTicket *ticket = (const SceNpTicket *)Memory::GetPointerUnchecked(ticketBufPtr);
|
||||
const u32 ticketEnd = ticketBufPtr + ticketLen;
|
||||
u32 inbuf = ticketBufPtr;
|
||||
inbuf += sizeof(ticket->header);
|
||||
inbuf += ticket->section.size + sizeof(ticket->section);
|
||||
u32 outbuf = bufferPtr;
|
||||
for (int i = 0; i < paramNum; i++) {
|
||||
SceNpTicketParamData* ticketParam = (SceNpTicketParamData*)Memory::GetPointerOrException(inbuf);
|
||||
// Only copy params that are inside the ticket and fit in the output.
|
||||
if (inbuf < ticketBufPtr || inbuf + sizeof(SceNpTicketParamData) > ticketEnd)
|
||||
break;
|
||||
const SceNpTicketParamData *ticketParam = (const SceNpTicketParamData *)Memory::GetPointerUnchecked(inbuf);
|
||||
u32 sz = (u32)sizeof(SceNpTicketParamData) + ticketParam->length;
|
||||
Memory::Memcpy(outbuf, inbuf, sz);
|
||||
if (sz > ticketEnd - inbuf || sz > PARAM_BUFFER_MAX_SIZE - (outbuf - bufferPtr))
|
||||
break;
|
||||
Memory::MemcpyUnchecked(outbuf, inbuf, sz);
|
||||
DEBUG_LOG(Log::sceNet, "%s - Param #%d: Type = %04x, Length = %u", __FUNCTION__, i, static_cast<unsigned int>(ticketParam->type), static_cast<unsigned int>(ticketParam->length));
|
||||
outbuf += sz;
|
||||
inbuf += sz;
|
||||
|
||||
+5
-5
@@ -115,14 +115,14 @@ static int sceNpMatching2CreateContext(u32 communicationIdPtr, u32 passPhrasePtr
|
||||
if (!npMatching2Inited)
|
||||
return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!Memory::IsValidAddress(communicationIdPtr) || !Memory::IsValidAddress(passPhrasePtr) || !Memory::IsValidRange(ctxIdPtr, 2))
|
||||
if (!Memory::IsValidRange(communicationIdPtr, sizeof(SceNpCommunicationId)) || !Memory::IsValidRange(passPhrasePtr, sizeof(SceNpCommunicationPassphrase)) || !Memory::IsValidRange(ctxIdPtr, 2))
|
||||
return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX);
|
||||
|
||||
// FIXME: It seems Context are mapped to TitleID? may return 0x80550C05 or 0x80550C06 when finding an existing context
|
||||
SceNpCommunicationId* titleid = (SceNpCommunicationId*)Memory::GetCharPointer(communicationIdPtr);
|
||||
const SceNpCommunicationId *titleid = (const SceNpCommunicationId *)Memory::GetPointerUnchecked(communicationIdPtr);
|
||||
memcpy(npTitleId.data, titleid->data, sizeof(npTitleId));
|
||||
|
||||
SceNpCommunicationPassphrase* passph = (SceNpCommunicationPassphrase*)Memory::GetCharPointer(passPhrasePtr);
|
||||
const SceNpCommunicationPassphrase *passph = (const SceNpCommunicationPassphrase *)Memory::GetPointerUnchecked(passPhrasePtr);
|
||||
|
||||
SceNpId npid{};
|
||||
int retval = NpGetNpId(&npid);
|
||||
@@ -372,7 +372,7 @@ static int sceNpMatching2GetServerIdListLocal(MIPSState *mips, int ctxId, u32 se
|
||||
if (!npMatching2Inited)
|
||||
return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!Memory::IsValidRange(serverIdsPtr, maxServerIds * sizeof(u16)))
|
||||
if (maxServerIds < 0 || !Memory::IsValidRange(serverIdsPtr, maxServerIds * sizeof(u16)))
|
||||
return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT);
|
||||
|
||||
// Returning dummy ids, 16-bit variables according to JPCSP
|
||||
@@ -389,7 +389,7 @@ static int sceNpMatching2GetServerInfo(int ctxId, u32 serverIdPtr, u32 unknown1P
|
||||
if (!npMatching2Inited)
|
||||
return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!Memory::IsValidRange(serverIdPtr, 2) || !Memory::IsValid4AlignedRange(unknown2Ptr, 8))
|
||||
if (!Memory::IsValidRange(serverIdPtr, 2) || !Memory::IsValid4AlignedRange(unknown1Ptr, 8) || !Memory::IsValid4AlignedRange(unknown2Ptr, 8))
|
||||
return hleLogError(Log::sceNet, SCE_NP_MATCHING2_ERROR_CONTEXT_MAX); // Should be SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT ?
|
||||
|
||||
// Server ID is a 16-bit variable according to JPCSP
|
||||
|
||||
@@ -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;
|
||||
|
||||
+18
-11
@@ -60,6 +60,11 @@ static int sceUriParse(MIPSState *mips, u32 parsedUriAreaAddr, const char* url,
|
||||
return hleLogDebug(Log::sceNet, 0, "workAreaSize: %d, %d", sz, workAreaSize);
|
||||
}
|
||||
|
||||
// workAreaAddString writes into it unchecked.
|
||||
if (workAreaSize < 0 || !Memory::IsValidRange(workAreaAddr, workAreaSize)) {
|
||||
return hleLogError(Log::sceNet, -1, "invalid work area");
|
||||
}
|
||||
|
||||
auto parsedUri = PSPPointer<PSPParsedUri>::Create(parsedUriAreaAddr);
|
||||
|
||||
// Parse the URL into URI components
|
||||
@@ -172,8 +177,7 @@ static int sceUriBuild(MIPSState *mips, u32 workAreaAddr, u32 workAreaSizeAddr,
|
||||
|
||||
auto getUriComponent = [](u32 addr, int flags, int flagMask) -> std::string {
|
||||
if (addr == 0 || (flags & flagMask) == 0) return "";
|
||||
const char* str = Memory::GetCharPointer(addr);
|
||||
return str ? std::string(str) : "";
|
||||
return Memory::IsValidNullTerminatedString(addr) ? std::string(Memory::GetCharPointerUnchecked(addr)) : "";
|
||||
};
|
||||
|
||||
std::string scheme = getUriComponent(parsedUri->schemeAddr, flags, 0x1);
|
||||
@@ -214,15 +218,12 @@ static int sceUriBuild(MIPSState *mips, u32 workAreaAddr, u32 workAreaSizeAddr,
|
||||
|
||||
if (port > 0) {
|
||||
int defaultPort = -1;
|
||||
if (parsedUri->schemeAddr != 0) {
|
||||
const char* protocol = Memory::GetCharPointer(parsedUri->schemeAddr);
|
||||
if (protocol) {
|
||||
std::string protocolStr(protocol);
|
||||
if (protocolStr == "http") defaultPort = 80;
|
||||
//else if (protocolStr == "https") defaultPort = 443;
|
||||
else if (protocolStr == "ftp") defaultPort = 21;
|
||||
else if (protocolStr == "ssh") defaultPort = 22;
|
||||
}
|
||||
if (Memory::IsValidNullTerminatedString(parsedUri->schemeAddr)) {
|
||||
std::string protocolStr(Memory::GetCharPointerUnchecked(parsedUri->schemeAddr));
|
||||
if (protocolStr == "http") defaultPort = 80;
|
||||
//else if (protocolStr == "https") defaultPort = 443;
|
||||
else if (protocolStr == "ftp") defaultPort = 21;
|
||||
else if (protocolStr == "ssh") defaultPort = 22;
|
||||
}
|
||||
if (port != defaultPort) {
|
||||
uri += ":" + std::to_string(port);
|
||||
@@ -255,6 +256,9 @@ static int sceUriBuild(MIPSState *mips, u32 workAreaAddr, u32 workAreaSizeAddr,
|
||||
if (requiredSize > workAreaSize) {
|
||||
return hleLogError(Log::sceNet, -1, "work area too small: need %d, have %d", requiredSize, workAreaSize);
|
||||
}
|
||||
if (!Memory::IsValidRange(workAreaAddr, requiredSize)) {
|
||||
return hleLogError(Log::sceNet, -1, "invalid work area");
|
||||
}
|
||||
|
||||
Memory::MemcpyUnchecked(workAreaAddr, uri.c_str(), requiredSize);
|
||||
|
||||
@@ -314,6 +318,9 @@ static int sceUriEscape(MIPSState *mips, u32 escapedAddr, u32 escapedLengthAddr,
|
||||
if (requiredSize > escapedBufferLength) {
|
||||
return hleLogError(Log::sceNet, -1, "buffer too small: need %d, have %d", requiredSize, escapedBufferLength);
|
||||
}
|
||||
if (!Memory::IsValidRange(escapedAddr, requiredSize)) {
|
||||
return hleLogError(Log::sceNet, -1, "invalid buffer");
|
||||
}
|
||||
|
||||
std::string escaped = "";
|
||||
|
||||
|
||||
Reference in new issue
Block a user