mirror of
https://github.com/1dot13/source.git
synced 2026-08-05 14:00:23 +02:00
grow libsmacker audio buffer when a frame exceeds the header max_buffer
The Smacker header declares a max audio chunk size, and libsmacker sized its output buffer from it — then wrote each frame's audio trusting the frame's own unpacked size, unchecked. The fan-localized intro videos (Chinese among others) declare max_buffer=2304 but carry ~97KB audio frames: every decode was a heap overflow, crashing the intro. The original SMACKW32.DLL played these files, so treat the per-frame size as truth and grow the buffer, bounded by a 16MB sanity cap; a chunk beyond that fails the frame as corrupt. Covers both the raw-PCM and DPCM paths. Verified with an ASan/UBSan harness over all 19 vanilla and Chinese intro SMKs: previously all 8 Chinese files faulted, now all decode both passes clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
committed by
majcosta
co-authored by
Claude Fable 5
parent
858c149584
commit
95cf0621a0
@@ -1467,6 +1467,33 @@ static char smk_render_video(struct smk_video_t * s, unsigned char * p, unsigned
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ensure the audio output buffer holds buffer_size bytes. The buffer is
|
||||
allocated from the header's max_buffer, but some encoders understate it
|
||||
(fan-localized JA2 intro SMKs declare 2304 and deliver ~97KB frames);
|
||||
the original SMACKW32.DLL played those fine, so trust the per-frame
|
||||
size and grow, within a sanity cap against corrupt files. */
|
||||
static char smk_audio_fit_buffer(struct smk_audio_t * s)
|
||||
{
|
||||
void * grown;
|
||||
|
||||
if (s->buffer_size <= (unsigned long)s->max_buffer)
|
||||
return 0;
|
||||
|
||||
if (s->buffer_size > 0x1000000) {
|
||||
fputs("libsmacker::smk_audio_fit_buffer() - ERROR: implausibly large audio chunk.\n", stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((grown = realloc(s->buffer, s->buffer_size)) == NULL) {
|
||||
perror("libsmacker::smk_audio_fit_buffer() - ERROR: failed to grow audio buffer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->buffer = grown;
|
||||
s->max_buffer = s->buffer_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decompress audio track i. */
|
||||
static char smk_render_audio(struct smk_audio_t * s, unsigned char * p, unsigned long size)
|
||||
{
|
||||
@@ -1484,6 +1511,11 @@ static char smk_render_audio(struct smk_audio_t * s, unsigned char * p, unsigned
|
||||
if (!s->compress) {
|
||||
/* Raw PCM data, update buffer size and perform copy */
|
||||
s->buffer_size = size;
|
||||
|
||||
if (smk_audio_fit_buffer(s) < 0)
|
||||
goto error;
|
||||
|
||||
t = s->buffer;
|
||||
memcpy(t, p, size);
|
||||
} else if (s->compress == 1) {
|
||||
/* SMACKER DPCM compression */
|
||||
@@ -1498,6 +1530,11 @@ static char smk_render_audio(struct smk_audio_t * s, unsigned char * p, unsigned
|
||||
((unsigned int) p[2] << 16) |
|
||||
((unsigned int) p[1] << 8) |
|
||||
((unsigned int) p[0]);
|
||||
|
||||
if (smk_audio_fit_buffer(s) < 0)
|
||||
goto error;
|
||||
|
||||
t = s->buffer;
|
||||
p += 4;
|
||||
size -= 4;
|
||||
/* Compressed audio: must unpack here */
|
||||
|
||||
Reference in New Issue
Block a user