Merge pull request #2395 from ArchitDewan/fix/atrac9-gradient-bounds

fix(ajm): reject ATRAC9 gradients beyond decoder bounds
This commit is contained in:
Adrià 2026-10-11 10:29:27 +02:00 committed by GitHub
commit 40d50b3f16
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 61 additions and 1 deletions

View File

@ -1,6 +1,9 @@
enable_language(C)
set(LIBATRAC9_DIR ${CMAKE_SOURCE_DIR}/3rdparty/LibAtrac9/C/src)
set(LIBATRAC9_PATCHED_DIR ${CMAKE_CURRENT_BINARY_DIR}/atrac9)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${LIBATRAC9_DIR}/unpack.c)
include(${CMAKE_CURRENT_SOURCE_DIR}/PatchLibAtrac9.cmake)
add_library(atrac9 STATIC EXCLUDE_FROM_ALL
${LIBATRAC9_DIR}/band_extension.c
${LIBATRAC9_DIR}/bit_allocation.c
@ -13,9 +16,10 @@ add_library(atrac9 STATIC EXCLUDE_FROM_ALL
${LIBATRAC9_DIR}/quantization.c
${LIBATRAC9_DIR}/scale_factors.c
${LIBATRAC9_DIR}/tables.c
${LIBATRAC9_DIR}/unpack.c
${LIBATRAC9_PATCHED_DIR}/unpack.c
${LIBATRAC9_DIR}/utility.c
)
target_include_directories(atrac9 PRIVATE ${LIBATRAC9_DIR})
set_target_properties(atrac9 PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_library(libSceAjm.native SHARED EXCLUDE_FROM_ALL
@ -31,6 +35,16 @@ target_link_libraries(libSceAjm.native PRIVATE atrac9 ffmpeg libc libkernel)
configure_windows_unwind(libSceAjm.native)
if(BUILD_TESTING)
add_test_executable(atrac9_gradient_tests tests/Atrac9Gradient.c ${LIBATRAC9_DIR}/bit_reader.c)
target_include_directories(atrac9_gradient_tests PRIVATE ${LIBATRAC9_PATCHED_DIR} ${LIBATRAC9_DIR})
target_compile_options(atrac9_gradient_tests PRIVATE -ffunction-sections -fdata-sections)
if(APPLE)
target_link_options(atrac9_gradient_tests PRIVATE LINKER:-dead_strip)
else()
target_link_options(atrac9_gradient_tests PRIVATE LINKER:--gc-sections)
endif()
add_test(NAME atrac9_gradient COMMAND atrac9_gradient_tests)
add_test_executable(guest_ajm_tests ${LIBS_INCLUDE_DIR}/tests/GuestAjm.cpp)
target_include_directories(guest_ajm_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_ajm_tests PRIVATE libSceAjm.native libc)

View File

@ -0,0 +1,10 @@
file(READ ${LIBATRAC9_DIR}/unpack.c libatrac9Unpack)
set(libatrac9OldGuard "block->GradientEndUnit < 0 || block->GradientEndUnit >= 48")
set(libatrac9NewGuard "block->GradientEndUnit < 0 || block->GradientEndUnit > 31")
string(FIND "${libatrac9Unpack}" "${libatrac9OldGuard}" libatrac9GuardPosition)
if(libatrac9GuardPosition EQUAL -1)
message(FATAL_ERROR "LibAtrac9 gradient guard has changed; review the local bounds fix")
endif()
string(REPLACE "${libatrac9OldGuard}" "${libatrac9NewGuard}" libatrac9Unpack "${libatrac9Unpack}")
file(MAKE_DIRECTORY ${LIBATRAC9_PATCHED_DIR})
file(WRITE ${LIBATRAC9_PATCHED_DIR}/unpack.c "${libatrac9Unpack}")

View File

@ -0,0 +1,36 @@
#include "unpack.c"
#include <stdlib.h>
static void WriteBits(unsigned char* data, int* position, int value, int width)
{
for (int bit = width - 1; bit >= 0; --bit)
{
int offset = (*position)++;
data[offset / 8] |= (unsigned char)(((value >> bit) & 1) << (7 - offset % 8));
}
}
static At9Status GradientStatus(int endUnit)
{
unsigned char data[4] = {0};
int position = 0;
WriteBits(data, &position, 0, 2);
WriteBits(data, &position, 0, 6);
WriteBits(data, &position, endUnit - 1, 6);
WriteBits(data, &position, 0, 5);
WriteBits(data, &position, 0, 5);
WriteBits(data, &position, 0, 4);
Block block = {0};
BitReaderCxt reader;
InitBitReaderCxt(&reader, data, sizeof(data));
return ReadGradientParams(&block, &reader);
}
int main(void)
{
if (GradientStatus(31) != ERR_SUCCESS) return EXIT_FAILURE;
if (GradientStatus(32) != ERR_UNPACK_GRAD_END_UNIT_OOB) return EXIT_FAILURE;
if (GradientStatus(47) != ERR_UNPACK_GRAD_END_UNIT_OOB) return EXIT_FAILURE;
return EXIT_SUCCESS;
}