mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-08 13:50:20 +00:00
fix(libScePngEnc): validate memory, image rows, and PNG output buffers in encoder
This commit is contained in:
1 parent
ec1f584fad
commit
bcffe2e2df
3 files changed
+31
-15
No files matched your search
@@ -97,14 +97,19 @@ int APS5_VABI scePngEncCreate(const PngEncCreateParam* param, void* memoryAddres
|
||||
if (memorySize < requiredSize) return PNG_ENC_ERROR_INVALID_SIZE;
|
||||
if (!handle) return PNG_ENC_ERROR_INVALID_ADDR;
|
||||
const std::uintptr_t aligned = (reinterpret_cast<std::uintptr_t>(memoryAddress) + HANDLE_ALIGNMENT - 1) & ~(HANDLE_ALIGNMENT - 1);
|
||||
auto* ctx = new (reinterpret_cast<void*>(aligned)) PngEncContext{};
|
||||
ctx->self = ctx;
|
||||
ctx->size = sizeof(PngEncCreateParam);
|
||||
ctx->maxImageWidth = (local.max_image_width + 7) & ~std::uint32_t{7};
|
||||
ctx->maxFilterNumber = local.max_filter_number;
|
||||
ctx->scratchSize = requiredSize - 112;
|
||||
PngEncContext localCtx{};
|
||||
localCtx.self = reinterpret_cast<PngEncContext*>(aligned);
|
||||
localCtx.size = sizeof(PngEncCreateParam);
|
||||
localCtx.maxImageWidth = (local.max_image_width + 7) & ~std::uint32_t{7};
|
||||
localCtx.maxFilterNumber = local.max_filter_number;
|
||||
localCtx.scratchSize = requiredSize - 112;
|
||||
if (!GuestCopyOut_nid_no_patch(reinterpret_cast<void*>(aligned), &localCtx, sizeof(localCtx))) {
|
||||
return PNG_ENC_ERROR_INVALID_ADDR;
|
||||
}
|
||||
auto* ctx = reinterpret_cast<PngEncContext*>(aligned);
|
||||
if (!GuestCopyOut_nid_no_patch(handle, &ctx, sizeof(ctx))) {
|
||||
ctx->self = nullptr;
|
||||
PngEncContext cleared{};
|
||||
GuestCopyOut_nid_no_patch(reinterpret_cast<void*>(aligned), &cleared, sizeof(cleared));
|
||||
return PNG_ENC_ERROR_INVALID_ADDR;
|
||||
}
|
||||
return 0;
|
||||
@@ -113,7 +118,8 @@ int APS5_VABI scePngEncCreate(const PngEncCreateParam* param, void* memoryAddres
|
||||
int APS5_VABI scePngEncDelete(void* handle) {
|
||||
PngEncContext* ctx = context(handle);
|
||||
if (!ctx) return PNG_ENC_ERROR_INVALID_HANDLE;
|
||||
ctx->self = nullptr;
|
||||
PngEncContext cleared{};
|
||||
GuestCopyOut_nid_no_patch(ctx, &cleared, sizeof(cleared));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -145,8 +151,12 @@ int APS5_VABI scePngEncEncode(void* handle, const PngEncEncodeParam* param, PngE
|
||||
try {
|
||||
pixels.resize(static_cast<std::size_t>(width) * height * channels);
|
||||
std::uint8_t* destination = pixels.data();
|
||||
const std::size_t rowBytes = static_cast<std::size_t>(width) * 4;
|
||||
std::vector<std::uint8_t> rowBuffer(rowBytes);
|
||||
for (std::uint32_t y = 0; y < height; ++y) {
|
||||
const std::uint8_t* source = localParam.image_mem_addr + static_cast<std::size_t>(y) * localParam.image_pitch;
|
||||
const std::uint8_t* sourceRow = localParam.image_mem_addr + static_cast<std::size_t>(y) * localParam.image_pitch;
|
||||
if (!GuestCopyIn_nid_no_patch(rowBuffer.data(), sourceRow, rowBytes)) return PNG_ENC_ERROR_INVALID_ADDR;
|
||||
const std::uint8_t* source = rowBuffer.data();
|
||||
for (std::uint32_t x = 0; x < width; ++x, source += 4) {
|
||||
*destination++ = source[bgr ? 2 : 0];
|
||||
*destination++ = source[1];
|
||||
@@ -165,7 +175,7 @@ int APS5_VABI scePngEncEncode(void* handle, const PngEncEncodeParam* param, PngE
|
||||
if (!GuestCopyOut_nid_no_patch(outputInfo, &localOutput, sizeof(localOutput))) return PNG_ENC_ERROR_INVALID_ADDR;
|
||||
}
|
||||
if (overflow) return PNG_ENC_ERROR_DATA_OVERFLOW;
|
||||
std::copy(png.begin(), png.end(), localParam.png_mem_addr);
|
||||
if (!GuestCopyOut_nid_no_patch(localParam.png_mem_addr, png.data(), png.size())) return PNG_ENC_ERROR_INVALID_ADDR;
|
||||
return static_cast<int>(png.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ int main() {
|
||||
Require(scePngEncCreate(&create, memory.data(), memorySize, nullptr) == invalidAddr);
|
||||
Require(scePngEncCreate(reinterpret_cast<const PngEncCreateParam*>(0x10), memory.data(), memorySize, &handle) == invalidAddr);
|
||||
Require(scePngEncCreate(&create, memory.data(), memorySize, reinterpret_cast<void**>(0x10)) == invalidAddr);
|
||||
Require(scePngEncCreate(&create, reinterpret_cast<void*>(0x10), memorySize, &handle) == invalidAddr);
|
||||
Require(scePngEncCreate(&create, memory.data(), memorySize - 1, &handle) == invalidSize);
|
||||
Require(scePngEncCreate(&create, memory.data(), memorySize, &handle) == 0 && reinterpret_cast<std::uintptr_t>(handle) % 16 == 0);
|
||||
|
||||
@@ -146,6 +147,8 @@ int main() {
|
||||
Require(scePngEncEncode(handle, &encode, reinterpret_cast<PngEncOutputInfo*>(0x10)) == invalidAddr);
|
||||
invalid.image_mem_addr = nullptr;
|
||||
Require(scePngEncEncode(handle, &invalid, nullptr) == invalidAddr);
|
||||
invalid.image_mem_addr = reinterpret_cast<const std::uint8_t*>(0x10);
|
||||
Require(scePngEncEncode(handle, &invalid, nullptr) == invalidAddr);
|
||||
for (auto change : {+[](PngEncEncodeParam& p) { p.pixel_format = 2; }, +[](PngEncEncodeParam& p) { p.color_space = 4; },
|
||||
+[](PngEncEncodeParam& p) { p.bit_depth = 16; }, +[](PngEncEncodeParam& p) { p.clut_number = 1; },
|
||||
+[](PngEncEncodeParam& p) { p.filter_type = 16; }, +[](PngEncEncodeParam& p) { p.compression_level = 10; }}) {
|
||||
@@ -165,6 +168,8 @@ int main() {
|
||||
invalid = encode;
|
||||
invalid.png_mem_addr = nullptr;
|
||||
Require(scePngEncEncode(handle, &invalid, nullptr) == invalidAddr);
|
||||
invalid.png_mem_addr = reinterpret_cast<std::uint8_t*>(0x10);
|
||||
Require(scePngEncEncode(handle, &invalid, nullptr) == invalidAddr);
|
||||
invalid = encode;
|
||||
invalid.image_mem_size = 0;
|
||||
Require(scePngEncEncode(handle, &invalid, nullptr) == invalidSize);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# libScePngEnc technical debt
|
||||
|
||||
### Functional
|
||||
|
||||
- [scePngEncEncode](../../../core/libs/prx/libScePngEnc/Export.cpp): native filter setup always includes the unfiltered candidate, including for partial masks. The host now permits it too; exact filter-selection ties, compressed bytes and partial-output behavior are not matched to the native encoder. Creation validation, work-memory size, 16-byte handle alignment and the context prefix now match the supplied module. Input-buffer alignment, pitch, dimensions, buffer capacity and selected-filter count now follow the native checks. Host scratch storage remains separately allocated.
|
||||
# libScePngEnc technical debt
|
||||
|
||||
### Functional
|
||||
|
||||
- [libScePngEnc](../../../core/libs/prx/libScePngEnc/Export.cpp) returns SCE_PNG_ENC_ERROR_INVALID_ADDR for unmapped or unwritable pointer arguments and buffers and SCE_PNG_ENC_ERROR_INVALID_HANDLE for an unreadable handle. This is a defensive host-protection fallback; console behaviour for unmapped or read-only memory is unmeasured.
|
||||
- [scePngEncEncode](../../../core/libs/prx/libScePngEnc/Export.cpp): native filter setup always includes the unfiltered candidate, including for partial masks. The host now permits it too; exact filter-selection ties, compressed bytes and partial-output behavior are not matched to the native encoder. Creation validation, work-memory size, 16-byte handle alignment and the context prefix now match the supplied module. Input-buffer alignment, pitch, dimensions, buffer capacity and selected-filter count now follow the native checks. Host scratch storage remains separately allocated.
|
||||
Reference in new issue
Block a user