Repository navigation
Conversation
added 2 commits
October 13, 2026 20:47
The CD track metadata formats are used by downstream readers with sscanf, and their %s fields write as much as the CHD's metadata string holds - a crafted image overflows the caller's buffer (rtissera#165). Width-limiting the existing *_FORMAT macros is not an option: the same macros are used to write metadata, and in printf a width pads instead of limiting, so writers would emit space-padded TYPE fields. Add CDROM_TRACK_METADATA_SCANF, CDROM_TRACK_METADATA2_SCANF and GDROM_TRACK_METADATA_SCANF alongside them, bounded to CD_METADATA_STRING_SIZE (16; the longest real value, MODE2_FORM_MIX, is 14 characters). tests/metadata_scanf.c checks the bounds with canaries and needs no corpus.
Every CD consumer of libchdr re-derives the same thing from the track metadata: where a track's frames start in the CHD once each track is padded to four frames, whether its pregap is stored, and which hunk and frame an LBA lands in (rtissera#155). chd_cd_open() parses CHT2/CHTR/CHGD metadata into a public TOC and chd_cd_read_sector() reads one sector by LBA - 2048 bytes of user data, the raw sector as a .bin holds it (audio little-endian), or the subcode. Addressing follows MAME's cdrom_file: unstored pregaps and postgaps take LBAs and read as zeros. The handle keeps the last decoded hunk, so sequential reads decode each hunk once. MSF callers use the existing msf_to_lba(). Track metadata is parsed with the bounded *_SCANF formats, and offsets are accumulated in 64 bits and rejected past 32, so crafted metadata yields CHDERR_INVALID_METADATA rather than wrapped offsets. tests/cd_toc.c reads every LBA of a generated three-track CD (stored pregap, unstored pregap, odd track lengths) and compares it with the BIN it was built from.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #155. Stacked on #199, since it parses metadata with the bounded formats from that PR. Only the last commit is new.
Every CD consumer redoes the same arithmetic from track metadata: per-track padding to
CD_TRACK_PADDINGframes, whether a pregap is stored, and which hunk and frame an LBA falls in. This PR moves that into libchdr, ported from MAME'scdrom_file.API (
cdrom.h, allchd_cd_*so the export filter keeps them)whatis one of:CHD_CD_READ_DATA: 2048 bytes of user data (MODE1/MODE2 offsets handled)CHD_CD_READ_RAW: 2352 bytes, the same as a.bin(audio swapped back to little-endian; legacy CHGT GD-ROMs left as they are)CHD_CD_READ_SUBCODE: 96 bytesBehaviour
CHCDand multi-sessionCHSEaren't read yet (marked in the code).CHDERR_INVALID_METADATA.msf_to_lba().Tests
generate.shnow buildstests/corpus/cd/, a 3-track disc (MODE1 data, audio with a stored INDEX 00 pregap, audio with an unstoredPREGAP, odd lengths to force padding), and keeps the source BIN.tests/cd_toc.c(cd-toc) checks the TOC and reads all 926 LBAs against the BIN. It skips when the corpus isn't generated, like the other corpus tests.Tested on Ubuntu 24.04 with chdman 0.264 (GCC, ASan/UBSan) and Windows (MinGW). On Windows the corpus tests skip.