From d0cf945ae2eec3318a0fd6c78d10109af060c012 Mon Sep 17 00:00:00 2001 From: Andre Zeps Date: Thu, 26 Feb 2026 06:16:21 +0100 Subject: [PATCH] CD-i: Buffer overflow fix + Initial default NvRAM (#1106) * CD-i: Fixed buffer overflow Fixed reintroduction of the buffer overflow by commit 1addb89ff Originally was fixed with c0171c9 but not yet well understood. * CD-i: Mount root folder NvRAM after core load Instead of starting with an empty NvRAM, "saves/CD-i/CD-i.sav" will be loaded instead. Avoids machine reset by NvRAM change in case a root folder CD image shall be used --- support/cdi/cdi.cpp | 52 ++++++++++++++++++++++++++------------------- support/cdi/cdi.h | 5 +++++ user_io.cpp | 11 +++++----- user_io.h | 2 ++ 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/support/cdi/cdi.cpp b/support/cdi/cdi.cpp index ea5352e..1ea8538 100644 --- a/support/cdi/cdi.cpp +++ b/support/cdi/cdi.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -40,7 +41,7 @@ struct subcode uint16_t mode1_crc0; uint16_t mode1_crc1; }; -static_assert(sizeof(struct subcode) == 24); +static_assert(sizeof(struct subcode) == CDI_SUBCHANNEL_LEN); struct toc_entry { @@ -51,8 +52,6 @@ struct toc_entry uint8_t f; }; -#define CD_SECTOR_LEN 2352 -#define CDIC_BUFFER_SIZE (CD_SECTOR_LEN + sizeof(subcode)) static std::array toc_buffer; uint32_t toc_entry_count = 0; static enum DiscType disc_type = DT_CDDA; @@ -233,7 +232,7 @@ static int load_cue(const char *filename, toc_t *table) bool modecdi{strstr(lptr, "CDI/2352") != nullptr}; bool audio{strstr(lptr, "AUDIO") != nullptr}; - table->tracks[table->last].sector_size = CD_SECTOR_LEN; + table->tracks[table->last].sector_size = CDI_SECTOR_LEN; if (!table->last) table->end = 150; // implicit 2 seconds pregap for track 1 @@ -315,7 +314,7 @@ static int load_cd_image(const char *filename, toc_t *table) // The real source and how this is calculated is yet unknown // We use sector 00:02:16 as reference as it contains the boot block. // If this is a suitable MODE2 header, we assume it is a CD-i disc - auto buffer = std::make_unique(CDIC_BUFFER_SIZE); + auto buffer = std::make_unique(CDI_CDIC_BUFFER_SIZE); if (buffer) { cdi_read_cd(buffer.get(), 166, 1); @@ -631,7 +630,7 @@ const uint8_t s_sector_scramble[] = void descramble_sector(uint8_t *buffer) { - for (uint32_t i = 12; i < CD_SECTOR_LEN; i++) + for (uint32_t i = 12; i < CDI_SECTOR_LEN; i++) { buffer[i] ^= s_sector_scramble[i - 12]; } @@ -790,11 +789,15 @@ void cdi_read_cd(uint8_t *buffer, int lba, int cnt) { if (lba < 0 || !toc.last) { - memset(buffer, 0, CD_SECTOR_LEN); + // Probably TOC area + memset(buffer, 0, CDI_SECTOR_LEN); + buffer += CDI_SECTOR_LEN; + subcode_data(lba, *reinterpret_cast(buffer)); + buffer += sizeof(struct subcode); } else { - memset(buffer, 0xAA, CD_SECTOR_LEN); + memset(buffer, 0xAA, CDI_SECTOR_LEN); for (int i = 0; i < toc.last; i++) { @@ -804,11 +807,11 @@ void cdi_read_cd(uint8_t *buffer, int lba, int cnt) { if (toc.tracks[i].offset) { - FileSeek(&toc.tracks[0].f, toc.tracks[i].offset + ((lba - toc.tracks[i].start + toc.tracks[i].pregap) * CD_SECTOR_LEN), SEEK_SET); + FileSeek(&toc.tracks[0].f, toc.tracks[i].offset + ((lba - toc.tracks[i].start + toc.tracks[i].pregap) * CDI_SECTOR_LEN), SEEK_SET); } else { - FileSeek(&toc.tracks[i].f, (lba - toc.tracks[i].start + toc.tracks[i].pregap) * CD_SECTOR_LEN, SEEK_SET); + FileSeek(&toc.tracks[i].f, (lba - toc.tracks[i].start + toc.tracks[i].pregap) * CDI_SECTOR_LEN, SEEK_SET); } } @@ -818,11 +821,11 @@ void cdi_read_cd(uint8_t *buffer, int lba, int cnt) { // The "fake" 150 sector pregap moves all the LBAs up by 150, so adjust here to read where the core actually wants data from int read_lba = lba - 150; - if (mister_chd_read_sector(toc.chd_f, (read_lba + toc.tracks[i].offset), 0, 0, CD_SECTOR_LEN, buffer, chd_hunkbuf, &chd_hunknum) == CHDERR_NONE) + if (mister_chd_read_sector(toc.chd_f, (read_lba + toc.tracks[i].offset), 0, 0, CDI_SECTOR_LEN, buffer, chd_hunkbuf, &chd_hunknum) == CHDERR_NONE) { if (!toc.tracks[i].type) // CHD requires byteswap of audio data { - for (int swapidx = 0; swapidx < CD_SECTOR_LEN; swapidx += 2) + for (int swapidx = 0; swapidx < CDI_SECTOR_LEN; swapidx += 2) { uint8_t temp = buffer[swapidx]; buffer[swapidx] = buffer[swapidx + 1]; @@ -838,15 +841,15 @@ void cdi_read_cd(uint8_t *buffer, int lba, int cnt) else { if (toc.tracks[i].offset) - FileReadAdv(&toc.tracks[0].f, buffer, CD_SECTOR_LEN); + FileReadAdv(&toc.tracks[0].f, buffer, CDI_SECTOR_LEN); else - FileReadAdv(&toc.tracks[i].f, buffer, CD_SECTOR_LEN); + FileReadAdv(&toc.tracks[i].f, buffer, CDI_SECTOR_LEN); } if ((lba + 1) > toc.tracks[i].end) break; check_scramble(lba, buffer); - buffer += CD_SECTOR_LEN; + buffer += CDI_SECTOR_LEN; subcode_data(lba, *reinterpret_cast(buffer)); buffer += sizeof(struct subcode); cnt--; @@ -857,8 +860,7 @@ void cdi_read_cd(uint8_t *buffer, int lba, int cnt) } } - buffer += CD_SECTOR_LEN; - subcode_data(lba, *reinterpret_cast(buffer)); + buffer += CDI_SECTOR_LEN; buffer += sizeof(struct subcode); cnt--; lba++; @@ -875,14 +877,14 @@ static void mount_cd(int size, int index) user_io_bufferinvalidate(0); } +/// Last used directory for save file management +/// Must be static to keep the value between mount calls +static char last_dir[1024] = ""; + void cdi_mount_cd(int s_index, const char *filename) { int loaded = 0; - /// Last used directory for save file management - /// Must be static to keep the value between mount calls - static char last_dir[1024] = {}; - if (strlen(filename)) { if (load_cd_image(filename, &toc) && toc.last) @@ -911,7 +913,7 @@ void cdi_mount_cd(int s_index, const char *filename) prepare_toc_buffer(&toc); user_io_set_index(0); - mount_cd(toc.end * CD_SECTOR_LEN, s_index); + mount_cd(toc.end * CDI_SECTOR_LEN, s_index); loaded = 1; } } @@ -928,3 +930,9 @@ void cdi_mount_cd(int s_index, const char *filename) void cdi_poll() { } + +void cdi_load_root_nvram() +{ + strcpy(last_dir, "games/CD-i"); + cdi_mount_save(last_dir); +} diff --git a/support/cdi/cdi.h b/support/cdi/cdi.h index 80a85aa..b799d7e 100644 --- a/support/cdi/cdi.h +++ b/support/cdi/cdi.h @@ -1,11 +1,16 @@ #ifndef CDI_H #define CDI_H +#define CDI_SECTOR_LEN 2352 +#define CDI_SUBCHANNEL_LEN 24 +#define CDI_CDIC_BUFFER_SIZE (CDI_SECTOR_LEN + CDI_SUBCHANNEL_LEN) + void cdi_mount_cd(int s_index, const char *filename); void cdi_fill_blanksave(uint8_t *buffer, uint32_t lba, int cnt); void cdi_read_cd(uint8_t *buffer, int lba, int cnt); int cdi_chd_hunksize(); const char* cdi_get_game_id(); void cdi_poll(); +void cdi_load_root_nvram(); #endif diff --git a/user_io.cpp b/user_io.cpp index 0934b19..e2c47dc 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -1552,6 +1552,7 @@ void user_io_init(const char *path, const char *xml) const char *home = HomeDir(); if (is_uneon()) x86_ide_set(); + if (is_cdi()) cdi_load_root_nvram(); if (!strlen(path) || !user_io_file_tx(path, 0, 0, 0, 1)) { @@ -3107,7 +3108,7 @@ void user_io_poll() int disk = -1; int ack = 0; int op = 0; - static uint8_t buffer[16][16384]; + static uint8_t buffer[16][UIO_BUFFER_SIZE]; uint64_t lba = 0; uint32_t blksz, blks, sz; @@ -3130,7 +3131,7 @@ void user_io_poll() if (disk == 1 && is_psx()) blksz = 2352; else if (disk == 0 && is_cdi()) - blksz = (2352 + 24); + blksz = CDI_CDIC_BUFFER_SIZE; else blksz = 128 << ((c >> 6) & 7); @@ -3265,11 +3266,11 @@ void user_io_poll() unsigned int psx_blksz = psx_chd_hunksize(); if (psx_blksz && psx_blksz <= sizeof(buffer[0])) buf_n = psx_blksz / blksz; } - else if (is_cdi() && blksz == (2352 + 24)) + else if (is_cdi() && blksz == CDI_CDIC_BUFFER_SIZE) { //returns 0 if the mounted disk is not a chd, otherwise returns the chd hunksize in bytes - unsigned int psx_blksz = cdi_chd_hunksize(); - if (psx_blksz && psx_blksz <= sizeof(buffer[0])) buf_n = psx_blksz / blksz; + unsigned int cdi_blksz = cdi_chd_hunksize(); + if (cdi_blksz && cdi_blksz <= sizeof(buffer[0])) buf_n = cdi_blksz / blksz; } //printf("SD RD (%llu,%d) on %d, WIDE=%d\n", lba, blksz, disk, fio_size); diff --git a/user_io.h b/user_io.h index 5b60aaf..79bda2e 100644 --- a/user_io.h +++ b/user_io.h @@ -163,6 +163,8 @@ #define EMU_JOY0 2 #define EMU_JOY1 3 +#define UIO_BUFFER_SIZE 16384 + void user_io_init(const char *path, const char *xml); unsigned char user_io_core_type(); void user_io_read_core_name();