Package: libavcodec-dev Version: 0.cvs20050106-1 Severity: grave Tags: security Justification: user security hole
[Cc'ing security@, as at least xine-lib embeds libavcodec, there may be more, I haven't investigated whether they are affected, but I assume it's the case] The most recent ffmpeg-cvs-log message from ffmpeg maintainer Michael Niedermayer mentions | integer overflows, heap corruption | possible arbitrary code execution cannot be ruled out in some cases | precautionary checks Feel free to downgrade severity if it turns out not to be exploitable. I've attached the complete commit message, which includes the fixes. Cheers, Moritz -- System Information: Debian Release: 3.1 APT prefers unstable APT policy: (500, 'unstable') Architecture: i386 (i686) Kernel: Linux 2.6.9-1-386 Locale: LANG=C, [EMAIL PROTECTED] (charmap=ISO-8859-15) Versions of packages libavcodec-dev depends on: ii liba52-0.7.4-dev [liba52-dev 0.7.4-1 Development library and headers fo ii libdts-dev 0.0.2-svn-1 development files for libdts ii libvorbis-dev 1.0.1-1 The Vorbis General Audio Compressi ii zlib1g-dev 1:1.2.2-4 compression library - development -- no debconf information
Update of /cvsroot/ffmpeg/ffmpeg/libavformat In directory mail:/var2/tmp/cvs-serv27074 Modified Files: 4xm.c allformats.c avidec.c aviobuf.c gifdec.c grab.c http.c img.c img2.c matroska.c mov.c nsvdec.c nut.c ogg.c segafilm.c sgi.c utils.c wc3movie.c avformat.h Log Message: integer overflows, heap corruption possible arbitrary code execution cannot be ruled out in some cases precautionary checks Index: 4xm.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/4xm.c,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- 4xm.c 19 Jun 2004 03:59:33 -0000 1.13 +++ 4xm.c 8 Jan 2005 14:21:32 -0000 1.14 @@ -185,6 +185,8 @@ current_track = LE_32(&header[i + 8]); if (current_track + 1 > fourxm->track_count) { fourxm->track_count = current_track + 1; + if((unsigned)fourxm->track_count >= UINT_MAX / sizeof(AudioTrack)) + return -1; fourxm->tracks = av_realloc(fourxm->tracks, fourxm->track_count * sizeof(AudioTrack)); if (!fourxm->tracks) { Index: allformats.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/allformats.c,v retrieving revision 1.42 retrieving revision 1.43 diff -u -d -r1.42 -r1.43 --- allformats.c 4 Jan 2005 14:38:52 -0000 1.42 +++ allformats.c 8 Jan 2005 14:21:32 -0000 1.43 @@ -125,8 +125,8 @@ #endif av_register_image_format(&jpeg_image_format); #endif - av_register_image_format(&gif_image_format); - av_register_image_format(&sgi_image_format); + av_register_image_format(&gif_image_format); +// av_register_image_format(&sgi_image_format); heap corruption, dont enable #endif //CONFIG_ENCODERS /* file protocols */ Index: avidec.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/avidec.c,v retrieving revision 1.58 retrieving revision 1.59 diff -u -d -r1.58 -r1.59 --- avidec.c 19 Dec 2004 02:55:40 -0000 1.58 +++ avidec.c 8 Jan 2005 14:21:32 -0000 1.59 @@ -302,9 +302,11 @@ get_le32(pb); /* ClrUsed */ get_le32(pb); /* ClrImportant */ + if(size > 10*4 && size<(1<<30)){ st->codec.extradata_size= size - 10*4; st->codec.extradata= av_malloc(st->codec.extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); get_buffer(pb, st->codec.extradata, st->codec.extradata_size); + } if(st->codec.extradata_size & 1) //FIXME check if the encoder really did this correctly get_byte(pb); @@ -549,6 +551,8 @@ nb_index_entries = size / 16; if (nb_index_entries <= 0) return -1; + if(nb_index_entries + 1 >= UINT_MAX / sizeof(AVIIndexEntry)) + return -1; /* read the entries and sort them in each stream component */ for(i = 0; i < nb_index_entries; i++) { Index: aviobuf.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/aviobuf.c,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- aviobuf.c 8 Oct 2004 20:09:52 -0000 1.22 +++ aviobuf.c 8 Jan 2005 14:21:32 -0000 1.23 @@ -629,11 +629,13 @@ /* reallocate buffer if needed */ new_size = d->pos + buf_size; new_allocated_size = d->allocated_size; + if(new_size < d->pos || new_size > INT_MAX/2) + return -1; while (new_size > new_allocated_size) { if (!new_allocated_size) new_allocated_size = new_size; else - new_allocated_size = (new_allocated_size * 3) / 2 + 1; + new_allocated_size += new_allocated_size / 2 + 1; } if (new_allocated_size > d->allocated_size) { @@ -691,6 +693,8 @@ else io_buffer_size = 1024; + if(sizeof(DynBuffer) + io_buffer_size < io_buffer_size) + return -1; d = av_malloc(sizeof(DynBuffer) + io_buffer_size); if (!d) return -1; Index: gifdec.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/gifdec.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- gifdec.c 19 Jun 2004 03:59:34 -0000 1.6 +++ gifdec.c 8 Jan 2005 14:21:32 -0000 1.7 @@ -474,6 +474,12 @@ s->transparent_color_index = -1; s->screen_width = get_le16(f); s->screen_height = get_le16(f); + if( (unsigned)s->screen_width > 32767 + || (unsigned)s->screen_height > 32767){ + av_log(NULL, AV_LOG_ERROR, "picture size too large\n"); + return -1; + } + v = get_byte(f); s->color_resolution = ((v & 0x70) >> 4) + 1; has_global_palette = (v & 0x80); Index: grab.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/grab.c,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- grab.c 19 Jun 2004 03:59:34 -0000 1.32 +++ grab.c 8 Jan 2005 14:21:32 -0000 1.33 @@ -76,6 +76,9 @@ frame_rate = ap->frame_rate; frame_rate_base = ap->frame_rate_base; + if((unsigned)width > 32767 || (unsigned)height > 32767) + return -1; + st = av_new_stream(s1, 0); if (!st) return -ENOMEM; Index: http.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/http.c,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- http.c 12 Aug 2004 00:09:32 -0000 1.17 +++ http.c 8 Jan 2005 14:21:32 -0000 1.18 @@ -290,12 +290,16 @@ static char *b64_encode( unsigned char *src ) { static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - char *dst = av_malloc( strlen( src ) * 4 / 3 + 12 ); - char *ret = dst; + unsigned int len= strlen(src); + char *ret, *dst; unsigned i_bits = 0; unsigned i_shift = 0; - + + if(len < UINT_MAX/4){ + ret=dst= av_malloc( len * 4 / 3 + 12 ); + }else + return NULL; + for( ;; ) { if( *src ) Index: img.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/img.c,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- img.c 10 Nov 2004 00:02:06 -0000 1.38 +++ img.c 8 Jan 2005 14:21:32 -0000 1.39 @@ -123,7 +123,7 @@ if (ap && ap->image_format) s->img_fmt = ap->image_format; - strcpy(s->path, s1->filename); + pstrcpy(s->path, sizeof(s->path), s1->filename); s->img_number = 0; s->img_count = 0; @@ -289,7 +289,7 @@ VideoData *img = s->priv_data; img->img_number = 1; - strcpy(img->path, s->filename); + pstrcpy(img->path, sizeof(img->path), s->filename); /* find format */ if (s->oformat->flags & AVFMT_NOFILE) Index: img2.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/img2.c,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- img2.c 4 Jan 2005 13:27:35 -0000 1.10 +++ img2.c 8 Jan 2005 14:21:32 -0000 1.11 @@ -184,7 +184,7 @@ return -ENOMEM; } - strcpy(s->path, s1->filename); + pstrcpy(s->path, sizeof(s->path), s1->filename); s->img_number = 0; s->img_count = 0; @@ -310,7 +310,7 @@ VideoData *img = s->priv_data; img->img_number = 1; - strcpy(img->path, s->filename); + pstrcpy(img->path, sizeof(img->path), s->filename); /* find format */ if (s->oformat->flags & AVFMT_NOFILE) Index: matroska.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/matroska.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- matroska.c 14 Jul 2004 01:32:14 -0000 1.6 +++ matroska.c 8 Jan 2005 14:21:32 -0000 1.7 @@ -669,7 +669,7 @@ /* ebml strings are usually not 0-terminated, so we allocate one * byte more, read the string and NULL-terminate it ourselves. */ - if (!(*str = av_malloc(size + 1))) { + if (size < 0 || !(*str = av_malloc(size + 1))) { av_log(matroska->ctx, AV_LOG_ERROR, "Memory allocation failed\n"); return AVERROR_NOMEM; } Index: mov.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/mov.c,v retrieving revision 1.57 retrieving revision 1.58 diff -u -d -r1.57 -r1.58 --- mov.c 9 Dec 2004 19:44:55 -0000 1.57 +++ mov.c 8 Jan 2005 14:21:32 -0000 1.58 @@ -367,6 +367,10 @@ /* empty */; a.size -= 8; + + if(a.size < 0) + break; + // av_log(NULL, AV_LOG_DEBUG, " i=%ld\n", i); if (c->parse_table[i].type == 0) { /* skip leaf atoms data */ // url_seek(pb, atom.offset+atom.size, SEEK_SET); @@ -401,7 +405,10 @@ { unsigned int len; MOV_ctab_t *t; - //url_fskip(pb, atom.size); // for now +#if 1 + url_fskip(pb, atom.size); // for now +#else + VERY VERY BROKEN, NEVER execute this, needs rewrite c->ctab = av_realloc(c->ctab, ++c->ctab_size); t = c->ctab[c->ctab_size]; t->seed = get_be32(pb); @@ -413,6 +420,7 @@ if (t->clrs) get_buffer(pb, t->clrs, len); } +#endif return 0; } @@ -677,6 +685,9 @@ { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; + if((uint64_t)atom.size > (1<<30)) + return -1; + // currently SVQ3 decoder expect full STSD header - so let's fake it // this should be fixed and just SMI header should be passed av_free(st->codec.extradata); @@ -697,6 +708,9 @@ { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; + if((uint64_t)atom.size > (1<<30)) + return -1; + av_free(st->codec.extradata); st->codec.extradata_size = atom.size; @@ -714,7 +728,7 @@ { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - int entries, i; + unsigned int i, entries; print_atom("stco", atom); @@ -722,6 +736,10 @@ get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ entries = get_be32(pb); + + if(entries >= UINT_MAX/sizeof(int64_t)) + return -1; + sc->chunk_count = entries; sc->chunk_offsets = (int64_t*) av_malloc(entries * sizeof(int64_t)); if (!sc->chunk_offsets) @@ -1138,7 +1156,7 @@ { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - int entries, i; + unsigned int i, entries; print_atom("stsc", atom); @@ -1146,6 +1164,10 @@ get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ entries = get_be32(pb); + + if(entries >= UINT_MAX / sizeof(MOV_sample_to_chunk_tbl)) + return -1; + #ifdef DEBUG av_log(NULL, AV_LOG_DEBUG, "track[%i].stsc.entries = %i\n", c->fc->nb_streams-1, entries); #endif @@ -1168,7 +1190,7 @@ { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - int entries, i; + unsigned int i, entries; print_atom("stss", atom); @@ -1176,6 +1198,10 @@ get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ entries = get_be32(pb); + + if(entries >= UINT_MAX / sizeof(long)) + return -1; + sc->keyframe_count = entries; #ifdef DEBUG av_log(NULL, AV_LOG_DEBUG, "keyframe_count = %ld\n", sc->keyframe_count); @@ -1196,7 +1222,7 @@ { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - int entries, i; + unsigned int i, entries; print_atom("stsz", atom); @@ -1205,6 +1231,9 @@ sc->sample_size = get_be32(pb); entries = get_be32(pb); + if(entries >= UINT_MAX / sizeof(long)) + return -1; + sc->sample_count = entries; #ifdef DEBUG av_log(NULL, AV_LOG_DEBUG, "sample_size = %ld sample_count = %ld\n", sc->sample_size, sc->sample_count); @@ -1227,7 +1256,7 @@ { AVStream *st = c->fc->streams[c->fc->nb_streams-1]; //MOVStreamContext *sc = (MOVStreamContext *)st->priv_data; - int entries, i; + unsigned int i, entries; int64_t duration=0; int64_t total_sample_count=0; @@ -1236,6 +1265,8 @@ get_byte(pb); /* version */ get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ entries = get_be32(pb); + if(entries >= UINT_MAX / sizeof(uint64_t)) + return -1; c->streams[c->fc->nb_streams-1]->stts_count = entries; c->streams[c->fc->nb_streams-1]->stts_data = (uint64_t*) av_malloc(entries * sizeof(uint64_t)); Index: nsvdec.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/nsvdec.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- nsvdec.c 30 Nov 2004 21:57:51 -0000 1.3 +++ nsvdec.c 8 Jan 2005 14:21:32 -0000 1.4 @@ -365,6 +365,8 @@ if (table_entries_used > 0) { nsv->index_entries = table_entries_used; + if((unsigned)table_entries >= UINT_MAX / sizeof(uint32_t)) + return -1; nsv->nsvf_index_data = av_malloc(table_entries * sizeof(uint32_t)); get_buffer(pb, nsv->nsvf_index_data, table_entries * sizeof(uint32_t)); } Index: nut.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/nut.c,v retrieving revision 1.39 retrieving revision 1.40 diff -u -d -r1.39 -r1.40 --- nut.c 13 Nov 2004 01:27:35 -0000 1.39 +++ nut.c 8 Jan 2005 14:21:32 -0000 1.40 @@ -82,7 +82,7 @@ int written_packet_size; int64_t packet_start[3]; //0-> startcode less, 1-> short startcode 2-> long startcodes FrameCode frame_code[256]; - int stream_count; + unsigned int stream_count; uint64_t next_startcode; ///< stores the next startcode if it has alraedy been parsed but the stream isnt seekable StreamContext *stream; int max_distance; @@ -255,8 +255,8 @@ return -1; } -static int get_str(ByteIOContext *bc, char *string, int maxlen){ - int len= get_v(bc); +static int get_str(ByteIOContext *bc, char *string, unsigned int maxlen){ + unsigned int len= get_v(bc); if(len && maxlen) get_buffer(bc, string, FFMIN(len, maxlen)); @@ -283,7 +283,7 @@ static uint64_t get_vb(ByteIOContext *bc){ uint64_t val=0; - int i= get_v(bc); + unsigned int i= get_v(bc); if(i>8) return UINT64_MAX; @@ -877,6 +877,10 @@ } nut->stream_count = get_v(bc); + if(nut->stream_count > MAX_STREAMS){ + av_log(s, AV_LOG_ERROR, "too many streams\n"); + return -1; + } nut->max_distance = get_v(bc); nut->max_short_distance = get_v(bc); nut->rate_num= get_v(bc); @@ -982,6 +986,8 @@ /* codec specific data headers */ while(get_v(bc) != 0){ st->codec.extradata_size= get_v(bc); + if((unsigned)st->codec.extradata_size > (1<<30)) + return -1; st->codec.extradata= av_mallocz(st->codec.extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); get_buffer(bc, st->codec.extradata, st->codec.extradata_size); // url_fskip(bc, get_v(bc)); Index: ogg.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/ogg.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- ogg.c 13 Nov 2004 01:27:35 -0000 1.20 +++ ogg.c 8 Jan 2005 14:21:33 -0000 1.21 @@ -195,6 +195,8 @@ if(next_packet(avfcontext, &op)){ return -1; } + if(op.bytes >= (1<<16) || op.bytes < 0) + return -1; codec->extradata_size+= 2 + op.bytes; codec->extradata= av_realloc(codec->extradata, codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); p= codec->extradata + codec->extradata_size - 2 - op.bytes; Index: segafilm.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/segafilm.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- segafilm.c 19 Jun 2004 03:59:34 -0000 1.5 +++ segafilm.c 8 Jan 2005 14:21:33 -0000 1.6 @@ -171,6 +171,8 @@ return AVERROR_INVALIDDATA; film->base_clock = BE_32(&scratch[8]); film->sample_count = BE_32(&scratch[12]); + if(film->sample_count >= UINT_MAX / sizeof(film_sample_t)) + return -1; film->sample_table = av_malloc(film->sample_count * sizeof(film_sample_t)); for(i=0; i<s->nb_streams; i++) Index: sgi.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/sgi.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- sgi.c 10 Apr 2004 15:09:46 -0000 1.3 +++ sgi.c 8 Jan 2005 14:21:33 -0000 1.4 @@ -65,6 +65,9 @@ info->xsize = (unsigned short) get_be16(f); info->ysize = (unsigned short) get_be16(f); info->zsize = (unsigned short) get_be16(f); + + if(info->zsize > 4096) + info->zsize= 0; #ifdef DEBUG printf("sgi header fields:\n"); Index: utils.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/utils.c,v retrieving revision 1.129 retrieving revision 1.130 diff -u -d -r1.129 -r1.130 --- utils.c 3 Jan 2005 20:33:52 -0000 1.129 +++ utils.c 8 Jan 2005 14:21:33 -0000 1.130 @@ -180,7 +180,10 @@ */ int av_new_packet(AVPacket *pkt, int size) { - void *data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); + void *data; + if((unsigned)size > (unsigned)size + FF_INPUT_BUFFER_PADDING_SIZE) + return AVERROR_NOMEM; + data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); if (!data) return AVERROR_NOMEM; memset(data + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); @@ -200,6 +203,8 @@ uint8_t *data; /* we duplicate the packet and don't forget to put the padding again */ + if((unsigned)pkt->size > (unsigned)pkt->size + FF_INPUT_BUFFER_PADDING_SIZE) + return AVERROR_NOMEM; data = av_malloc(pkt->size + FF_INPUT_BUFFER_PADDING_SIZE); if (!data) { return AVERROR_NOMEM; @@ -277,8 +282,8 @@ return 0; } -void fifo_realloc(FifoBuffer *f, int new_size){ - int old_size= f->end - f->buffer; +void fifo_realloc(FifoBuffer *f, unsigned int new_size){ + unsigned int old_size= f->end - f->buffer; if(old_size < new_size){ uint8_t *old= f->buffer; @@ -1007,10 +1012,16 @@ AVIndexEntry *entries, *ie; int index; + if((unsigned)st->nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry)) + return -1; + entries = av_fast_realloc(st->index_entries, &st->index_entries_allocated_size, (st->nb_index_entries + 1) * sizeof(AVIndexEntry)); + if(!entries) + return -1; + st->index_entries= entries; index= av_index_search_timestamp(st, timestamp, 0); Index: wc3movie.c =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/wc3movie.c,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- wc3movie.c 19 Jun 2004 03:59:34 -0000 1.8 +++ wc3movie.c 8 Jan 2005 14:21:33 -0000 1.9 @@ -169,6 +169,8 @@ if ((ret = get_buffer(pb, preamble, 4)) != 4) return AVERROR_IO; wc3->palette_count = LE_32(&preamble[0]); + if((unsigned)wc3->palette_count >= UINT_MAX / PALETTE_SIZE) + return -1; wc3->palettes = av_malloc(wc3->palette_count * PALETTE_SIZE); break; Index: avformat.h =================================================================== RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/avformat.h,v retrieving revision 1.112 retrieving revision 1.113 diff -u -d -r1.112 -r1.113 --- avformat.h 1 Dec 2004 02:28:28 -0000 1.112 +++ avformat.h 8 Jan 2005 14:21:33 -0000 1.113 @@ -546,7 +546,7 @@ int fifo_read(FifoBuffer *f, uint8_t *buf, int buf_size, uint8_t **rptr_ptr); void fifo_write(FifoBuffer *f, uint8_t *buf, int size, uint8_t **wptr_ptr); int put_fifo(ByteIOContext *pb, FifoBuffer *f, int buf_size, uint8_t **rptr_ptr); -void fifo_realloc(FifoBuffer *f, int size); +void fifo_realloc(FifoBuffer *f, unsigned int size); /* media file input */ AVInputFormat *av_find_input_format(const char *short_name);