1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 18:53:28 +01:00

sys_spu: protect sys_spu_image members in kernel mode

Save relevant info in idm, set sys_spu_image segs and nsegs members to 0.
This commit is contained in:
Eladash 2020-01-21 18:40:12 +02:00 committed by Ani
parent 8a176de6a1
commit fad8b38b28
3 changed files with 57 additions and 20 deletions

View File

@ -1132,6 +1132,7 @@ void spu_thread::cpu_task()
skip_npc_set = false;
// Note: works both on RawSPU and threaded SPU!
set_interrupt_status((pc & 1) != 0);
pc &= 0x3fffc;

View File

@ -45,26 +45,31 @@ void sys_spu_image::load(const fs::file& stream)
}
}
type = SYS_SPU_IMAGE_TYPE_KERNEL;
nsegs = sys_spu_image::get_nsegs(obj.progs);
this->type = SYS_SPU_IMAGE_TYPE_KERNEL;
const s32 nsegs = sys_spu_image::get_nsegs(obj.progs);
const u32 mem_size = nsegs * sizeof(sys_spu_segment) + ::size32(stream);
segs = vm::cast(vm::alloc(mem_size, vm::main));
const vm::ptr<sys_spu_segment> segs = vm::cast(vm::alloc(mem_size, vm::main));
// Write ID and save entry
entry_point = idm::make<lv2_obj, lv2_spu_image>(+obj.header.e_entry);
const u32 entry = obj.header.e_entry;
const u32 src = segs.addr() + nsegs * sizeof(sys_spu_segment);
stream.seek(0);
stream.read(vm::base(src), stream.size());
if (nsegs < 0 || sys_spu_image::fill(segs, nsegs, obj.progs, src) != nsegs)
if (nsegs <= 0 || nsegs > 0x20 || sys_spu_image::fill(segs, nsegs, obj.progs, src) != nsegs)
{
fmt::throw_exception("Failed to load SPU segments (%d)" HERE, nsegs);
}
// Write ID and save entry
this->entry_point = idm::make<lv2_obj, lv2_spu_image>(+obj.header.e_entry, segs, nsegs);
// Unused and set to 0
this->nsegs = 0;
this->segs = vm::null;
vm::page_protect(segs.addr(), ::align(mem_size, 4096), 0, 0, vm::page_writable);
}
@ -200,7 +205,7 @@ error_code _sys_spu_image_get_information(ppu_thread& ppu, vm::ptr<sys_spu_image
}
*entry_point = image->e_entry;
*nsegs = img->nsegs;
*nsegs = image->nsegs;
return CELL_OK;
}
@ -243,12 +248,14 @@ error_code _sys_spu_image_close(ppu_thread& ppu, vm::ptr<sys_spu_image> img)
return CELL_EINVAL;
}
if (!idm::remove<lv2_obj, lv2_spu_image>(img->entry_point))
const auto handle = idm::withdraw<lv2_obj, lv2_spu_image>(img->entry_point);
if (!handle)
{
return CELL_ESRCH;
}
vm::dealloc(img->segs.addr(), vm::main);
verify(HERE), vm::dealloc(handle->segs.addr(), vm::main);
return CELL_OK;
}
@ -258,8 +265,20 @@ error_code _sys_spu_image_get_segments(ppu_thread& ppu, vm::ptr<sys_spu_image> i
sys_spu.error("_sys_spu_image_get_segments(img=*0x%x, segments=*0x%x, nseg=%d)", img, segments, nseg);
if (nseg <= 0 || nseg > 0x20 || img->type != SYS_SPU_IMAGE_TYPE_KERNEL)
{
return CELL_EINVAL;
}
const auto handle = idm::get<lv2_obj, lv2_spu_image>(img->entry_point);
if (!handle)
{
return CELL_ESRCH;
}
// TODO: apply SPU patches
std::memcpy(segments.get_ptr(), img->segs.get_ptr(), sizeof(sys_spu_segment) * nseg);
std::memcpy(segments.get_ptr(), handle->segs.get_ptr(), sizeof(sys_spu_segment) * std::min<s32>(nseg, handle->nsegs));
return CELL_OK;
}
@ -274,14 +293,11 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
return CELL_EINVAL;
}
if (img->type != SYS_SPU_IMAGE_TYPE_KERNEL && img->type != SYS_SPU_IMAGE_TYPE_USER)
sys_spu_image image;
switch (img->type)
{
return CELL_EINVAL;
}
sys_spu_image image = *img;
if (img->type == SYS_SPU_IMAGE_TYPE_KERNEL)
case SYS_SPU_IMAGE_TYPE_KERNEL:
{
const auto handle = idm::get<lv2_obj, lv2_spu_image>(img->entry_point);
@ -290,8 +306,24 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
return CELL_ESRCH;
}
// Save actual entry point
// Image information is stored in IDM
image.entry_point = handle->e_entry;
image.nsegs = handle->nsegs;
image.segs = handle->segs;
image.type = SYS_SPU_IMAGE_TYPE_KERNEL;
break;
}
case SYS_SPU_IMAGE_TYPE_USER:
{
if (img->entry_point > 0x3fffc || img->nsegs <= 0 || img->nsegs > 0x20)
{
return CELL_EINVAL;
}
image = *img;
break;
}
default: return CELL_EINVAL;
}
// Read thread name

View File

@ -225,9 +225,13 @@ struct lv2_spu_image : lv2_obj
static const u32 id_base = 0x22000000;
const u32 e_entry;
const vm::ptr<sys_spu_segment> segs;
const s32 nsegs;
lv2_spu_image(u32 entry)
lv2_spu_image(u32 entry, vm::ptr<sys_spu_segment> segs, s32 nsegs)
: e_entry(entry)
, segs(segs)
, nsegs(nsegs)
{
}
};