From e2a8ea1f4234c7b6e6f8056578703b8c4c664c09 Mon Sep 17 00:00:00 2001
From: pionere <[EMAIL REDACTED]>
Date: Wed, 15 Dec 2021 10:34:11 +0100
Subject: [PATCH] improve ParseFMT - ensure the structs used in ParseFMT are
packed without padding - use stack to load the format information - ensure
ParseFMT does not read outside of the allocated memory in case of EXT_CODE
---
src/codecs/music_wav.c | 50 +++++++++++++++++++++++-------------------
1 file changed, 27 insertions(+), 23 deletions(-)
diff --git a/src/codecs/music_wav.c b/src/codecs/music_wav.c
index 8150188c..340d8550 100644
--- a/src/codecs/music_wav.c
+++ b/src/codecs/music_wav.c
@@ -79,6 +79,7 @@ typedef struct {
#define WAVE_MONO 1
#define WAVE_STEREO 2
+#pragma pack(push, 1)
typedef struct {
/* Not saved in the chunk we read:
Uint32 chunkID;
@@ -90,7 +91,7 @@ typedef struct {
Uint32 byterate; /* Average bytes per second */
Uint16 blockalign; /* Bytes per sample block */
Uint16 bitspersample; /* One of 8, 12, 16, or 4 for ADPCM */
-} WaveFMT;
+} WaveFMTHeader;
typedef struct {
Uint16 cbSize;
@@ -107,6 +108,11 @@ typedef struct {
Uint8 sub_data[8];
} WaveFMTex;
+typedef struct {
+ WaveFMTHeader format;
+ WaveFMTex formatEx;
+} _WaveFMT;
+
typedef struct {
Uint32 identifier;
Uint32 type;
@@ -132,6 +138,7 @@ typedef struct {
Uint32 sampler_data;
SampleLoop loops[1];
} SamplerChunk;
+#pragma pack(pop)
/*********************************************/
/* Define values for AIFF (IFF audio) format */
@@ -632,33 +639,34 @@ static void WAV_Delete(void *context)
static SDL_bool ParseFMT(WAV_Music *wave, Uint32 chunk_length)
{
SDL_AudioSpec *spec = &wave->spec;
- WaveFMT *format;
- WaveFMTex *formatEx = NULL;
+ _WaveFMT fmt;
Uint8 *data;
int bits;
- SDL_bool loaded = SDL_FALSE;
- if (chunk_length < sizeof(*format)) {
+ if (chunk_length < sizeof(fmt.format)) {
Mix_SetError("Wave format chunk too small");
return SDL_FALSE;
}
- data = (Uint8 *)SDL_malloc(chunk_length);
- if (!data) {
- Mix_SetError("Out of memory");
+ bits = chunk_length >= sizeof(fmt) ? sizeof(fmt) : sizeof(fmt.format);
+ if (!SDL_RWread(wave->src, &fmt, bits, 1)) {
+ Mix_SetError("Couldn't read %d bytes from WAV file", chunk_length);
return SDL_FALSE;
}
- if (!SDL_RWread(wave->src, data, chunk_length, 1)) {
+ chunk_length -= bits;
+ if (chunk_length != 0 && !SDL_RWseek(wave->src, chunk_length, RW_SEEK_CUR)) {
Mix_SetError("Couldn't read %d bytes from WAV file", chunk_length);
- goto done;
+ return SDL_FALSE;
}
- format = (WaveFMT *)data;
- wave->encoding = SDL_SwapLE16(format->encoding);
+ wave->encoding = SDL_SwapLE16(fmt.format.encoding);
if (wave->encoding == EXT_CODE) {
- formatEx = (WaveFMTex*)(data + sizeof(WaveFMT));
- wave->encoding = (Uint16)SDL_SwapLE32(formatEx->subencoding);
+ if (bits < sizeof(fmt)) {
+ Mix_SetError("Wave format chunk too small");
+ return SDL_FALSE;
+ }
+ wave->encoding = (Uint16)SDL_SwapLE32(fmt.formatEx.subencoding);
}
/* Decode the audio data format */
@@ -681,8 +689,8 @@ static SDL_bool ParseFMT(WAV_Music *wave, Uint32 chunk_length)
Mix_SetError("Unknown WAVE data format");
goto done;
}
- spec->freq = (int)SDL_SwapLE32(format->frequency);
- bits = (int) SDL_SwapLE16(format->bitspersample);
+ spec->freq = (int)SDL_SwapLE32(fmt.format.frequency);
+ bits = (int) SDL_SwapLE16(fmt.format.bitspersample);
switch (bits) {
case 8:
switch(wave->encoding) {
@@ -726,9 +734,9 @@ static SDL_bool ParseFMT(WAV_Music *wave, Uint32 chunk_length)
default:
unknown_bits:
Mix_SetError("Unknown PCM format with %d bits", bits);
- goto done;
+ return SDL_FALSE;
}
- spec->channels = (Uint8) SDL_SwapLE16(format->channels);
+ spec->channels = (Uint8) SDL_SwapLE16(fmt.format.channels);
spec->samples = 4096; /* Good default buffer size */
wave->samplesize = spec->channels * (bits / 8);
/* SDL_CalculateAudioSpec */
@@ -736,11 +744,7 @@ static SDL_bool ParseFMT(WAV_Music *wave, Uint32 chunk_length)
spec->size *= spec->channels;
spec->size *= spec->samples;
- loaded = SDL_TRUE;
-
-done:
- SDL_free(data);
- return loaded;
+ return SDL_TRUE;
}
static SDL_bool ParseDATA(WAV_Music *wave, Uint32 chunk_length)