X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fvividas.c;h=603d01a2dc9fb3877204bb5371d075bfbf18550d;hb=c81b8e04aa0952a7aec1e08940f29ae501fb6bfd;hp=ecbe47765c6be72944128464ea72fa45f9bb7eae;hpb=e9909fe194181d99148ed7f2c605866dfef6c72a;p=ffmpeg diff --git a/libavformat/vividas.c b/libavformat/vividas.c index ecbe47765c6..603d01a2dc9 100644 --- a/libavformat/vividas.c +++ b/libavformat/vividas.c @@ -28,6 +28,7 @@ * @sa http://wiki.multimedia.cx/index.php?title=Vividas_VIV */ +#include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" #include "avio_internal.h" #include "avformat.h" @@ -52,6 +53,7 @@ typedef struct VIV_AudioSubpacket { typedef struct VividasDemuxContext { int n_sb_blocks; VIV_SB_block *sb_blocks; + int num_audio; uint32_t sb_key; int64_t sb_offset; @@ -70,7 +72,7 @@ typedef struct VividasDemuxContext { VIV_AudioSubpacket audio_subpackets[MAX_AUDIO_SUBPACKETS]; } VividasDemuxContext; -static int viv_probe(AVProbeData *p) +static int viv_probe(const AVProbeData *p) { if (memcmp(p->buf, "vividas03", 9)) return 0; @@ -78,11 +80,11 @@ static int viv_probe(AVProbeData *p) return AVPROBE_SCORE_MAX; } -static const unsigned short keybits[32] = { - 163, 416, 893, 82, 223, 572, 1137, 430, - 659, 1104, 13, 626, 695, 972, 1465, 686, - 843, 1216, 317, 1122, 1383, 92, 513, 1158, - 1243, 48, 573, 1306, 1495, 396, 1009, 350, +static const uint8_t keybits[32] = { + 20, 52, 111, 10, 27, 71, 142, 53, + 82, 138, 1, 78, 86, 121, 183, 85, +105, 152, 39, 140, 172, 11, 64, 144, +155, 6, 71, 163, 186, 49, 126, 43, }; static uint32_t decode_key(uint8_t *buf) @@ -91,7 +93,7 @@ static uint32_t decode_key(uint8_t *buf) for (int i = 0; i < 32; i++) { unsigned p = keybits[i]; - key |= !!(buf[p>>3] & (1<<(p&7))) << i; + key |= ((buf[p] >> ((i*5+3)&7)) & 1u) << i; } return key; @@ -115,10 +117,7 @@ static unsigned recover_key(unsigned char sample[4], unsigned expected_size) put_v(plaintext+2, expected_size); - return (sample[0]^plaintext[0])| - ((sample[1]^plaintext[1])<<8)| - ((sample[2]^plaintext[2])<<16)| - ((sample[3]^plaintext[3])<<24); + return AV_RL32(sample) ^ AV_RL32(plaintext); } static void xor_block(void *p1, void *p2, unsigned size, int key, unsigned *key_ptr) @@ -130,7 +129,7 @@ static void xor_block(void *p1, void *p2, unsigned size, int key, unsigned *key_ size >>= 2; while (size > 0) { - *d2 = *d1 ^ k; + *d2 = *d1 ^ (HAVE_BIGENDIAN ? av_bswap32(k) : k); k += key; d1++; d2++; @@ -156,6 +155,10 @@ static void decode_block(uint8_t *src, uint8_t *dest, unsigned size, if (align) { uint32_t tmpkey = *key_ptr - key; + if (a2 > s) { + a2 = s; + avpriv_request_sample(NULL, "tiny aligned block"); + } memcpy(tmp + align, src, a2); xor_block(tmp, tmp, 4, key, &tmpkey); memcpy(dest, tmp + align, a2); @@ -163,8 +166,6 @@ static void decode_block(uint8_t *src, uint8_t *dest, unsigned size, } if (s >= 4) { - if (!align) - align = 4; xor_block(src + a2, dest + a2, s & ~3, key, key_ptr); s &= 3; @@ -178,12 +179,13 @@ static void decode_block(uint8_t *src, uint8_t *dest, unsigned size, } } -static uint32_t get_v(uint8_t *p) +static uint32_t get_v(uint8_t *p, int len) { uint32_t v = 0; + const uint8_t *end = p + len; do { - if (v >= UINT_MAX / 128 - *p) + if (p >= end || v >= UINT_MAX / 128 - *p) return v; v <<= 7; v += *p & 0x7f; @@ -204,8 +206,8 @@ static uint8_t *read_vblock(AVIOContext *src, uint32_t *size, decode_block(tmp, tmp, 4, key, k2, align); - n = get_v(tmp); - if (!n) + n = get_v(tmp, 4); + if (n < 4) return NULL; buf = av_malloc(n); @@ -218,7 +220,7 @@ static uint8_t *read_vblock(AVIOContext *src, uint32_t *size, memcpy(buf, tmp, 4); if (avio_read(src, buf + 4, n) == n) { - decode_block(buf + 4, buf + 4, n, key, k2, align + 4); + decode_block(buf + 4, buf + 4, n, key, k2, align); } else { av_free(buf); buf = NULL; @@ -241,18 +243,21 @@ static uint8_t *read_sb_block(AVIOContext *src, unsigned *size, k2 = *key; decode_block(ibuf, sbuf, 8, *key, &k2, 0); - n = get_v(sbuf+2); + n = get_v(sbuf+2, 6); if (sbuf[0] != 'S' || sbuf[1] != 'B' || (expected_size>0 && n != expected_size)) { uint32_t tmpkey = recover_key(ibuf, expected_size); k2 = tmpkey; decode_block(ibuf, sbuf, 8, tmpkey, &k2, 0); - n = get_v(sbuf+2); + n = get_v(sbuf+2, 6); if (sbuf[0] != 'S' || sbuf[1] != 'B' || expected_size != n) return NULL; *key = tmpkey; } + if (n < 8) + return NULL; + buf = av_malloc(n); if (!buf) return NULL; @@ -262,7 +267,7 @@ static uint8_t *read_sb_block(AVIOContext *src, unsigned *size, *size = n; n -= 8; - if (avio_read(src, buf+8, n) < n) { + if (avio_read(src, buf+8, n) != n) { av_free(buf); return NULL; } @@ -272,17 +277,15 @@ static uint8_t *read_sb_block(AVIOContext *src, unsigned *size, return buf; } -static void track_header(VividasDemuxContext *viv, AVFormatContext *s, uint8_t *buf, int size) +static int track_header(VividasDemuxContext *viv, AVFormatContext *s, uint8_t *buf, int size) { - int i,j; + int i, j, ret; int64_t off; int val_1; - int num_video, num_audio; - AVIOContext *pb; + int num_video; + AVIOContext pb0, *pb = &pb0; - pb = avio_alloc_context(buf, size, 0, NULL, NULL, NULL, NULL); - if (!pb) - return; + ffio_init_context(pb, buf, size, 0, NULL, NULL, NULL, NULL); ffio_read_varlen(pb); // track_header_len avio_r8(pb); // '1' @@ -291,7 +294,11 @@ static void track_header(VividasDemuxContext *viv, AVFormatContext *s, uint8_t for (i=0;iid = i; @@ -321,8 +334,9 @@ static void track_header(VividasDemuxContext *viv, AVFormatContext *s, uint8_t off += ffio_read_varlen(pb); avio_r8(pb); // '3' avio_r8(pb); // val_7 - st->time_base.num = avio_rl32(pb); // frame_time - st->time_base.den = avio_rl32(pb); // time_base + num = avio_rl32(pb); // frame_time + den = avio_rl32(pb); // time_base + avpriv_set_pts_info(st, 64, num, den); st->nb_frames = avio_rl32(pb); // n frames st->codecpar->width = avio_rl16(pb); // width st->codecpar->height = avio_rl16(pb); // height @@ -335,15 +349,17 @@ static void track_header(VividasDemuxContext *viv, AVFormatContext *s, uint8_t off = avio_tell(pb); off += ffio_read_varlen(pb); // val_10 avio_r8(pb); // '4' - num_audio = avio_r8(pb); + viv->num_audio = avio_r8(pb); avio_seek(pb, off, SEEK_SET); - if (num_audio != 1) - av_log(s, AV_LOG_WARNING, "number of audio tracks %d is not 1\n", num_audio); + if (viv->num_audio != 1) + av_log(s, AV_LOG_WARNING, "number of audio tracks %d is not 1\n", viv->num_audio); - for(i=0;inum_audio;i++) { int q; AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); st->id = num_video + i; @@ -357,6 +373,8 @@ static void track_header(VividasDemuxContext *viv, AVFormatContext *s, uint8_t avio_rl16(pb); //codec_subid st->codecpar->channels = avio_rl16(pb); // channels st->codecpar->sample_rate = avio_rl32(pb); // sample_rate + if (st->codecpar->sample_rate <= 0 || st->codecpar->channels <= 0) + return AVERROR_INVALIDDATA; avio_seek(pb, 10, SEEK_CUR); // data_1 q = avio_r8(pb); avio_seek(pb, q, SEEK_CUR); // data_2 @@ -364,7 +382,7 @@ static void track_header(VividasDemuxContext *viv, AVFormatContext *s, uint8_t if (avio_tell(pb) < off) { int num_data; - int xd_size = 0; + int xd_size = 1; int data_len[256]; int offset = 1; uint8_t *p; @@ -373,74 +391,100 @@ static void track_header(VividasDemuxContext *viv, AVFormatContext *s, uint8_t ffio_read_varlen(pb); // len_3 num_data = avio_r8(pb); for (j = 0; j < num_data; j++) { - data_len[j] = ffio_read_varlen(pb); - xd_size += data_len[j]; + int64_t len = ffio_read_varlen(pb); + if (len < 0 || len > INT_MAX/2 - xd_size) { + return AVERROR_INVALIDDATA; + } + data_len[j] = len; + xd_size += len + 1 + len/255; } - st->codecpar->extradata_size = 64 + xd_size + xd_size / 255; - if (ff_alloc_extradata(st->codecpar, st->codecpar->extradata_size)) - return; + ret = ff_alloc_extradata(st->codecpar, xd_size); + if (ret < 0) + return ret; p = st->codecpar->extradata; p[0] = 2; - for (j = 0; j < num_data - 1; j++) - offset += av_xiphlacing(&p[offset], data_len[j]); + for (j = 0; j < num_data - 1; j++) { + unsigned delta = av_xiphlacing(&p[offset], data_len[j]); + av_assert0(delta <= xd_size - offset); + offset += delta; + } for (j = 0; j < num_data; j++) { - avio_read(pb, &p[offset], data_len[j]); + int ret = avio_read(pb, &p[offset], data_len[j]); + if (ret < data_len[j]) { + st->codecpar->extradata_size = 0; + av_freep(&st->codecpar->extradata); + break; + } + av_assert0(data_len[j] <= xd_size - offset); offset += data_len[j]; } - st->codecpar->extradata_size = offset; + if (offset < st->codecpar->extradata_size) + st->codecpar->extradata_size = offset; } } - av_free(pb); + return 0; } -static void track_index(VividasDemuxContext *viv, AVFormatContext *s, uint8_t *buf, unsigned size) +static int track_index(VividasDemuxContext *viv, AVFormatContext *s, uint8_t *buf, unsigned size) { int64_t off; int64_t poff; int maxnp=0; - AVIOContext *pb; + AVIOContext pb0, *pb = &pb0; int i; + int64_t filesize = avio_size(s->pb); + uint64_t n_sb_blocks_tmp; - pb = avio_alloc_context(buf, size, 0, NULL, NULL, NULL, NULL); - if (!pb) - return; + ffio_init_context(pb, buf, size, 0, NULL, NULL, NULL, NULL); ffio_read_varlen(pb); // track_index_len avio_r8(pb); // 'c' - viv->n_sb_blocks = ffio_read_varlen(pb); - viv->sb_blocks = av_calloc(viv->n_sb_blocks, sizeof(VIV_SB_block)); + n_sb_blocks_tmp = ffio_read_varlen(pb); + if (n_sb_blocks_tmp > size / 2) + return AVERROR_INVALIDDATA; + viv->sb_blocks = av_calloc(n_sb_blocks_tmp, sizeof(*viv->sb_blocks)); if (!viv->sb_blocks) { - viv->n_sb_blocks = 0; - av_free(pb); - return; + return AVERROR(ENOMEM); } + viv->n_sb_blocks = n_sb_blocks_tmp; off = 0; poff = 0; for (i = 0; i < viv->n_sb_blocks; i++) { + uint64_t size_tmp = ffio_read_varlen(pb); + uint64_t n_packets_tmp = ffio_read_varlen(pb); + + if (size_tmp > INT_MAX || n_packets_tmp > INT_MAX) + return AVERROR_INVALIDDATA; + viv->sb_blocks[i].byte_offset = off; viv->sb_blocks[i].packet_offset = poff; - viv->sb_blocks[i].size = ffio_read_varlen(pb); - viv->sb_blocks[i].n_packets = ffio_read_varlen(pb); + viv->sb_blocks[i].size = size_tmp; + viv->sb_blocks[i].n_packets = n_packets_tmp; off += viv->sb_blocks[i].size; poff += viv->sb_blocks[i].n_packets; - if (maxnp < viv->sb_blocks[i].n_packets) maxnp = viv->sb_blocks[i].n_packets; } + if (filesize > 0 && poff > filesize) + return AVERROR_INVALIDDATA; + viv->sb_entries = av_calloc(maxnp, sizeof(VIV_SB_entry)); - av_free(pb); + if (!viv->sb_entries) + return AVERROR(ENOMEM); + + return 0; } static void load_sb_block(AVFormatContext *s, VividasDemuxContext *viv, unsigned expected_size) @@ -499,6 +543,7 @@ static int viv_read_header(AVFormatContext *s) uint32_t b22_size = 0; uint32_t b22_key = 0; uint8_t *buf = 0; + int ret; avio_skip(pb, 9); @@ -530,6 +575,9 @@ static int viv_read_header(AVFormatContext *s) break; block_len = ffio_read_varlen(pb); + if (avio_feof(pb) || block_len <= 0) + return AVERROR_INVALIDDATA; + block_type = avio_r8(pb); if (block_type == 22) { @@ -554,14 +602,18 @@ static int viv_read_header(AVFormatContext *s) buf = read_vblock(pb, &v, key, &k2, 0); if (!buf) return AVERROR(EIO); - track_header(viv, s, buf, v); + ret = track_header(viv, s, buf, v); av_free(buf); + if (ret < 0) + return ret; buf = read_vblock(pb, &v, key, &k2, v); if (!buf) return AVERROR(EIO); - track_index(viv, s, buf, v); + ret = track_index(viv, s, buf, v); av_free(buf); + if (ret < 0) + goto fail; viv->sb_offset = avio_tell(pb); if (viv->n_sb_blocks > 0) { @@ -572,6 +624,9 @@ static int viv_read_header(AVFormatContext *s) } return 0; +fail: + av_freep(&viv->sb_blocks); + return ret; } static int viv_read_packet(AVFormatContext *s, @@ -582,6 +637,8 @@ static int viv_read_packet(AVFormatContext *s, int64_t off; int ret; + if (!viv->sb_pb) + return AVERROR(EIO); if (avio_feof(viv->sb_pb)) return AVERROR_EOF; @@ -598,7 +655,7 @@ static int viv_read_packet(AVFormatContext *s, pkt->stream_index = 1; astream = s->streams[pkt->stream_index]; - pkt->pts = av_rescale(viv->audio_sample, astream->time_base.den, astream->time_base.num) / astream->codecpar->sample_rate; + pkt->pts = av_rescale_q(viv->audio_sample, av_make_q(1, astream->codecpar->sample_rate), astream->time_base); viv->audio_sample += viv->audio_subpackets[viv->current_audio_subpacket].pcm_bytes / 2 / astream->codecpar->channels; pkt->flags |= AV_PKT_FLAG_KEY; viv->current_audio_subpacket++; @@ -615,14 +672,23 @@ static int viv_read_packet(AVFormatContext *s, } pb = viv->sb_pb; + if (!pb) + return AVERROR(EIO); off = avio_tell(pb); + + if (viv->current_sb_entry >= viv->n_sb_entries) + return AVERROR_INVALIDDATA; + off += viv->sb_entries[viv->current_sb_entry].size; if (viv->sb_entries[viv->current_sb_entry].flag == 0) { uint64_t v_size = ffio_read_varlen(pb); + if (!viv->num_audio) + return AVERROR_INVALIDDATA; + ffio_read_varlen(pb); - if (v_size > INT_MAX) + if (v_size > INT_MAX || !v_size) return AVERROR_INVALIDDATA; ret = av_get_packet(pb, pkt, v_size); if (ret < 0) @@ -651,7 +717,7 @@ static int viv_read_packet(AVFormatContext *s, } else { uint64_t v_size = ffio_read_varlen(pb); - if (v_size > INT_MAX) + if (v_size > INT_MAX || !v_size) return AVERROR_INVALIDDATA; ret = av_get_packet(pb, pkt, v_size); if (ret < 0)