From 8e6f8de19b9afd2d1ebc3a26e4802bc189ed7673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 9 Oct 2026 14:21:39 +0200 Subject: [PATCH] Kernel: Validate thread, MipsCall and interrupt indices from savestates waitType, thread priorities, MipsCall::numArgs, action type IDs and pending interrupt numbers all index host arrays (some of them function pointer tables) without further checks. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/HLE/sceKernelInterrupt.cpp | 10 ++++++++++ Core/HLE/sceKernelThread.cpp | 15 ++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index b06e780a0e..00be5940c3 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -258,6 +258,16 @@ void __InterruptsDoState(PointerWrap &p) intState.DoState(p); PendingInterrupt pi(0, 0); Do(p, pendingInterrupts, pi); + if (p.mode == p.MODE_READ) { + for (const PendingInterrupt &pend : pendingInterrupts) { + if (pend.intr < 0 || pend.intr >= PSP_NUMBER_INTERRUPTS) { + p.SetError(p.ERROR_FAILURE); + ERROR_LOG(Log::sceIntc, "Savestate failure: invalid pending interrupt %d", pend.intr); + pendingInterrupts.clear(); + return; + } + } + } Do(p, interruptsEnabled); Do(p, inInterrupt); Do(p, threadBeforeInterrupt); diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index f9e37c7a69..98ed74a2ec 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -166,7 +166,7 @@ public: } PSPAction *createActionByType(int actionType) { - if (actionType < (int) types_.size() && types_[actionType] != NULL) { + if (actionType >= 0 && actionType < (int) types_.size() && types_[actionType] != NULL) { PSPAction *a = types_[actionType](); a->actionTypeID = actionType; return a; @@ -475,6 +475,14 @@ void PSPThread::DoState(PointerWrap &p) { } else { waitPausedForCallback = false; } + + // These index waitTypeFuncs and the ready queues. + if (p.mode == p.MODE_READ) { + if ((u32)nt.waitType >= NUM_WAITTYPES || (u32)nt.currentPriority >= ThreadQueueList::NUM_QUEUES || (u32)nt.initialPriority >= ThreadQueueList::NUM_QUEUES) { + ERROR_LOG(Log::sceKernel, "Savestate failure: invalid thread wait type or priority"); + p.SetError(p.ERROR_FAILURE); + } + } } @@ -585,6 +593,11 @@ void MipsCall::DoState(PointerWrap &p) Do(p, cbId); DoArray(p, args, ARRAY_SIZE(args)); Do(p, numArgs); + if (numArgs < 0 || numArgs > (int)ARRAY_SIZE(args)) { + ERROR_LOG(Log::sceKernel, "Savestate failure: invalid MipsCall arg count %d", numArgs); + p.SetError(p.ERROR_FAILURE); + return; + } // No longer used. u32 legacySavedIdRegister = 0; Do(p, legacySavedIdRegister);