From 96e2a7e576a3d469aba2647c675be485d2c62200 Mon Sep 17 00:00:00 2001 From: MarcZX10 <67475268+MarcZX10@users.noreply.github.com> Date: Mon, 2 Nov 2026 23:40:38 +0000 Subject: [PATCH 1/2] fix(libSceAjm): check batch job buffer counts before the 8-bit cast sceAjmBatchJobRunSplit cast the size_t buffer counts to 32-bit before the range check in JobRejected, so a count such as 2^32 + 1 was truncated to 1 and accepted, and the job ran with the wrong buffer count. Check the full counts against 0xff first and refuse with the invalid-parameter error the other range checks use. --- core/libs/prx/libSceAjm.native/src/Ajm.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/libs/prx/libSceAjm.native/src/Ajm.cpp b/core/libs/prx/libSceAjm.native/src/Ajm.cpp index dff2f7ab82..a76b820a85 100644 --- a/core/libs/prx/libSceAjm.native/src/Ajm.cpp +++ b/core/libs/prx/libSceAjm.native/src/Ajm.cpp @@ -2064,6 +2064,7 @@ int APS5_VABI sceAjmBatchJobControl(AjmBatchInfo* info, uint32_t instance, uint6 } int APS5_VABI sceAjmBatchJobRunSplit(AjmBatchInfo* info, uint32_t instance, uint64_t flags, const AjmBuffer* input_buffers, size_t input_buffers_num, const AjmBuffer* output_buffers, size_t output_buffers_num, void* sideband_output, size_t sideband_output_size) { + if (input_buffers_num > 0xffu || output_buffers_num > 0xffu) return SCE_AJM_ERROR_INVALID_PARAMETER; auto header = MakeHeader(JobKind::Run, instance, sideband_output, sideband_output_size); header.flags = flags; header.inputCount = static_cast(input_buffers_num); From 9b20e4eb70ceafbba4921cd6d776e54f7f91f236 Mon Sep 17 00:00:00 2001 From: MarcZX10 <67475268+MarcZX10@users.noreply.github.com> Date: Mon, 2 Nov 2026 23:41:06 +0000 Subject: [PATCH 2/2] test(libSceAjm): refuse batch job buffer counts that wrap past 32 bits A run job with 2^32 + 1 input or output buffers must be refused with the invalid-parameter error and leave the batch empty. Before the fix the count was truncated to 1 and the job was appended. --- core/libs/tests/GuestAjm.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/libs/tests/GuestAjm.cpp b/core/libs/tests/GuestAjm.cpp index 007a6beaf0..b3ae2b5f17 100644 --- a/core/libs/tests/GuestAjm.cpp +++ b/core/libs/tests/GuestAjm.cpp @@ -931,6 +931,19 @@ void TestBatchBounds(std::uint32_t context) { #endif } +void TestBatchJobCountRange(std::uint32_t context) { + (void)context; + constexpr int invalidParameter = static_cast(0x80930005); + std::vector storage(256); + AjmBatchInfo info{}; + Require(sceAjmBatchInitialize(storage.data(), storage.size(), &info) == 0); + const AjmBuffer buffer{storage.data(), 16}; + const std::size_t wrapped = (std::size_t{1} << 32) + 1; + Require(sceAjmBatchJobRunSplit(&info, 0, 0, &buffer, wrapped, &buffer, 1, nullptr, 0) == invalidParameter); + Require(sceAjmBatchJobRunSplit(&info, 0, 0, &buffer, 1, &buffer, wrapped, nullptr, 0) == invalidParameter); + Require(info.offset == 0); +} + void TestBatchWaitRelease(std::uint32_t context) { constexpr int invalidBatch = static_cast(0x80930004); std::vector batch(64); @@ -2606,6 +2619,7 @@ int main(int argc, char** argv) { TestGetInfo(context); TestGetStatistics(context); TestBatchBounds(context); + TestBatchJobCountRange(context); TestBatchWaitRelease(context); TestInstanceHandleLifetime(context); TestBatchCancel(context);