Permalink
Browse files

Use bounds-checked bytestream readers

This should fix many possible crashes with corrupted extradata.

Along the way passed errors back from parse_extra_data, and deleted
frma and terminator atom writing from ff_private.

This might have broken something.

git-svn-id: https://svn.perian.org/trunk@1526 621663c8-3916-0410-8f58-edc14a8543d5
  • Loading branch information...
astrange
astrange committed Nov 13, 2012
1 parent c178e33 commit 9e561c3251e033d6bd052eb2e21f82181fe6b13d
Showing with 256 additions and 247 deletions.
  1. +46 −54 CommonUtils.c
  2. +1 −10 CommonUtils.h
  3. +46 −39 FFissionCodec/FFissionDecoder.cpp
  4. +4 −2 FFusionCodec.c
  5. +77 −51 MatroskaCodecIDs.cpp
  6. +29 −15 bitstream_info.c
  7. +53 −76 ff_private.c
View
@@ -26,9 +26,9 @@
#include <fnmatch.h>
#include <libavcodec/avcodec.h>
#include <libavcodec/bytestream.h>
#include "CommonUtils.h"
typedef struct LanguageTriplet {
char twoChar[3];
char threeChar[4]; // (ISO 639-2 3 char code)
@@ -204,39 +204,18 @@ short ISO639_2ToQTLangCode(const char *lang)
return langUnspecified;
}
/* write the int32_t data to target & then return a pointer which points after that data */
uint8_t *write_int32(uint8_t *target, int32_t data)
{
return write_data(target, (uint8_t*)&data, sizeof(data));
} /* write_int32() */
/* write the int16_t data to target & then return a pointer which points after that data */
uint8_t *write_int16(uint8_t *target, int16_t data)
{
return write_data(target, (uint8_t*)&data, sizeof(data));
} /* write_int16() */
/* write the data to the target adress & then return a pointer which points after the written data */
uint8_t *write_data(uint8_t *target, uint8_t* data, int32_t data_size)
{
if(data_size > 0)
memcpy(target, data, data_size);
return (target + data_size);
} /* write_data() */
#define MP4ESDescrTag 0x03
#define MP4DecConfigDescrTag 0x04
#define MP4DecSpecificDescrTag 0x05
// based off of mov_mp4_read_descr_len from mov.c in ffmpeg's libavformat
static int readDescrLen(UInt8 **buffer)
static unsigned readDescrLen(GetByteContext *g)
{
int len = 0;
unsigned len = 0;
int count = 4;
while (count--) {
int c = *(*buffer)++;
uint8_t c = bytestream2_get_byte(g);
len = (len << 7) | (c & 0x7f);
if (!(c & 0x80))
break;
@@ -245,41 +224,46 @@ static int readDescrLen(UInt8 **buffer)
}
// based off of mov_mp4_read_descr from mov.c in ffmpeg's libavformat
static int readDescr(UInt8 **buffer, int *tag)
static unsigned readDescr(GetByteContext *g, int *tag)
{
*tag = *(*buffer)++;
return readDescrLen(buffer);
*tag = bytestream2_get_byte(g);
return readDescrLen(g);
}
// based off of mov_read_esds from mov.c in ffmpeg's libavformat
ComponentResult ReadESDSDescExt(Handle descExt, UInt8 **buffer, int *size)
{
UInt8 *esds = (UInt8 *) *descExt;
UInt8 *esds = (UInt8 *)*descExt;
UInt8 *extradata;
int tag, len;
GetByteContext g;
bytestream2_init(&g, esds, GetHandleSize(descExt));
// FIXME use safe bytestream reading here
*size = 0;
esds += 4; // version + flags
len = readDescr(&esds, &tag);
esds += 2; // ID
bytestream2_skip(&g, 4); // version + flags
readDescr(&g, &tag);
bytestream2_skip(&g, 2); // ID
if (tag == MP4ESDescrTag)
esds++; // priority
bytestream2_skip(&g, 1); // priority
len = readDescr(&esds, &tag);
readDescr(&g, &tag);
if (tag == MP4DecConfigDescrTag) {
esds++; // object type id
esds++; // stream type
esds += 3; // buffer size db
esds += 4; // max bitrate
esds += 4; // average bitrate
bytestream2_skip(&g, 1); // object type id
bytestream2_skip(&g, 1); // stream type
bytestream2_skip(&g, 3); // buffer size db
bytestream2_skip(&g, 4); // max bitrate
bytestream2_skip(&g, 4); // average bitrate
len = readDescr(&esds, &tag);
len = readDescr(&g, &tag);
if (tag == MP4DecSpecificDescrTag) {
*buffer = calloc(1, len + FF_INPUT_BUFFER_PADDING_SIZE);
if (*buffer) {
memcpy(*buffer, esds, len);
extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
if (extradata) {
if (bytestream2_get_buffer(&g, extradata, len) != len) {
av_free(extradata);
return paramErr;
}
*buffer = extradata;
*size = len;
}
}
@@ -288,20 +272,28 @@ ComponentResult ReadESDSDescExt(Handle descExt, UInt8 **buffer, int *size)
return noErr;
}
int isImageDescriptionExtensionPresent(ImageDescriptionHandle desc, long type)
int isImageDescriptionExtensionPresent(ImageDescriptionHandle desc, FourCharCode type)
{
ImageDescriptionPtr d = *desc;
int offset = sizeof(ImageDescription);
uint8_t *p = (uint8_t *)d;
GetByteContext g;
bytestream2_init(&g, p, GetHandleSize((Handle)desc));
bytestream2_skip(&g, sizeof(ImageDescription));
//read next description, need 8 bytes for size and type
while(offset < d->idSize - 8)
while(bytestream2_get_bytes_left(&g))
{
long len = *(p+offset) << 24 | *(p+offset+1) << 16 | *(p+offset+2) << 8 | *(p+offset+3);
long rtype = *(p+offset + 4) << 24 | *(p+offset+5) << 16 | *(p+offset+6) << 8 | *(p+offset+7);
if(rtype == type && offset + len <= d->idSize)
unsigned len;
FourCharCode rtype;
len = bytestream2_get_be32(&g);
rtype = bytestream2_get_be32(&g);
if(rtype == type && (len - 8) <= bytestream2_get_bytes_left(&g))
return 1;
offset += len;
bytestream2_skip(&g, len - 8);
}
return 0;
}
View
@@ -35,20 +35,11 @@ short ISO639_1ToQTLangCode(const char *lang);
// ISO 639-2 to language ID expected by SetMediaLanguage
short ISO639_2ToQTLangCode(const char *lang);
/* write the int32_t data to target & then return a pointer which points after that data */
uint8_t *write_int32(uint8_t *target, int32_t data);
/* write the int16_t data to target & then return a pointer which points after that data */
uint8_t *write_int16(uint8_t *target, int16_t data);
/* write the data to the target adress & then return a pointer which points after the written data */
uint8_t *write_data(uint8_t *target, uint8_t* data, int32_t data_size);
// mallocs the buffer and copies the codec-specific description to it, in the same format
// as is specified in Matroska and is used in libavcodec
ComponentResult ReadESDSDescExt(Handle descExt, UInt8 **buffer, int *size);
int isImageDescriptionExtensionPresent(ImageDescriptionHandle desc, long type);
int isImageDescriptionExtensionPresent(ImageDescriptionHandle desc, FourCharCode type);
// does the current process break if we signal droppable frames?
int IsFrameDroppingEnabled();
@@ -21,6 +21,7 @@
#include <AudioToolbox/AudioToolbox.h>
#include <libavcodec/dca.h>
#include <libavcodec/bytestream.h>
#include "ComponentBase.h"
#include "FFissionDecoder.h"
@@ -32,12 +33,6 @@
#define MY_APP_DOMAIN CFSTR("org.perian.Perian")
#define PASSTHROUGH_KEY CFSTR("attemptDTSPassthrough")
typedef struct CookieAtomHeader {
long size;
long type;
unsigned char data[1];
} CookieAtomHeader;
struct WaveFormatEx {
uint16_t wFormatTag;
uint16_t nChannels;
@@ -220,52 +215,57 @@ void FFissionDecoder::SetupExtradata()
int FFissionDecoder::ConvertXiphVorbisCookie()
{
Byte *ptr = magicCookie;
Byte *cend = magicCookie + magicCookieSize;
Byte *headerData[3] = {NULL};
int headerSize[3] = {0};
while (ptr < cend) {
CookieAtomHeader *aheader = reinterpret_cast<CookieAtomHeader *>(ptr);
int size = EndianU32_BtoN(aheader->size);
ptr += size;
if (ptr > cend || size <= 0)
break;
GetByteContext g;
bytestream2_init(&g, magicCookie, magicCookieSize);
int headerOffset[3] = {};
int headerSize[3] = {};
while (bytestream2_get_bytes_left(&g)) {
unsigned size, type;
size = bytestream2_get_be32(&g);
type = bytestream2_get_be32(&g);
unsigned dataSize = size - 8;
switch(EndianS32_BtoN(aheader->type)) {
switch(type) {
case kCookieTypeVorbisHeader:
headerData[0] = aheader->data;
headerSize[0] = size - 8;
headerOffset[0] = bytestream2_tell(&g);
headerSize[0] = dataSize;
break;
case kCookieTypeVorbisComments:
headerData[1] = aheader->data;
headerSize[1] = size - 8;
headerOffset[1] = bytestream2_tell(&g);
headerSize[1] = dataSize;
break;
case kCookieTypeVorbisCodebooks:
headerData[2] = aheader->data;
headerSize[2] = size - 8;
headerOffset[2] = bytestream2_tell(&g);
headerSize[2] = dataSize;
break;
}
bytestream2_skip(&g, dataSize);
}
if (headerSize[0] <= 0 || headerSize[1] <= 0 || headerSize[2] <= 0) {
int len = headerSize[0] + headerSize[1] + headerSize[2];
if (headerSize[0] <= 0 || headerSize[1] <= 0 || headerSize[2] <= 0 || len >= magicCookieSize) {
Codecprintf(NULL, "Invalid Vorbis extradata\n");
return 0;
}
int len = headerSize[0] + headerSize[1] + headerSize[2];
Byte *newCookie = new Byte[len + len/255 + 64 + FF_INPUT_BUFFER_PADDING_SIZE];
ptr = newCookie;
Size newCookieSize = len + len/255 + 64 + FF_INPUT_BUFFER_PADDING_SIZE;
Byte *newCookie = new Byte[newCookieSize];
Byte *ptr = newCookie;
ptr[0] = 2; // number of packets minus 1
ptr[0] = 2; // number of packets minus 1
int offset = 1;
offset += av_xiphlacing(&ptr[offset], headerSize[0]);
offset += av_xiphlacing(&ptr[offset], headerSize[1]);
for (int i = 0; i < 3; i++) {
memcpy(&ptr[offset], headerData[i], headerSize[i]);
offset += headerSize[i];
bytestream2_seek(&g, headerOffset[i], SEEK_SET);
offset += bytestream2_get_buffer(&g, &ptr[offset], headerSize[i]);
}
delete[] magicCookie;
@@ -484,29 +484,36 @@ void FFissionDecoder::AppendInputData(const void* inInputData, UInt32& ioInputDa
}
}
#define AV_RL16(x) EndianU16_LtoN(*(uint16_t *)(x))
#define AV_RB16(x) EndianU16_BtoN(*(uint16_t *)(x))
int produceDTSPassthroughPackets(Byte *outputBuffer, int *outBufUsed, uint8_t *packet, int packetSize, int channelCount, int bigEndian)
{
if(packetSize < 96)
return 0;
static const uint8_t p_sync_le[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x00, 0x00 };
static const uint8_t p_sync_be[6] = { 0xF8, 0x72, 0x4E, 0x1F, 0x00, 0x00 };
GetByteContext g;
uint32_t mrk = AV_RB16(packet) << 16 | AV_RB16(packet + 2);
bytestream2_init(&g, packet, packetSize);
uint32_t mrk;
unsigned int frameSize = 0;
unsigned int blockCount = 0;
uint16_t s1, s2;
mrk = bytestream2_get_be16(&g) << 16;
mrk |= bytestream2_get_be16(&g);
switch (mrk) {
case DCA_MARKER_RAW_BE:
blockCount = (AV_RB16(packet + 4) >> 2) & 0x7f;
frameSize = (AV_RB16(packet + 4) & 0x3) << 12 | ((AV_RB16(packet + 6) >> 4) & 0xfff);
s1 = bytestream2_get_be16(&g);
s2 = bytestream2_get_be16(&g);
blockCount = (s1 >> 2) & 0x7f;
frameSize = (s1 & 0x3) << 12 | ((s2 >> 4) & 0xfff);
break;
case DCA_MARKER_RAW_LE:
blockCount = (AV_RL16(packet + 4) >> 2) & 0x7f;
frameSize = (AV_RL16(packet + 4) & 0x3) << 12 | ((AV_RL16(packet + 6) >> 4) & 0xfff);
s1 = bytestream2_get_le16(&g);
s2 = bytestream2_get_le16(&g);
blockCount = (s1 >> 2) & 0x7f;
frameSize = (s1 & 0x3) << 12 | ((s2 >> 4) & 0xfff);
break;
case DCA_MARKER_14B_BE:
case DCA_MARKER_14B_LE:
View
@@ -728,8 +728,10 @@ pascal ComponentResult FFusionCodecPreflight(FFusionGlobals glob, CodecDecompres
FFusionDebugPrint("%p preflighted for %dx%d '%s'. (%d bytes of extradata)\n", glob, (**p->imageDescription).width, (**p->imageDescription).height, FourCCString(glob->componentType), glob->avContext->extradata_size);
if(glob->avContext->extradata_size != 0 && glob->begin.parser != NULL)
ffusionParseExtraData(glob->begin.parser, glob->avContext->extradata, glob->avContext->extradata_size);
if(glob->avContext->extradata_size != 0 && glob->begin.parser != NULL) {
if (!ffusionParseExtraData(glob->begin.parser, glob->avContext->extradata, glob->avContext->extradata_size))
err = featureUnsupported;
}
if (glob->fileLog)
ffusionLogDebugInfo(glob->begin.parser, glob->fileLog);
Oops, something went wrong.

0 comments on commit 9e561c3

Please sign in to comment.