mirror of
https://github.com/libretro/fuse-libretro.git
synced 2026-11-08 08:09:17 -10:00
libspectrum: fix NULL/short symbol-table crashes in TZX 0x19 blocks
A malformed Generalised Data Block (TZX ID 0x19) can drive the tape state
machine into DATA1 with data_table.symbols == NULL, after which
set_tstates_and_flags() dereferences symbol->lengths and faults on the
near-NULL address 0x8 (the offset of the lengths pointer in
libspectrum_tape_generalised_data_symbol on LP64). Two independent paths
reach this:
1. Empty data table (TOTD == 0): read_symbol_table() allocates nothing,
but generalised_data_edge()'s PILOT->DATA1 transition is taken
unconditionally once the pilot run is exhausted. The subsequent
get_generalised_data_symbol() then also walks block->data with a
bits_per_symbol derived from log(0), overrunning the buffer.
2. Truncated data table (TOTD > 0 but body too short):
tzx_read_generalised_data() ignored the data-table
read_symbol_table() return, so the block was appended with
symbols_in_block > 0 and symbols == NULL. Playback then indexes
table->symbols[current_symbol] and faults at 0x8.
Fixes:
- Check the data-table read_symbol_table() return, mirroring the pilot
table, so a corrupt table rejects the file at parse time (path 2).
- In the PILOT->DATA1 transition, fall through to PAUSE when the data
table / data buffer is absent instead of entering DATA1 (path 1).
- Guard the DATA1 edge itself against a NULL data symbol table as a
belt-and-suspenders backstop.
Reproduced and verified fixed under ASan/UBSan with two crafted fixtures
(the exact 0x8 SEGV for path 2, a heap-overflow for path 1); both are
clean after the fix.
This commit is contained in:
1 parent
ecfee0006d
commit
24fe44eace
2 files changed
+23
-7
No files matched your search
+21
-6
@@ -1012,12 +1012,19 @@ generalised_data_edge( libspectrum_tape_generalised_data_block *block,
|
||||
if( ++state->symbols_through_run == block->pilot_repeats[ state->run ] ) {
|
||||
state->symbols_through_run = 0;
|
||||
if( ++state->run == table->symbols_in_block ) {
|
||||
state->state = LIBSPECTRUM_TAPE_STATE_DATA1;
|
||||
state->bits_through_byte = 0;
|
||||
state->bytes_through_stream = 0;
|
||||
state->symbols_through_stream = 0;
|
||||
state->current_byte = block->data[ 0 ];
|
||||
state->current_symbol = get_generalised_data_symbol( block, state );
|
||||
/* A data table with no symbols leaves data_table.symbols == NULL;
|
||||
entering DATA1 would then dereference a NULL symbol table (and
|
||||
block->data). Skip straight to the tail pause instead. */
|
||||
if( block->data_table.symbols == NULL || block->data == NULL ) {
|
||||
state->state = LIBSPECTRUM_TAPE_STATE_PAUSE;
|
||||
} else {
|
||||
state->state = LIBSPECTRUM_TAPE_STATE_DATA1;
|
||||
state->bits_through_byte = 0;
|
||||
state->bytes_through_stream = 0;
|
||||
state->symbols_through_stream = 0;
|
||||
state->current_byte = block->data[ 0 ];
|
||||
state->current_symbol = get_generalised_data_symbol( block, state );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1025,6 +1032,14 @@ generalised_data_edge( libspectrum_tape_generalised_data_block *block,
|
||||
|
||||
case LIBSPECTRUM_TAPE_STATE_DATA1:
|
||||
table = &( block->data_table );
|
||||
/* Defend against a malformed block that reached DATA1 without a data
|
||||
symbol table (see the PILOT transition above). */
|
||||
if( table->symbols == NULL ) {
|
||||
state->state = LIBSPECTRUM_TAPE_STATE_PAUSE;
|
||||
*tstates = block->pause_tstates;
|
||||
do_tail_pause( tstates, end_of_block, flags );
|
||||
break;
|
||||
}
|
||||
symbol = &( table->symbols[ state->current_symbol ] );
|
||||
|
||||
set_tstates_and_flags( symbol, state->edges_through_symbol, tstates,
|
||||
|
||||
@@ -628,7 +628,8 @@ tzx_read_generalised_data( libspectrum_tape *tape,
|
||||
ptr2 = *ptr;
|
||||
|
||||
table = libspectrum_tape_block_data_table( block );
|
||||
libspectrum_tape_block_read_symbol_table( table, ptr, length );
|
||||
error = libspectrum_tape_block_read_symbol_table( table, ptr, length );
|
||||
if( error ) { libspectrum_tape_block_free( block ); return error; }
|
||||
|
||||
length -= ptr2 - *ptr;
|
||||
|
||||
|
||||
Reference in new issue
Block a user