mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-25 13:18:22 +01:00
check limit of width * height is 32 bits
Update the RIFF-specs file too Change-Id: I113a7e25da2f7a19c1344c1dc5d496127cfe2596
This commit is contained in:
parent
16c46e83ac
commit
7f22bd2596
@ -329,9 +329,9 @@ Extended WebP file header:
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| R |L|M|I|A|T| Reserved |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Canvas Width | ...
|
||||
| Canvas Width Minus One | ...
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
... Canvas Height |
|
||||
... Canvas Height Minus One |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Tiling (T): 1 bit
|
||||
@ -387,15 +387,17 @@ Reserved: 24 bits
|
||||
|
||||
: SHOULD be `0`.
|
||||
|
||||
Canvas Width: 24 bits
|
||||
Canvas Width Minus One: 24 bits
|
||||
|
||||
: _1-based_ width of the canvas in pixels.
|
||||
The actual canvas width is '1 + Canvas Width Minus One'
|
||||
|
||||
Canvas Height: 24 bits
|
||||
Canvas Height Minus One: 24 bits
|
||||
|
||||
: _1-based_ height of the canvas in pixels.
|
||||
The actual canvas height is '1 + Canvas Height Minus One'
|
||||
|
||||
The product of _Canvas Width_ and _Canvas Height_ SHOULD be at most `2^32 - 1`.
|
||||
The product of _Canvas Width_ and _Canvas Height_ MUST be at most `2^32 - 1`.
|
||||
|
||||
Future specifications MAY add more fields.
|
||||
|
||||
@ -433,11 +435,11 @@ Frame chunk:
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Frame X | ...
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
... Frame Y | Frame Width ...
|
||||
... Frame Y | Frame Width Minus One ...
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
... | Frame Height |
|
||||
... | Frame Height Minus One |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Frame Duration |
|
||||
| Frame Duration Minus One |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
Frame X: 24 bits (_uint24_)
|
||||
@ -448,18 +450,20 @@ Frame Y: 24 bits (_uint24_)
|
||||
|
||||
: The Y coordinate of the upper left corner of the frame is `Frame Y * 2`
|
||||
|
||||
Frame Width: 24 bits (_uint24_)
|
||||
Frame Width Minus One: 24 bits (_uint24_)
|
||||
|
||||
: The _1-based_ width of the frame.
|
||||
The Frame Width is '1 + Frame Width Minus One'
|
||||
|
||||
Frame Height: 24 bits (_uint24_)
|
||||
Frame Height Minus One: 24 bits (_uint24_)
|
||||
|
||||
: The _1-based_ height of the frame.
|
||||
The Frame Height is '1 + Frame Height Minus One'
|
||||
|
||||
Frame Duration: 24 bits (_uint24_)
|
||||
Frame Duration Minus One: 24 bits (_uint24_)
|
||||
|
||||
: Time to wait before displaying the next frame, in 1 millisecond units
|
||||
(_1-based_).
|
||||
: _1-based_ time to wait before displaying the next frame, in 1 millisecond
|
||||
units. The actual duration is '1 + Frame Duration Minus One' milliseconds.
|
||||
|
||||
For images that are animations, this chunk contains information about a single
|
||||
frame, and describes the (optional) alpha chunk and the bitstream chunk that
|
||||
|
@ -58,7 +58,7 @@ static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) {
|
||||
// Returns VP8_STATUS_BITSTREAM_ERROR for invalid header, and
|
||||
// VP8_STATUS_OK otherwise.
|
||||
// In case there are not enough bytes (partial RIFF container), return 0 for
|
||||
// riff_size. Else return the riff_size extracted from the header.
|
||||
// *riff_size. Else return the RIFF size extracted from the header.
|
||||
static VP8StatusCode ParseRIFF(const uint8_t** data, size_t* data_size,
|
||||
size_t* riff_size) {
|
||||
assert(data);
|
||||
@ -88,15 +88,18 @@ static VP8StatusCode ParseRIFF(const uint8_t** data, size_t* data_size,
|
||||
// Returns VP8_STATUS_BITSTREAM_ERROR for invalid VP8X header,
|
||||
// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
|
||||
// VP8_STATUS_OK otherwise.
|
||||
// If a VP8X chunk is found, found_vp8x is set to true and *width, *height and
|
||||
// *flags are set to the corresponding values extracted from the VP8X chunk.
|
||||
static VP8StatusCode ParseVP8X(const uint8_t** data, size_t* data_size,
|
||||
int* found_vp8x,
|
||||
int* width, int* height, uint32_t* flags) {
|
||||
// If a VP8X chunk is found, found_vp8x is set to true and *width_ptr,
|
||||
// *height_ptr and *flags_ptr are set to the corresponding values extracted
|
||||
// from the VP8X chunk.
|
||||
static VP8StatusCode ParseVP8X(const uint8_t** const data,
|
||||
size_t* const data_size,
|
||||
int* const found_vp8x,
|
||||
int* const width_ptr, int* const height_ptr,
|
||||
uint32_t* const flags_ptr) {
|
||||
const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
|
||||
assert(data);
|
||||
assert(data_size);
|
||||
assert(found_vp8x);
|
||||
assert(data != NULL);
|
||||
assert(data_size != NULL);
|
||||
assert(found_vp8x != NULL);
|
||||
|
||||
*found_vp8x = 0;
|
||||
|
||||
@ -105,6 +108,8 @@ static VP8StatusCode ParseVP8X(const uint8_t** data, size_t* data_size,
|
||||
}
|
||||
|
||||
if (!memcmp(*data, "VP8X", TAG_SIZE)) {
|
||||
int width, height;
|
||||
uint32_t flags;
|
||||
const uint32_t chunk_size = get_le32(*data + TAG_SIZE);
|
||||
if (chunk_size != VP8X_CHUNK_SIZE) {
|
||||
return VP8_STATUS_BITSTREAM_ERROR; // Wrong chunk size.
|
||||
@ -114,16 +119,16 @@ static VP8StatusCode ParseVP8X(const uint8_t** data, size_t* data_size,
|
||||
if (*data_size < vp8x_size) {
|
||||
return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
|
||||
}
|
||||
flags = get_le32(*data + 8);
|
||||
width = 1 + get_le24(*data + 12);
|
||||
height = 1 + get_le24(*data + 15);
|
||||
if (width * (uint64_t)height >= MAX_IMAGE_AREA) {
|
||||
return VP8_STATUS_BITSTREAM_ERROR; // image is too large
|
||||
}
|
||||
|
||||
if (flags != NULL) {
|
||||
*flags = get_le32(*data + 8);
|
||||
}
|
||||
if (width != NULL) {
|
||||
*width = 1 + get_le24(*data + 12);
|
||||
}
|
||||
if (height != NULL) {
|
||||
*height = 1 + get_le24(*data + 15);
|
||||
}
|
||||
if (flags_ptr != NULL) *flags_ptr = flags;
|
||||
if (width_ptr != NULL) *width_ptr = width;
|
||||
if (height_ptr != NULL) *height_ptr = height;
|
||||
// Skip over VP8X header bytes.
|
||||
*data += vp8x_size;
|
||||
*data_size -= vp8x_size;
|
||||
@ -137,7 +142,8 @@ static VP8StatusCode ParseVP8X(const uint8_t** data, size_t* data_size,
|
||||
// Returns VP8_STATUS_BITSTREAM_ERROR if any invalid chunk size is encountered,
|
||||
// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
|
||||
// VP8_STATUS_OK otherwise.
|
||||
// If an alpha chunk is found, alpha_data and alpha_size are set appropriately.
|
||||
// If an alpha chunk is found, *alpha_data and *alpha_size are set
|
||||
// appropriately.
|
||||
static VP8StatusCode ParseOptionalChunks(const uint8_t** data,
|
||||
size_t* data_size,
|
||||
size_t riff_size,
|
||||
@ -202,9 +208,9 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** data,
|
||||
// riff_size) VP8/VP8L header,
|
||||
// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
|
||||
// VP8_STATUS_OK otherwise.
|
||||
// If a VP8/VP8L chunk is found, chunk_size is set to the total number of bytes
|
||||
// If a VP8/VP8L chunk is found, *chunk_size is set to the total number of bytes
|
||||
// extracted from the VP8/VP8L chunk header.
|
||||
// The flag 'is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data.
|
||||
// The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data.
|
||||
static VP8StatusCode ParseVP8Header(const uint8_t** data_ptr, size_t* data_size,
|
||||
size_t riff_size,
|
||||
size_t* chunk_size, int* is_lossless) {
|
||||
@ -245,9 +251,9 @@ static VP8StatusCode ParseVP8Header(const uint8_t** data_ptr, size_t* data_size,
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// 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
|
||||
// amount will be read to fetch the remaining parameters.
|
||||
// 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 amount will be read to fetch the remaining parameters.
|
||||
// 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).
|
||||
// Note: The following chunk sequences (before the raw VP8/VP8L data) are
|
||||
|
@ -444,6 +444,9 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
|
||||
Skip(mem, 3); // Reserved.
|
||||
dmux->canvas_width_ = 1 + GetLE24s(mem);
|
||||
dmux->canvas_height_ = 1 + GetLE24s(mem);
|
||||
if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) {
|
||||
return PARSE_ERROR; // image final dimension is too large
|
||||
}
|
||||
Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data.
|
||||
dmux->state_ = WEBP_DEMUX_PARSED_HEADER;
|
||||
|
||||
|
@ -218,6 +218,7 @@ static uint8_t* EmitVP8XChunk(uint8_t* const dst, uint32_t width,
|
||||
const size_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
|
||||
assert(width >= 1 && height >= 1);
|
||||
assert(width <= MAX_CANVAS_SIZE && height <= MAX_CANVAS_SIZE);
|
||||
assert(width * (uint64_t)height < MAX_IMAGE_AREA);
|
||||
PutLE32(dst, mktag('V', 'P', '8', 'X'));
|
||||
PutLE32(dst + TAG_SIZE, VP8X_CHUNK_SIZE);
|
||||
PutLE32(dst + CHUNK_HEADER_SIZE, flags);
|
||||
|
@ -74,7 +74,11 @@ typedef enum {
|
||||
#define ALPHA_FLAG_BIT 0x10 // Should be same as the ALPHA_FLAG in mux.h
|
||||
#define ROTATION_FLAG_BITS 0xe0 // all 3 bits for rotation + symmetry
|
||||
|
||||
#define MAX_CANVAS_SIZE (1 << 24) // 24 bit max for VP8X width/height.
|
||||
#define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height.
|
||||
#define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height.
|
||||
#define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count
|
||||
#define MAX_DURATION (1U << 24) // maximum duration
|
||||
#define MAX_POSITION_OFFSET (1U << 24) // maximum frame/tile x/y offset
|
||||
|
||||
// Maximum chunk payload is such that adding the header and padding won't
|
||||
// overflow a uint32_t.
|
||||
|
Loading…
Reference in New Issue
Block a user