ref: b485a96254c0690aa8487608f9e62d30e9e4b8d4
parent: 07f324fd0ded2e82b83392894c02560f2c66f641
author: Mark Harris <mark.hsj@gmail.com>
date: Wed Sep 30 21:29:03 EDT 2015
opusenc: Handle arbitrary AIFF/WAV chunk sizes Properly handle chunks of any size from AIFF/WAV input files, including padding them to an even size as required. Also ensure that a relevant message is displayed on any AIFF/WAV open failure. See oggenc https://trac.xiph.org/ticket/1817, https://trac.xiph.org/ticket/1912, https://trac.xiph.org/ticket/2212 (CVE-2015-6749).
--- a/src/audio-in.c
+++ b/src/audio-in.c
@@ -191,27 +191,27 @@
static int find_wav_chunk(FILE *in, char *type, unsigned int *len)
{
unsigned char buf[8];
+ unsigned int chunklen;
while(1)
{
if(fread(buf,1,8,in) < 8) /* Suck down a chunk specifier */
- {
- fprintf(stderr, _("Warning: Unexpected EOF reading WAV header\n"));
return 0; /* EOF before reaching the appropriate chunk */
- }
+ chunklen = READ_U32_LE(buf+4);
+
if(memcmp(buf, type, 4))
{
- *len = READ_U32_LE(buf+4);
- if(!seek_forward(in, *len))
- return 0;
-
buf[4] = 0;
- fprintf(stderr, _("Skipping chunk of type \"%s\", length %d\n"), buf, *len);
+ fprintf(stderr, _("Skipping chunk of type \"%s\", length %u\n"),
+ buf, chunklen);
+
+ if(!seek_forward(in, (ogg_int64_t)chunklen + (chunklen & 1)))
+ return 0;
}
else
{
- *len = READ_U32_LE(buf+4);
+ *len = chunklen;
return 1;
}
}
@@ -220,11 +220,12 @@
static int find_aiff_chunk(FILE *in, char *type, unsigned int *len)
{
unsigned char buf[8];
+ unsigned int chunklen;
int restarted = 0;
while(1)
{
- if(fread(buf,1,8,in) <8)
+ if(fread(buf,1,8,in) < 8)
{
if(!restarted) {
/* Handle out of order chunks by seeking back to the start
@@ -233,25 +234,45 @@
if(!FSEEK(in, 12, SEEK_SET))
continue;
}
- fprintf(stderr, _("Warning: Unexpected EOF in AIFF chunk\n"));
return 0;
}
- *len = READ_U32_BE(buf+4);
+ chunklen = READ_U32_BE(buf+4);
if(memcmp(buf,type,4))
{
- if((*len) & 0x1)
- (*len)++;
-
- if(!seek_forward(in, *len))
+ if(!seek_forward(in, (ogg_int64_t)chunklen + (chunklen & 1)))
return 0;
}
else
+ {
+ *len = chunklen;
return 1;
+ }
}
}
+/* Read chunk of size *len and advance the file position to the next chunk.
+ * Returns 0 on EOF or read error. Otherwise *len is updated with the number
+ * of bytes placed in the buffer (the lesser of the chunk size and buffer
+ * size) and 1 is returned.
+ */
+static int read_chunk(FILE *in, unsigned char *buf, unsigned int bufsize,
+ unsigned int *len)
+{
+ unsigned int chunklen = *len;
+ unsigned int readlen = chunklen > bufsize ? bufsize : chunklen;
+
+ if(fread(buf, 1, readlen, in) != readlen)
+ return 0;
+
+ if(!seek_forward(in, (ogg_int64_t)(chunklen - readlen) + (chunklen & 1)))
+ return 0;
+
+ *len = readlen;
+ return 1;
+}
+
double read_IEEE80(unsigned char *buf)
{
int s=buf[0]&0xff;
@@ -314,7 +335,7 @@
{
int aifc; /* AIFC or AIFF? */
unsigned int len;
- unsigned char *buffer;
+ unsigned char buffer[22];
unsigned char buf2[8];
int bigendian = 1;
aiff_fmt format;
@@ -333,17 +354,9 @@
return 0; /* EOF before COMM chunk */
}
- if(len < 18)
+ if(len < 18 || !read_chunk(in, buffer, sizeof(buffer), &len))
{
- fprintf(stderr, _("Warning: Truncated common chunk in AIFF header\n"));
- return 0; /* Weird common chunk */
- }
-
- buffer = alloca(len);
-
- if(fread(buffer,1,len,in) < len)
- {
- fprintf(stderr, _("Warning: Unexpected EOF reading AIFF header\n"));
+ fprintf(stderr, _("ERROR: Incomplete common chunk in AIFF header\n"));
return 0;
}
@@ -484,7 +497,10 @@
*/
if(!find_wav_chunk(in, "fmt ", &len))
- return 0; /* EOF */
+ {
+ fprintf(stderr, _("ERROR: No format chunk found in WAV file\n"));
+ return 0;
+ }
if(len < 16)
{
@@ -504,11 +520,9 @@
_("Warning: INVALID format chunk in wav header.\n"
" Trying to read anyway (may not work)...\n"));
- if(len>40)len=40;
-
- if(fread(buf,1,len,in) < len)
+ if(!read_chunk(in, buf, sizeof(buf), &len))
{
- fprintf(stderr, _("Warning: Unexpected EOF reading WAV header\n"));
+ fprintf(stderr, _("ERROR: Incomplete format chunk in WAV header\n"));
return 0;
}
@@ -578,9 +592,6 @@
validbits = format.samplesize;
}
- if(!find_wav_chunk(in, "data", &len))
- return 0; /* EOF */
-
if(format.format == 1)
{
samplesize = format.samplesize/8;
@@ -596,6 +607,12 @@
{
fprintf(stderr, _("ERROR: Unsupported WAV file type.\n"
"Must be standard PCM or type 3 floating point PCM.\n"));
+ return 0;
+ }
+
+ if(!find_wav_chunk(in, "data", &len))
+ {
+ fprintf(stderr, _("ERROR: No data chunk found in WAV file\n"));
return 0;
}
--- a/src/opusenc.h
+++ b/src/opusenc.h
@@ -85,7 +85,7 @@
opus_int64 totalframes;
short samplesize;
int rate;
- int offset;
+ unsigned int offset;
int blocksize;
} aiff_fmt;