mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-14 15:00:30 +02:00
sceIo: Validate PGD block sizes and dir listing state
The PGD block size comes from the file header (or a savestate), and is used to size the block buffer and as a divisor and mask, so require a sane power of two. On load, force the next read to fill the buffer, which isn't saved. sceIoDread only checks the listing index against the end. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
864778a11b
commit
9372d4b490
3 files changed
+34
-1
No files matched your search
+20
-1
@@ -275,7 +275,19 @@ public:
|
||||
if (pgdInfo)
|
||||
p.DoVoid(pgdInfo, sizeof(PGD_DESC));
|
||||
if (p.mode == p.MODE_READ && pgdInfo) {
|
||||
pgdInfo->block_buf = (u8 *)malloc(pgdInfo->block_size * 2);
|
||||
pgdInfo->block_buf = nullptr;
|
||||
if (pgd_valid_block_size(pgdInfo->block_size)) {
|
||||
pgdInfo->block_buf = (u8 *)malloc(pgdInfo->block_size * 2);
|
||||
}
|
||||
if (!pgdInfo->block_buf) {
|
||||
ERROR_LOG(Log::sceIo, "Savestate has an invalid PGD block size");
|
||||
p.SetError(p.ERROR_FAILURE);
|
||||
pgd_close(pgdInfo);
|
||||
pgdInfo = nullptr;
|
||||
return;
|
||||
}
|
||||
// The buffer isn't saved, so make the next read fill it.
|
||||
pgdInfo->current_block = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2510,6 +2522,13 @@ public:
|
||||
// TODO: Is this the right way for it to wake up?
|
||||
int count = (int) listing.size();
|
||||
Do(p, count);
|
||||
// sceIoDread only checks for index == count.
|
||||
if (count < 0 || index < 0 || index > count || !p.CheckRead(count)) {
|
||||
ERROR_LOG(Log::sceIo, "Savestate has an invalid dir listing");
|
||||
p.SetError(p.ERROR_FAILURE);
|
||||
index = 0;
|
||||
return;
|
||||
}
|
||||
listing.resize(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
listing[i].DoState(p);
|
||||
|
||||
@@ -678,6 +678,11 @@ PGD_DESC *pgd_open(KirkState *kirk, u8 *pgd_buf, int pgd_flag, u8 *pgd_vkey)
|
||||
pgd->data_offset = *(u32*)(pgd_buf+0x4c);
|
||||
memcpy(pgd->dkey, pgd_buf+0x30, 16);
|
||||
|
||||
if(!pgd_valid_block_size(pgd->block_size)){
|
||||
free(pgd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pgd->align_size = (pgd->data_size+15)&~15;
|
||||
pgd->table_offset = pgd->data_offset+pgd->align_size;
|
||||
pgd->block_nr = (pgd->align_size+pgd->block_size-1)&~(pgd->block_size-1);
|
||||
@@ -686,6 +691,10 @@ PGD_DESC *pgd_open(KirkState *kirk, u8 *pgd_buf, int pgd_flag, u8 *pgd_vkey)
|
||||
pgd->file_offset = 0;
|
||||
pgd->current_block = -1;
|
||||
pgd->block_buf = (u8*)malloc(pgd->block_size*2);
|
||||
if(pgd->block_buf==NULL){
|
||||
free(pgd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pgd;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,11 @@ typedef struct {
|
||||
u32 file_offset;
|
||||
}PGD_DESC;
|
||||
|
||||
// block_size comes from the file (or a savestate). Reads mask with block_size - 1, so it must be a power of two.
|
||||
static inline int pgd_valid_block_size(u32 block_size) {
|
||||
return block_size >= 16 && block_size <= 0x100000 && (block_size & (block_size - 1)) == 0;
|
||||
}
|
||||
|
||||
|
||||
// type:
|
||||
// 2: use fuse id
|
||||
|
||||
Reference in new issue
Block a user