From acc7320caec1af614ab9bedc95591c759d5ba990 Mon Sep 17 00:00:00 2001 From: Eladash Date: Mon, 3 Feb 2020 17:31:29 +0200 Subject: [PATCH] Fix cellVdecGetPicItem Fix potential overflow, race condition and correctness fixes for picInfo_addr --- rpcs3/Emu/Cell/Modules/cellVdec.cpp | 36 +++++++++++++++++++---------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellVdec.cpp b/rpcs3/Emu/Cell/Modules/cellVdec.cpp index 359d59443d..c748ab494a 100644 --- a/rpcs3/Emu/Cell/Modules/cellVdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVdec.cpp @@ -833,11 +833,18 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr picItem) // TODO: return CELL_VDEC_ERROR_SEQ + struct all_info_t + { + CellVdecPicItem picItem; + std::aligned_union_t<0, CellVdecAvcInfo, CellVdecDivxInfo, CellVdecMpeg2Info> picInfo; + }; + AVFrame* frame{}; u64 pts; u64 dts; u64 usrd; u32 frc; + vm::ptr info; { std::lock_guard lock(vdec->mutex); @@ -851,6 +858,17 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr picItem) dts = picture.dts; usrd = picture.userdata; frc = picture.frc; + info.set(vdec->mem_addr + vdec->mem_bias); + + constexpr u64 size_needed = sizeof(all_info_t); + + if (vdec->mem_bias + size_needed >= vdec->mem_size / size_needed * size_needed) + { + vdec->mem_bias = 0; + break; + } + + vdec->mem_bias += size_needed; break; } } @@ -862,14 +880,6 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr picItem) return CELL_VDEC_ERROR_EMPTY; } - const vm::ptr info = vm::cast(vdec->mem_addr + vdec->mem_bias); - - vdec->mem_bias += 512; - if (vdec->mem_bias + 512 > vdec->mem_size) - { - vdec->mem_bias = 0; - } - info->codecType = vdec->type; info->startAddr = 0x00000123; // invalid value (no address for picture) const int buffer_size = av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1); @@ -888,11 +898,13 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr picItem) info->auUserData[1] = 0; info->status = CELL_OK; info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL; - info->picInfo_addr = info.addr() + u32{sizeof(CellVdecPicItem)}; + + const vm::addr_t picinfo_addr{info.addr() + ::offset32(&all_info_t::picInfo)}; + info->picInfo_addr = picinfo_addr; if (vdec->type == CELL_VDEC_CODEC_TYPE_AVC) { - const vm::ptr avc = vm::cast(info.addr() + u32{sizeof(CellVdecPicItem)}); + const vm::ptr avc = picinfo_addr; avc->horizontalSize = frame->width; avc->verticalSize = frame->height; @@ -948,7 +960,7 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr picItem) } else if (vdec->type == CELL_VDEC_CODEC_TYPE_DIVX) { - const vm::ptr dvx = vm::cast(info.addr() + u32{sizeof(CellVdecPicItem)}); + const vm::ptr dvx = picinfo_addr; switch (s32 pct = frame->pict_type) { @@ -984,7 +996,7 @@ error_code cellVdecGetPicItem(u32 handle, vm::pptr picItem) } else if (vdec->type == CELL_VDEC_CODEC_TYPE_MPEG2) { - const vm::ptr mp2 = vm::cast(info.addr() + u32{sizeof(CellVdecPicItem)}); + const vm::ptr mp2 = picinfo_addr; std::memset(mp2.get_ptr(), 0, sizeof(CellVdecMpeg2Info)); mp2->horizontal_size = frame->width;