From 74586bab5778c4da9475b175c2ee82787d212f9f Mon Sep 17 00:00:00 2001 From: RomainROCH Date: Fri, 2 Oct 2026 06:19:39 +0200 Subject: [PATCH] fix(libkernel): avoid semaphore count overflow --- .../prx/libkernel/Semaphore/src/Semaphore.cpp | 2 +- core/libs/tests/GuestKernelErrors.cpp | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/core/libs/prx/libkernel/Semaphore/src/Semaphore.cpp b/core/libs/prx/libkernel/Semaphore/src/Semaphore.cpp index 6c5e07d24..0fecf4253 100644 --- a/core/libs/prx/libkernel/Semaphore/src/Semaphore.cpp +++ b/core/libs/prx/libkernel/Semaphore/src/Semaphore.cpp @@ -41,7 +41,7 @@ int APS5_VABI sceKernelSignalSema(KernelSema sem, int count) { } std::lock_guard lock(sem->mutex); - if (sem->tokenCount + count > sem->maxCount) { + if (count > sem->maxCount - sem->tokenCount) { return SCE_KERNEL_ERROR_EINVAL; } sem->tokenCount += count; diff --git a/core/libs/tests/GuestKernelErrors.cpp b/core/libs/tests/GuestKernelErrors.cpp index 972d74aa0..045ced418 100644 --- a/core/libs/tests/GuestKernelErrors.cpp +++ b/core/libs/tests/GuestKernelErrors.cpp @@ -1,9 +1,14 @@ #include "SceTypes.hpp" #include #include +#include #include extern "C" { +int APS5_VABI sceKernelCreateSema(KernelSema*, const char*, std::uint32_t, int, int, void*); +int APS5_VABI sceKernelDeleteSema(KernelSema); +int APS5_VABI sceKernelSignalSema(KernelSema, int); +int APS5_VABI sceKernelPollSema(KernelSema, int); int APS5_VABI sceKernelCreateEqueue(KernelEqueue* eq, const char* name); int APS5_VABI sceKernelDeleteEqueue(KernelEqueue eq); int APS5_VABI sceKernelWaitEqueue(KernelEqueue eq, KernelEvent* ev, int num, int* out, const KernelUseconds* timo); @@ -33,6 +38,22 @@ static constexpr int PRIO_PROTECT = 2; static void Require(bool value) { if (!value) std::abort(); } int main() { + constexpr int maximum = std::numeric_limits::max(); + KernelSema semaphore = nullptr; + Require(sceKernelCreateSema(&semaphore, "overflow", 1, maximum - 1, maximum, nullptr) == SCE_OK); + Require(sceKernelSignalSema(semaphore, 2) == SCE_KERNEL_ERROR_EINVAL); + Require(sceKernelSignalSema(semaphore, maximum) == SCE_KERNEL_ERROR_EINVAL); + Require(sceKernelPollSema(semaphore, maximum - 1) == SCE_OK); + Require(sceKernelSignalSema(semaphore, maximum) == SCE_OK); + Require(sceKernelSignalSema(semaphore, 1) == SCE_KERNEL_ERROR_EINVAL); + Require(sceKernelPollSema(semaphore, maximum) == SCE_OK); + Require(sceKernelDeleteSema(semaphore) == SCE_OK); + Require(sceKernelCreateSema(&semaphore, "limit", 1, 1, 3, nullptr) == SCE_OK); + Require(sceKernelSignalSema(semaphore, 3) == SCE_KERNEL_ERROR_EINVAL); + Require(sceKernelSignalSema(semaphore, 2) == SCE_OK); + Require(sceKernelPollSema(semaphore, 3) == SCE_OK); + Require(sceKernelDeleteSema(semaphore) == SCE_OK); + KernelEqueue eq = 0; Require(sceKernelCreateEqueue(&eq, "errors") == SCE_OK); KernelEvent event{};