Protects against overreads. Signed-off-by: Paul B Mahol <onemda@gmail.com> Signed-off-by: Ronald S. Bultje <rsbultje@gmail.com>tags/n0.11
| @@ -21,19 +21,19 @@ | |||||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| */ | */ | ||||
| #include "libavutil/intreadwrite.h" | |||||
| #include "libavcodec/bytestream.h" | |||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "s3tc.h" | #include "s3tc.h" | ||||
| static inline void dxt1_decode_pixels(const uint8_t *s, uint32_t *d, | |||||
| static inline void dxt1_decode_pixels(GetByteContext *gb, uint32_t *d, | |||||
| unsigned int qstride, unsigned int flag, | unsigned int qstride, unsigned int flag, | ||||
| uint64_t alpha) { | uint64_t alpha) { | ||||
| unsigned int x, y, c0, c1, a = (!flag * 255u) << 24; | unsigned int x, y, c0, c1, a = (!flag * 255u) << 24; | ||||
| unsigned int rb0, rb1, rb2, rb3, g0, g1, g2, g3; | unsigned int rb0, rb1, rb2, rb3, g0, g1, g2, g3; | ||||
| uint32_t colors[4], pixels; | uint32_t colors[4], pixels; | ||||
| c0 = AV_RL16(s); | |||||
| c1 = AV_RL16(s+2); | |||||
| c0 = bytestream2_get_le16(gb); | |||||
| c1 = bytestream2_get_le16(gb); | |||||
| rb0 = (c0<<3 | c0<<8) & 0xf800f8; | rb0 = (c0<<3 | c0<<8) & 0xf800f8; | ||||
| rb1 = (c1<<3 | c1<<8) & 0xf800f8; | rb1 = (c1<<3 | c1<<8) & 0xf800f8; | ||||
| @@ -61,7 +61,7 @@ static inline void dxt1_decode_pixels(const uint8_t *s, uint32_t *d, | |||||
| colors[2] = rb2 + g2 + a; | colors[2] = rb2 + g2 + a; | ||||
| pixels = AV_RL32(s+4); | |||||
| pixels = bytestream2_get_le32(gb); | |||||
| for (y=0; y<4; y++) { | for (y=0; y<4; y++) { | ||||
| for (x=0; x<4; x++) { | for (x=0; x<4; x++) { | ||||
| a = (alpha & 0x0f) << 28; | a = (alpha & 0x0f) << 28; | ||||
| @@ -74,24 +74,24 @@ static inline void dxt1_decode_pixels(const uint8_t *s, uint32_t *d, | |||||
| } | } | ||||
| } | } | ||||
| void ff_decode_dxt1(const uint8_t *s, uint8_t *dst, | |||||
| void ff_decode_dxt1(GetByteContext *gb, uint8_t *dst, | |||||
| const unsigned int w, const unsigned int h, | const unsigned int w, const unsigned int h, | ||||
| const unsigned int stride) { | const unsigned int stride) { | ||||
| unsigned int bx, by, qstride = stride/4; | unsigned int bx, by, qstride = stride/4; | ||||
| uint32_t *d = (uint32_t *) dst; | uint32_t *d = (uint32_t *) dst; | ||||
| for (by=0; by < h/4; by++, d += stride-w) | for (by=0; by < h/4; by++, d += stride-w) | ||||
| for (bx=0; bx < w/4; bx++, s+=8, d+=4) | |||||
| dxt1_decode_pixels(s, d, qstride, 0, 0LL); | |||||
| for (bx = 0; bx < w / 4; bx++, d += 4) | |||||
| dxt1_decode_pixels(gb, d, qstride, 0, 0LL); | |||||
| } | } | ||||
| void ff_decode_dxt3(const uint8_t *s, uint8_t *dst, | |||||
| void ff_decode_dxt3(GetByteContext *gb, uint8_t *dst, | |||||
| const unsigned int w, const unsigned int h, | const unsigned int w, const unsigned int h, | ||||
| const unsigned int stride) { | const unsigned int stride) { | ||||
| unsigned int bx, by, qstride = stride/4; | unsigned int bx, by, qstride = stride/4; | ||||
| uint32_t *d = (uint32_t *) dst; | uint32_t *d = (uint32_t *) dst; | ||||
| for (by=0; by < h/4; by++, d += stride-w) | for (by=0; by < h/4; by++, d += stride-w) | ||||
| for (bx=0; bx < w/4; bx++, s+=16, d+=4) | |||||
| dxt1_decode_pixels(s+8, d, qstride, 1, AV_RL64(s)); | |||||
| for (bx = 0; bx < w / 4; bx++, d += 4) | |||||
| dxt1_decode_pixels(gb, d, qstride, 1, bytestream2_get_le64(gb)); | |||||
| } | } | ||||
| @@ -29,24 +29,24 @@ | |||||
| /** | /** | ||||
| * Decode DXT1 encoded data to RGB32 | * Decode DXT1 encoded data to RGB32 | ||||
| * @param src source buffer, has to be aligned on a 4-byte boundary | |||||
| * @param gb GetByteContext | |||||
| * @param dst destination buffer | * @param dst destination buffer | ||||
| * @param w width of output image | * @param w width of output image | ||||
| * @param h height of output image | * @param h height of output image | ||||
| * @param stride line size of output image | * @param stride line size of output image | ||||
| */ | */ | ||||
| void ff_decode_dxt1(const uint8_t *src, uint8_t *dst, | |||||
| void ff_decode_dxt1(GetByteContext *gb, uint8_t *dst, | |||||
| const unsigned int w, const unsigned int h, | const unsigned int w, const unsigned int h, | ||||
| const unsigned int stride); | const unsigned int stride); | ||||
| /** | /** | ||||
| * Decode DXT3 encoded data to RGB32 | * Decode DXT3 encoded data to RGB32 | ||||
| * @param src source buffer, has to be aligned on a 4-byte boundary | |||||
| * @param gb GetByteContext | |||||
| * @param dst destination buffer | * @param dst destination buffer | ||||
| * @param w width of output image | * @param w width of output image | ||||
| * @param h height of output image | * @param h height of output image | ||||
| * @param stride line size of output image | * @param stride line size of output image | ||||
| */ | */ | ||||
| void ff_decode_dxt3(const uint8_t *src, uint8_t *dst, | |||||
| void ff_decode_dxt3(GetByteContext *gb, uint8_t *dst, | |||||
| const unsigned int w, const unsigned int h, | const unsigned int w, const unsigned int h, | ||||
| const unsigned int stride); | const unsigned int stride); | ||||
| @@ -24,6 +24,7 @@ | |||||
| #include "libavutil/intreadwrite.h" | #include "libavutil/intreadwrite.h" | ||||
| #include "libavutil/imgutils.h" | #include "libavutil/imgutils.h" | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bytestream.h" | |||||
| #include "s3tc.h" | #include "s3tc.h" | ||||
| typedef struct TXDContext { | typedef struct TXDContext { | ||||
| @@ -41,25 +42,25 @@ static av_cold int txd_init(AVCodecContext *avctx) { | |||||
| static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size, | static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size, | ||||
| AVPacket *avpkt) { | AVPacket *avpkt) { | ||||
| const uint8_t *buf = avpkt->data; | |||||
| TXDContext * const s = avctx->priv_data; | TXDContext * const s = avctx->priv_data; | ||||
| GetByteContext gb; | |||||
| AVFrame *picture = data; | AVFrame *picture = data; | ||||
| AVFrame * const p = &s->picture; | AVFrame * const p = &s->picture; | ||||
| unsigned int version, w, h, d3d_format, depth, stride, mipmap_count, flags; | unsigned int version, w, h, d3d_format, depth, stride, mipmap_count, flags; | ||||
| unsigned int y, v; | unsigned int y, v; | ||||
| uint8_t *ptr; | uint8_t *ptr; | ||||
| const uint8_t *cur = buf; | |||||
| const uint32_t *palette = (const uint32_t *)(cur + 88); | |||||
| uint32_t *pal; | uint32_t *pal; | ||||
| version = AV_RL32(cur); | |||||
| d3d_format = AV_RL32(cur+76); | |||||
| w = AV_RL16(cur+80); | |||||
| h = AV_RL16(cur+82); | |||||
| depth = AV_RL8 (cur+84); | |||||
| mipmap_count = AV_RL8 (cur+85); | |||||
| flags = AV_RL8 (cur+87); | |||||
| cur += 92; | |||||
| bytestream2_init(&gb, avpkt->data, avpkt->size); | |||||
| version = bytestream2_get_le32(&gb); | |||||
| bytestream2_skip(&gb, 72); | |||||
| d3d_format = bytestream2_get_le32(&gb); | |||||
| w = bytestream2_get_le16(&gb); | |||||
| h = bytestream2_get_le16(&gb); | |||||
| depth = bytestream2_get_byte(&gb); | |||||
| mipmap_count = bytestream2_get_byte(&gb); | |||||
| bytestream2_skip(&gb, 1); | |||||
| flags = bytestream2_get_byte(&gb); | |||||
| if (version < 8 || version > 9) { | if (version < 8 || version > 9) { | ||||
| av_log(avctx, AV_LOG_ERROR, "texture data version %i is unsupported\n", | av_log(avctx, AV_LOG_ERROR, "texture data version %i is unsupported\n", | ||||
| @@ -69,10 +70,9 @@ static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size, | |||||
| if (depth == 8) { | if (depth == 8) { | ||||
| avctx->pix_fmt = PIX_FMT_PAL8; | avctx->pix_fmt = PIX_FMT_PAL8; | ||||
| cur += 1024; | |||||
| } else if (depth == 16 || depth == 32) | |||||
| } else if (depth == 16 || depth == 32) { | |||||
| avctx->pix_fmt = PIX_FMT_RGB32; | avctx->pix_fmt = PIX_FMT_RGB32; | ||||
| else { | |||||
| } else { | |||||
| av_log(avctx, AV_LOG_ERROR, "depth of %i is unsupported\n", depth); | av_log(avctx, AV_LOG_ERROR, "depth of %i is unsupported\n", depth); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -96,25 +96,26 @@ static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size, | |||||
| if (depth == 8) { | if (depth == 8) { | ||||
| pal = (uint32_t *) p->data[1]; | pal = (uint32_t *) p->data[1]; | ||||
| for (y=0; y<256; y++) { | |||||
| v = AV_RB32(palette+y); | |||||
| pal[y] = (v>>8) + (v<<24); | |||||
| for (y = 0; y < 256; y++) { | |||||
| v = bytestream2_get_be32(&gb); | |||||
| pal[y] = (v >> 8) + (v << 24); | |||||
| } | } | ||||
| bytestream2_skip(&gb, 4); | |||||
| for (y=0; y<h; y++) { | for (y=0; y<h; y++) { | ||||
| memcpy(ptr, cur, w); | |||||
| bytestream2_get_buffer(&gb, ptr, w); | |||||
| ptr += stride; | ptr += stride; | ||||
| cur += w; | |||||
| } | } | ||||
| } else if (depth == 16) { | } else if (depth == 16) { | ||||
| bytestream2_skip(&gb, 4); | |||||
| switch (d3d_format) { | switch (d3d_format) { | ||||
| case 0: | case 0: | ||||
| if (!(flags & 1)) | if (!(flags & 1)) | ||||
| goto unsupported; | goto unsupported; | ||||
| case FF_S3TC_DXT1: | case FF_S3TC_DXT1: | ||||
| ff_decode_dxt1(cur, ptr, w, h, stride); | |||||
| ff_decode_dxt1(&gb, ptr, w, h, stride); | |||||
| break; | break; | ||||
| case FF_S3TC_DXT3: | case FF_S3TC_DXT3: | ||||
| ff_decode_dxt3(cur, ptr, w, h, stride); | |||||
| ff_decode_dxt3(&gb, ptr, w, h, stride); | |||||
| break; | break; | ||||
| default: | default: | ||||
| goto unsupported; | goto unsupported; | ||||
| @@ -124,9 +125,8 @@ static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size, | |||||
| case 0x15: | case 0x15: | ||||
| case 0x16: | case 0x16: | ||||
| for (y=0; y<h; y++) { | for (y=0; y<h; y++) { | ||||
| memcpy(ptr, cur, w*4); | |||||
| bytestream2_get_buffer(&gb, ptr, w * 4); | |||||
| ptr += stride; | ptr += stride; | ||||
| cur += w*4; | |||||
| } | } | ||||
| break; | break; | ||||
| default: | default: | ||||
| @@ -134,13 +134,10 @@ static int txd_decode_frame(AVCodecContext *avctx, void *data, int *data_size, | |||||
| } | } | ||||
| } | } | ||||
| for (; mipmap_count > 1; mipmap_count--) | |||||
| cur += AV_RL32(cur) + 4; | |||||
| *picture = s->picture; | *picture = s->picture; | ||||
| *data_size = sizeof(AVPicture); | *data_size = sizeof(AVPicture); | ||||
| return cur - buf; | |||||
| return avpkt->size; | |||||
| unsupported: | unsupported: | ||||
| av_log(avctx, AV_LOG_ERROR, "unsupported d3d format (%08x)\n", d3d_format); | av_log(avctx, AV_LOG_ERROR, "unsupported d3d format (%08x)\n", d3d_format); | ||||