formats/cassimg.cpp: Fixed bad image crash in tap format (MT8952)

This commit is contained in:
Andrei Holub 2025-01-28 19:44:20 -05:00
parent 55e8b75801
commit 8d346a669e
3 changed files with 45 additions and 50 deletions

View File

@ -798,7 +798,7 @@ cassette_image::error cassette_image::legacy_construct(const LegacyWaveFiller *l
/* sanity check the args */
assert(legacy_args->header_samples >= -1);
assert(legacy_args->trailer_samples >= 0);
assert(legacy_args->fill_wave);
assert(legacy_args->fill_wave || legacy_args->fill_wave_ext);
const uint64_t size = image_size();
@ -859,22 +859,16 @@ cassette_image::error cassette_image::legacy_construct(const LegacyWaveFiller *l
/* convert the file data to samples */
while ((pos < sample_count) && (offset < size))
{
/* allocate a buffer for the binary data */
std::vector<uint8_t> chunk(args.chunk_size);
image_read(&chunk[0], offset, args.chunk_size);
offset += args.chunk_size;
const int slice = std::min<int>(args.chunk_size, size - offset);
/*
This approach is problematic because we don't have control on incomming image size when processing the data
(at least in tap implementation).
The method sending the size of output (calculated in 'chunk_sample_calc' above) which uses same data as a input but
without knowing how much data available in the image. Having wrong header with size bigger than image couses illegal
access beyond image data.
Desired state is:
length = args.fill_wave(&samples[pos], args.chunk_size, &chunk[0]);
aslo the fix for tap is commented out in 'tap_cas_fill_wave'
*/
length = args.fill_wave(&samples[pos], sample_count - pos, &chunk[0]);
/* allocate a buffer for the binary data */
std::vector<uint8_t> chunk(slice);
image_read(&chunk[0], offset, slice);
offset += slice;
length = (args.fill_wave_ext != nullptr)
? args.fill_wave_ext(&samples[pos], sample_count - pos, &chunk[0], slice)
: args.fill_wave(&samples[pos], sample_count - pos, &chunk[0]);
if (length < 0)
{
err = error::INVALID_IMAGE;

View File

@ -127,6 +127,7 @@ public:
uint32_t sample_frequency = 0;
int header_samples = 0;
int trailer_samples = 0;
int (*fill_wave_ext)(int16_t *, int, const uint8_t *, int) = nullptr;
};
~cassette_image();

View File

@ -809,16 +809,17 @@ static int tap_cas_to_wav_size( const uint8_t *casdata, int caslen )
int size = 0;
const uint8_t *p = casdata;
while (caslen > 0)
while (caslen > 2)
{
int data_size = get_u16le(&p[0]);
int pilot_length = (p[2] == 0x00) ? 8063 : 3223;
caslen -= data_size;
if (caslen < 0)
caslen -= 2;
if (caslen < data_size)
{
LOG_FORMATS("tap_cas_to_wav_size: Requested 0x%X byte but only 0x%X available.\n", data_size, data_size + caslen);
data_size += caslen;
LOG_FORMATS("tap_cas_to_wav_size: Requested 0x%X byte but only 0x%X available.\n", data_size, caslen);
data_size = caslen;
}
caslen -= data_size;
LOG_FORMATS("tap_cas_to_wav_size: Handling TAP block containing 0x%X bytes", data_size);
p += 2;
size += tzx_cas_handle_block(nullptr, p, 1000, data_size, 2168, pilot_length, 667, 735, 855, 1710, 8);
@ -828,24 +829,22 @@ static int tap_cas_to_wav_size( const uint8_t *casdata, int caslen )
return size;
}
static int tap_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes )
static int tap_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes, int bytes_length )
{
int16_t *p = buffer;
int size = 0;
//while (length > 0)
while (size < length)
while (bytes_length > 2)
{
int data_size = get_u16le(&bytes[0]);
int pilot_length = (bytes[2] == 0x00) ? 8063 : 3223;
LOG_FORMATS("tap_cas_fill_wave: Handling TAP block containing 0x%X bytes\n", data_size);
/*
length -= data_size;
if (length < 0)
bytes_length -= 2;
if (bytes_length < data_size)
{
data_size += length; // Take as much as we can.
data_size = bytes_length; // Take as much as we can.
}
*/
bytes_length -= data_size;
bytes += 2;
size += tzx_cas_handle_block(&p, bytes, 1000, data_size, 2168, pilot_length, 667, 735, 855, 1710, 8);
bytes += data_size;
@ -855,35 +854,36 @@ static int tap_cas_fill_wave( int16_t *buffer, int length, const uint8_t *bytes
static const cassette_image::LegacyWaveFiller tzx_legacy_fill_wave =
{
tzx_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
tzx_cas_to_wav_size, /* chunk_sample_calc */
TZX_WAV_FREQUENCY, /* sample_frequency */
0, /* header_samples */
0 /* trailer_samples */
tzx_cas_fill_wave, // fill_wave
-1, // chunk_size
0, // chunk_samples
tzx_cas_to_wav_size, // chunk_sample_calc
TZX_WAV_FREQUENCY, // sample_frequency
0, // header_samples
0, // trailer_samples
};
static const cassette_image::LegacyWaveFiller tap_legacy_fill_wave =
{
tap_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
tap_cas_to_wav_size, /* chunk_sample_calc */
TZX_WAV_FREQUENCY, /* sample_frequency */
0, /* header_samples */
0 /* trailer_samples */
nullptr, // fill_wave
-1, // chunk_size
0, // chunk_samples
tap_cas_to_wav_size, // chunk_sample_calc
TZX_WAV_FREQUENCY, // sample_frequency
0, // header_samples
0, // trailer_samples
tap_cas_fill_wave // fill_wave_ext
};
static const cassette_image::LegacyWaveFiller cdt_legacy_fill_wave =
{
cdt_cas_fill_wave, /* fill_wave */
-1, /* chunk_size */
0, /* chunk_samples */
tzx_cas_to_wav_size, /* chunk_sample_calc */
TZX_WAV_FREQUENCY, /* sample_frequency */
0, /* header_samples */
0 /* trailer_samples */
cdt_cas_fill_wave, // fill_wave
-1, // chunk_size
0, // chunk_samples
tzx_cas_to_wav_size, // chunk_sample_calc
TZX_WAV_FREQUENCY, // sample_frequency
0, // header_samples
0 // trailer_samples
};
static cassette_image::error tzx_cassette_identify( cassette_image *cassette, cassette_image::Options *opts )