WebP Decoding error handling:

- Don't allow any extended chunks (except ALPH) without RIFF & VP8X
chunks.
- Also, don't allow VP8X without RIFF.

Change-Id: I1beba43e617ec637901aeeb93f2f484ec086a75d
This commit is contained in:
Urvang Joshi 2012-06-29 14:31:32 +05:30
parent fcc69923b9
commit 3ba81bbe8b

View File

@ -245,26 +245,22 @@ static VP8StatusCode ParseVP8Header(const uint8_t** data_ptr, size_t* data_size,
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Returns true if 'fourcc' matches a chunk that can appear in a 'VP8X' file.
// Image chunks are dealt with separately so are not included here.
static int IsExtendedFormatChunk(const uint8_t fourcc[4]) {
return (!memcmp(fourcc, "ALPH", TAG_SIZE) ||
!memcmp(fourcc, "FRM ", TAG_SIZE) ||
!memcmp(fourcc, "ICCP", TAG_SIZE) ||
!memcmp(fourcc, "LOOP", TAG_SIZE) ||
!memcmp(fourcc, "META", TAG_SIZE) ||
!memcmp(fourcc, "TILE", TAG_SIZE));
}
// Fetch 'width', 'height', 'has_alpha' and fill out 'headers' based on 'data'. // Fetch 'width', 'height', 'has_alpha' and fill out 'headers' based on 'data'.
// All the output parameters may be NULL. If 'headers' is NULL only the minimal // All the output parameters may be NULL. If 'headers' is NULL only the minimal
// amount will be read to fetch the remaining parameters. // amount will be read to fetch the remaining parameters.
// If 'headers' is non-NULL this function will attempt to locate both alpha // If 'headers' is non-NULL this function will attempt to locate both alpha
// data (with or without a VP8X chunk) and the bitstream chunk (VP8/VP8L). // data (with or without a VP8X chunk) and the bitstream chunk (VP8/VP8L).
// Note: The following chunk sequences (before the raw VP8/VP8L data) are
// considered valid by this function:
// RIFF + VP8(L)
// RIFF + VP8X + (optional chunks) + VP8(L)
// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
static VP8StatusCode ParseHeadersInternal( static VP8StatusCode ParseHeadersInternal(
const uint8_t* data, size_t data_size, const uint8_t* data, size_t data_size,
int* const width, int* const height, int* const has_alpha, int* const width, int* const height, int* const has_alpha,
WebPHeaderStructure* const headers) { WebPHeaderStructure* const headers) {
int found_riff = 0;
int found_vp8x = 0; int found_vp8x = 0;
VP8StatusCode status; VP8StatusCode status;
WebPHeaderStructure hdrs; WebPHeaderStructure hdrs;
@ -281,6 +277,7 @@ static VP8StatusCode ParseHeadersInternal(
if (status != VP8_STATUS_OK) { if (status != VP8_STATUS_OK) {
return status; // Wrong RIFF header / insufficient data. return status; // Wrong RIFF header / insufficient data.
} }
found_riff = (hdrs.riff_size > 0);
// Skip over VP8X. // Skip over VP8X.
{ {
@ -289,6 +286,11 @@ static VP8StatusCode ParseHeadersInternal(
if (status != VP8_STATUS_OK) { if (status != VP8_STATUS_OK) {
return status; // Wrong VP8X / insufficient data. return status; // Wrong VP8X / insufficient data.
} }
if (!found_riff && found_vp8x) {
// Note: This restriction may be removed in the future, if it becomes
// necessary to send VP8X chunk to the decoder.
return VP8_STATUS_BITSTREAM_ERROR;
}
if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG_BIT); if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG_BIT);
if (found_vp8x && headers == NULL) { if (found_vp8x && headers == NULL) {
return VP8_STATUS_OK; // Return features from VP8X header. return VP8_STATUS_OK; // Return features from VP8X header.
@ -297,10 +299,9 @@ static VP8StatusCode ParseHeadersInternal(
if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA; if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA;
// Skip over optional chunks. // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
// If a VP8X chunk was not found look for chunks that may be contained within if ((found_riff && found_vp8x) ||
// one to initiate the parse. (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) {
if (found_vp8x || IsExtendedFormatChunk(data)) {
status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size, status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
&hdrs.alpha_data, &hdrs.alpha_data_size); &hdrs.alpha_data, &hdrs.alpha_data_size);
if (status != VP8_STATUS_OK) { if (status != VP8_STATUS_OK) {