diff --git a/Core/Dialog/PSPDialog.cpp b/Core/Dialog/PSPDialog.cpp index ac554c6e4f..c87a35dc1a 100644 --- a/Core/Dialog/PSPDialog.cpp +++ b/Core/Dialog/PSPDialog.cpp @@ -394,6 +394,20 @@ void PSPDialog::DisplayButtons(int flags, std::string_view caption) { } } +int PSPDialog::CheckRequest(u32 addr, std::initializer_list sizes) { + if (!Memory::IsValidRange(addr, sizeof(pspUtilityDialogCommon))) { + return SCE_ERROR_UTILITY_INVALID_ADDRESS; + } + const u32 size = Memory::ReadUnchecked_U32(addr); + if (std::find(sizes.begin(), sizes.end(), size) == sizes.end()) { + return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; + } + if (!Memory::IsValidRange(addr, size)) { + return SCE_ERROR_UTILITY_INVALID_ADDRESS; + } + return 0; +} + int PSPDialog::GetConfirmButton() { if (PSP_CoreParameter().compat.flags().ForceCircleButtonConfirm) { return CTRL_CIRCLE; diff --git a/Core/Dialog/PSPDialog.h b/Core/Dialog/PSPDialog.h index 9f0320305e..7272225533 100644 --- a/Core/Dialog/PSPDialog.h +++ b/Core/Dialog/PSPDialog.h @@ -17,6 +17,8 @@ #pragma once +#include + #include "Common/CommonTypes.h" #include "Common/Render/TextureAtlas.h" #include "Common/Swap.h" @@ -114,6 +116,9 @@ protected: } static int GetConfirmButton(); + // What every InitStart checks first in sceUtility_Driver: the address, then the size against + // the ones that type accepts (utility/dialog/sizes), then the rest of the range. + static int CheckRequest(u32 addr, std::initializer_list sizes); static int GetCancelButton(); void StartFade(bool fadeIn_); diff --git a/Core/Dialog/PSPGamedataInstallDialog.cpp b/Core/Dialog/PSPGamedataInstallDialog.cpp index 8985cfc462..3939d61714 100644 --- a/Core/Dialog/PSPGamedataInstallDialog.cpp +++ b/Core/Dialog/PSPGamedataInstallDialog.cpp @@ -61,10 +61,10 @@ int PSPGamedataInstallDialog::Init(u32 paramAddr) { return SCE_ERROR_UTILITY_INVALID_STATUS; } - if (!Memory::IsValidRange(paramAddr, sizeof(SceUtilityGamedataInstallParam))) { - // This should probably crash - ERROR_LOG(Log::sceUtility, "sceGamedataInstallInitStart: invalid param address 0x%08X", paramAddr); - return SCE_KERNEL_ERROR_INVALID_POINTER; + const int check = CheckRequest(paramAddr, { 1424, 1432 }); + if (check < 0) { + ERROR_LOG(Log::sceUtility, "sceGamedataInstallInitStart: bad request at %08x: %08x", paramAddr, check); + return check; } param.ptr = paramAddr; @@ -88,11 +88,6 @@ int PSPGamedataInstallDialog::Init(u32 paramAddr) { } const int size = Memory::ReadUnchecked_U32(paramAddr); - if (size != 1424 && size != 1432) { - ERROR_LOG_REPORT(Log::sceUtility, "sceGamedataInstallInitStart: invalid param size %d", size); - return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; - } - memset(&request, 0, sizeof(request)); // Only copy the right size to support different request format Memory::Memcpy(&request, paramAddr, size, "sceGamedataInstallInitStart"); diff --git a/Core/Dialog/PSPHtmlViewerDialog.cpp b/Core/Dialog/PSPHtmlViewerDialog.cpp index 7f83874e54..391a4d5185 100644 --- a/Core/Dialog/PSPHtmlViewerDialog.cpp +++ b/Core/Dialog/PSPHtmlViewerDialog.cpp @@ -52,23 +52,10 @@ struct SceUtilityHtmlViewerParam { }; // From sceUtility_Driver's InitStart for the HtmlViewer, firmware 6.61: the request size says which -// firmware's layout it is, and the working memory it allocates for the browser depends on that and -// on bit 0x400 of options. Any other size is INVALID_PARAM_SIZE. -static bool HtmlViewerWorkSize(u32 size, u32 options, u32 *workSize) { - switch (size) { - case 0x70: // 2.00 - case 0x78: // 2.50 - case 0x80: // 2.60 - *workSize = 0x380000; - return true; - case 0x98: // 2.70 - case 0xA4: // 2.80 - case 0xA8: // 3.00 - *workSize = (options & 0x400) ? 0x480000 : 0x380000; - return true; - default: - return false; - } +// firmware's layout it is: 0x70, 0x78 and 0x80 are 2.00 to 2.60, 0x98, 0xA4 and 0xA8 2.70 to 3.00. +// The working memory it allocates for the browser depends on that and on bit 0x400 of options. +static u32 HtmlViewerWorkSize(u32 size, u32 options) { + return size >= 0x98 && (options & 0x400) ? 0x480000 : 0x380000; } static std::string ReadUrl(u32 addr) { @@ -99,18 +86,13 @@ int PSPHtmlViewerDialog::Init(u32 paramAddr) { if (GetStatus() != SCE_UTILITY_STATUS_NONE) { return SCE_ERROR_UTILITY_INVALID_STATUS; } - if (!Memory::IsValidRange(paramAddr, sizeof(pspUtilityDialogCommon))) { - return SCE_ERROR_UTILITY_INVALID_ADDRESS; + const int check = CheckRequest(paramAddr, { 0x70, 0x78, 0x80, 0x98, 0xA4, 0xA8 }); + if (check < 0) { + return check; } const u32 size = Memory::ReadUnchecked_U32(paramAddr); const SceUtilityHtmlViewerParam *param = (const SceUtilityHtmlViewerParam *)Memory::GetPointerUnchecked(paramAddr); - u32 workSize = 0; - if (!HtmlViewerWorkSize(size, param->options, &workSize)) { - return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; - } - if (!Memory::IsValidRange(paramAddr, size)) { - return SCE_ERROR_UTILITY_INVALID_ADDRESS; - } + u32 workSize = HtmlViewerWorkSize(size, param->options); u32 addr = userMemory.Alloc(workSize, false, "HtmlViewer"); if (addr == (u32)-1) { diff --git a/Core/Dialog/PSPMsgDialog.cpp b/Core/Dialog/PSPMsgDialog.cpp index 965695e38b..ff6064f78a 100755 --- a/Core/Dialog/PSPMsgDialog.cpp +++ b/Core/Dialog/PSPMsgDialog.cpp @@ -56,18 +56,16 @@ int PSPMsgDialog::Init(unsigned int paramAddr) { return SCE_ERROR_UTILITY_INVALID_STATUS; } + const int check = CheckRequest(paramAddr, { SCE_UTILITY_MSGDIALOG_SIZE_V1, SCE_UTILITY_MSGDIALOG_SIZE_V2, SCE_UTILITY_MSGDIALOG_SIZE_V3 }); + if (check < 0) { + return check; + } + if (!Memory::IsValid4AlignedAddress(paramAddr)) { + return SCE_KERNEL_ERROR_BAD_ARGUMENT; // untested + } messageDialogAddr = paramAddr; - if (!Memory::IsValid4AlignedAddress(paramAddr)) { - // What to do? - return SCE_KERNEL_ERROR_BAD_ARGUMENT; - } - int size = Memory::ReadUnchecked_U32(paramAddr); - // The only sizes sceUtility_Driver accepts (utility/dialog/sizes). - if (size != SCE_UTILITY_MSGDIALOG_SIZE_V1 && size != SCE_UTILITY_MSGDIALOG_SIZE_V2 && size != SCE_UTILITY_MSGDIALOG_SIZE_V3) { - return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; - } memset(&messageDialog, 0, sizeof(messageDialog)); // Only copy the right size to support different request format Memory::Memcpy(&messageDialog,paramAddr,size); diff --git a/Core/Dialog/PSPNetconfDialog.cpp b/Core/Dialog/PSPNetconfDialog.cpp index 08572b9d34..b361a0e886 100644 --- a/Core/Dialog/PSPNetconfDialog.cpp +++ b/Core/Dialog/PSPNetconfDialog.cpp @@ -60,16 +60,21 @@ int PSPNetconfDialog::Init(u32 paramAddr) { if (ReadStatus() != SCE_UTILITY_STATUS_NONE) return SCE_ERROR_UTILITY_INVALID_STATUS; + const int check = CheckRequest(paramAddr, { 0x38, 0x40, 0x44 }); + if (check < 0) { + return check; + } + + if (!ReadVariableSizedStruct(paramAddr, &request)) { + return SCE_KERNEL_ERROR_BAD_ARGUMENT; // untested, it's misaligned + } + requestAddr = paramAddr; + NOTICE_LOG(Log::sceUtility, "PSPNetConfDialog Init"); jsonReady_ = false; // Kick off a request to the infra-dns.json since we'll need it later. StartInfraJsonDownload(); - requestAddr = paramAddr; - if (!ReadVariableSizedStruct(paramAddr, &request)) { - return SCE_KERNEL_ERROR_BAD_ARGUMENT; // untested - } - ChangeStatusInit(NET_INIT_DELAY_US); // Eat any keys pressed before the dialog inited. @@ -340,7 +345,7 @@ int PSPNetconfDialog::Update(int animSpeed) { } if (ReadStatus() == SCE_UTILITY_STATUS_FINISHED || pendingStatus == SCE_UTILITY_STATUS_FINISHED) - Memory::Memcpy(requestAddr, &request, request.common.size, "NetConfDialogParam"); + Memory::Memcpy(requestAddr, &request, std::min((u32)request.common.size, (u32)sizeof(request)), "NetConfDialogParam"); return 0; } diff --git a/Core/Dialog/PSPNpSigninDialog.cpp b/Core/Dialog/PSPNpSigninDialog.cpp index ecc2feb4ca..064c54fb11 100644 --- a/Core/Dialog/PSPNpSigninDialog.cpp +++ b/Core/Dialog/PSPNpSigninDialog.cpp @@ -43,11 +43,16 @@ int PSPNpSigninDialog::Init(u32 paramAddr) { if (ReadStatus() != SCE_UTILITY_STATUS_NONE) return SCE_ERROR_UTILITY_INVALID_STATUS; - requestAddr = paramAddr; - if (!ReadVariableSizedStruct(paramAddr, &request)) { - return SCE_KERNEL_ERROR_BAD_ARGUMENT; // untested + const int check = CheckRequest(paramAddr, { 0x40 }); + if (check < 0) { + return check; } + if (!ReadVariableSizedStruct(paramAddr, &request)) { + return SCE_KERNEL_ERROR_BAD_ARGUMENT; // untested, it's misaligned + } + requestAddr = paramAddr; + WARN_LOG_REPORT_ONCE(PSPNpSigninDialogInit, Log::sceNet, "NpSignin Init Params: %08x, %08x, %08x, %08x", request.npSigninStatus, request.unknown1, request.unknown2, request.unknown3); ChangeStatusInit(NP_INIT_DELAY_US); @@ -172,7 +177,7 @@ int PSPNpSigninDialog::Shutdown(bool force) { // FIXME: This should probably be done within FinishShutdown to prevent some games (ie. UNO) from progressing further while the Dialog is still being faded-out, since we can't override non-virtual method... so here is the closes one to FinishShutdown. if (Memory::IsValidAddress(requestAddr)) // Need to validate first to prevent Invalid address when the game is being Shutdown/Exited to menu - Memory::Memcpy(requestAddr, &request, request.common.size, "NpSigninDialogParam"); + Memory::Memcpy(requestAddr, &request, std::min((u32)request.common.size, (u32)sizeof(request)), "NpSigninDialogParam"); return 0; } diff --git a/Core/Dialog/PSPPlaceholderDialog.cpp b/Core/Dialog/PSPPlaceholderDialog.cpp index 85c9415b0c..3f0a7d9565 100644 --- a/Core/Dialog/PSPPlaceholderDialog.cpp +++ b/Core/Dialog/PSPPlaceholderDialog.cpp @@ -31,16 +31,15 @@ int PSPPlaceholderDialog::Init(u32 paramAddr) { if (ReadStatus() != SCE_UTILITY_STATUS_NONE) { return SCE_ERROR_UTILITY_INVALID_STATUS; } + // The request sizes a PSP accepts for GameSharing. + const int check = DialogType() == UtilityDialogType::GAMESHARING ? CheckRequest(paramAddr, { 0x50, 0x54, 0x64 }) : 0; + if (check < 0) { + return check; + } if (!Memory::IsValidRange(paramAddr, sizeof(pspUtilityDialogCommon))) { return SCE_KERNEL_ERROR_BAD_ARGUMENT; } params_ = paramAddr; - // The request sizes a PSP accepts for GameSharing. - const u32 size = params_->size; - if (DialogType() == UtilityDialogType::GAMESHARING && size != 0x50 && size != 0x54 && size != 0x64) { - params_ = 0; - return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; - } ChangeStatusInit(PLACEHOLDER_INIT_DELAY_US); InitCommon(); diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index 271f3baae9..08a9b88078 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -127,6 +127,11 @@ int PSPSaveDialog::Init(int paramAddr) { ioThreadStatus = SAVEIO_NONE; requestAddr = 0; + const int check = CheckRequest(paramAddr, { SAVEDATA_DIALOG_SIZE_V1, SAVEDATA_DIALOG_SIZE_V2, SAVEDATA_DIALOG_SIZE_V3 }); + if (check < 0) { + ERROR_LOG(Log::sceUtility, "sceUtilitySavedataInitStart: bad request at %08x: %08x", paramAddr, check); + return check; + } if (!Memory::IsValid4AlignedAddress(paramAddr)) { return SCE_KERNEL_ERROR_BAD_ARGUMENT; // untested } @@ -134,11 +139,6 @@ int PSPSaveDialog::Init(int paramAddr) { int size = Memory::ReadUnchecked_U32(requestAddr); memset(&request, 0, sizeof(request)); - // Only copy the right size to support different save request format - if (size != SAVEDATA_DIALOG_SIZE_V1 && size != SAVEDATA_DIALOG_SIZE_V2 && size != SAVEDATA_DIALOG_SIZE_V3) { - ERROR_LOG_REPORT(Log::sceUtility, "sceUtilitySavedataInitStart: invalid size %d", size); - return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; - } Memory::Memcpy(&request, requestAddr, size); Memory::Memcpy(&originalRequest, requestAddr, size); diff --git a/Core/Dialog/PSPScreenshotDialog.cpp b/Core/Dialog/PSPScreenshotDialog.cpp index 83f0d87b21..dcef0c30c5 100644 --- a/Core/Dialog/PSPScreenshotDialog.cpp +++ b/Core/Dialog/PSPScreenshotDialog.cpp @@ -66,22 +66,12 @@ int PSPScreenshotDialog::Init(u32 paramAddr) { return SCE_ERROR_UTILITY_INVALID_STATUS; } + const int check = CheckRequest(paramAddr, { SCE_UTILITY_SCREENSHOTDIALOG_SIZE_V1, SCE_UTILITY_SCREENSHOTDIALOG_SIZE_V2, SCE_UTILITY_SCREENSHOTDIALOG_SIZE_V3 }); + if (check < 0) { + ERROR_LOG(Log::HLE, "sceUtilityScreenshotInitStart(%08x): bad request: %08x", paramAddr, check); + return check; + } params_ = PSPPointer::Create(paramAddr); - if (!params_.IsValid()) { - ERROR_LOG_REPORT(Log::HLE, "sceUtilityScreenshotInitStart(%08x): invalid pointer", paramAddr); - return SCE_KERNEL_ERROR_INVALID_POINTER; - } - - switch ((u32)params_->base.size) { - case SCE_UTILITY_SCREENSHOTDIALOG_SIZE_V1: - case SCE_UTILITY_SCREENSHOTDIALOG_SIZE_V2: - case SCE_UTILITY_SCREENSHOTDIALOG_SIZE_V3: - break; - - default: - ERROR_LOG_REPORT(Log::HLE, "sceUtilityScreenshotInitStart(%08x): invalid size %d", paramAddr, (u32)params_->base.size); - return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; - } mode = params_->mode; ChangeStatus(SCE_UTILITY_STATUS_INITIALIZE, 0); diff --git a/test.py b/test.py index 51b13df6a1..0900273693 100755 --- a/test.py +++ b/test.py @@ -428,6 +428,7 @@ tests_good = [ "utility/dialog/abort", "utility/dialog/htmlviewer", "utility/dialog/priority", + "utility/dialog/sizes", "utility/dialog/status", "utility/msgdialog/abort", "utility/savedata/autosave",