X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmov.c;h=a2f746b6c18466c31404746fdfa50912b5021e05;hb=1607f774949add9e93bba6f288c9c5bf2c10d880;hp=54930a4052a23df44e8dedab6de47db18bb8ee3f;hpb=dc83733f2bf2f26433bbf23d42fe92a2c7691df1;p=ffmpeg diff --git a/libavformat/mov.c b/libavformat/mov.c index 54930a4052a..a2f746b6c18 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -206,32 +206,38 @@ static int mov_read_covr(MOVContext *c, AVIOContext *pb, int type, int len) static int mov_metadata_loci(MOVContext *c, AVIOContext *pb, unsigned len) { char language[4] = { 0 }; - char buf[100]; + char buf[200], place[100]; uint16_t langcode = 0; double longitude, latitude; const char *key = "location"; - if (len < 4 + 2 + 1 + 1 + 4 + 4 + 4) + if (len < 4 + 2 + 1 + 1 + 4 + 4 + 4) { + av_log(c->fc, AV_LOG_ERROR, "loci too short\n"); return AVERROR_INVALIDDATA; + } avio_skip(pb, 4); // version+flags langcode = avio_rb16(pb); ff_mov_lang_to_iso639(langcode, language); len -= 6; - len -= avio_get_str(pb, len, buf, sizeof(buf)); // place name - if (len < 1) + len -= avio_get_str(pb, len, place, sizeof(place)); + if (len < 1) { + av_log(c->fc, AV_LOG_ERROR, "place name too long\n"); return AVERROR_INVALIDDATA; + } avio_skip(pb, 1); // role len -= 1; - if (len < 14) + if (len < 12) { + av_log(c->fc, AV_LOG_ERROR, "no space for coordinates left (%d)\n", len); return AVERROR_INVALIDDATA; + } longitude = ((int32_t) avio_rb32(pb)) / (float) (1 << 16); latitude = ((int32_t) avio_rb32(pb)) / (float) (1 << 16); // Try to output in the same format as the ?xyz field - snprintf(buf, sizeof(buf), "%+08.4f%+09.4f/", latitude, longitude); + snprintf(buf, sizeof(buf), "%+08.4f%+09.4f/%s", latitude, longitude, place); if (*language && strcmp(language, "und")) { char key2[16]; snprintf(key2, sizeof(key2), "%s-%s", key, language); @@ -439,7 +445,8 @@ static int mov_read_chpl(MOVContext *c, AVIOContext *pb, MOVAtom atom) if ((atom.size -= 9+str_len) < 0) return 0; - avio_read(pb, str, str_len); + if (avio_read(pb, str, str_len) != str_len) + return AVERROR_INVALIDDATA; str[str_len] = 0; avpriv_new_chapter(c->fc, i, (AVRational){1,10000000}, start, AV_NOPTS_VALUE, str); } @@ -491,7 +498,8 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom) volume_len = avio_r8(pb); volume_len = FFMIN(volume_len, 27); - avio_read(pb, dref->volume, 27); + if (avio_read(pb, dref->volume, 27) != 27) + return AVERROR_INVALIDDATA; dref->volume[volume_len] = 0; av_log(c->fc, AV_LOG_DEBUG, "volume %s, len %d\n", dref->volume, volume_len); @@ -499,7 +507,8 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom) len = avio_r8(pb); len = FFMIN(len, 63); - avio_read(pb, dref->filename, 63); + if (avio_read(pb, dref->filename, 63) != 63) + return AVERROR_INVALIDDATA; dref->filename[len] = 0; av_log(c->fc, AV_LOG_DEBUG, "filename %s, len %d\n", dref->filename, len); @@ -526,7 +535,10 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom) dref->path = av_mallocz(len+1); if (!dref->path) return AVERROR(ENOMEM); - avio_read(pb, dref->path, len); + if (avio_read(pb, dref->path, len) != len) { + av_freep(&dref->path); + return AVERROR_INVALIDDATA; + } if (type == 18) // no additional processing needed continue; if (len > volume_len && !strncmp(dref->path, dref->volume, volume_len)) { @@ -543,8 +555,10 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom) dref->dir = av_malloc(len+1); if (!dref->dir) return AVERROR(ENOMEM); - if (avio_read(pb, dref->dir, len) != len) + if (avio_read(pb, dref->dir, len) != len) { + av_freep(&dref->dir); return AVERROR_INVALIDDATA; + } dref->dir[len] = 0; for (j = 0; j < len; j++) if (dref->dir[j] == ':') @@ -600,7 +614,10 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom) title_str = av_malloc(title_size + 1); /* Add null terminator */ if (!title_str) return AVERROR(ENOMEM); - avio_read(pb, title_str, title_size); + if (avio_read(pb, title_str, title_size) != title_size) { + av_freep(&title_str); + return AVERROR_INVALIDDATA; + } title_str[title_size] = 0; if (title_str[0]) { int off = (!c->isom && title_str[0] == title_size - 1); @@ -781,7 +798,8 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom) char* comp_brands_str; uint8_t type[5] = {0}; - avio_read(pb, type, 4); + if (avio_read(pb, type, 4) != 4) + return AVERROR_INVALIDDATA; if (strcmp(type, "qt ")) c->isom = 1; av_log(c->fc, AV_LOG_DEBUG, "ISO: File Type Major Brand: %.4s\n",(char *)&type); @@ -795,7 +813,10 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom) comp_brands_str = av_malloc(comp_brand_size + 1); /* Add null terminator */ if (!comp_brands_str) return AVERROR(ENOMEM); - avio_read(pb, comp_brands_str, comp_brand_size); + if (avio_read(pb, comp_brands_str, comp_brand_size) != comp_brand_size) { + av_freep(&comp_brands_str); + return AVERROR_INVALIDDATA; + } comp_brands_str[comp_brand_size] = 0; av_dict_set(&c->fc->metadata, "compatible_brands", comp_brands_str, 0); av_freep(&comp_brands_str); @@ -988,7 +1009,8 @@ static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; st = c->fc->streams[c->fc->nb_streams - 1]; - avio_read(pb, color_parameter_type, 4); + if (avio_read(pb, color_parameter_type, 4) != 4) + return AVERROR_INVALIDDATA; if (strncmp(color_parameter_type, "nclx", 4) && strncmp(color_parameter_type, "nclc", 4)) { av_log(c->fc, AV_LOG_WARNING, "unsupported color_parameter_type %s\n", @@ -1689,9 +1711,9 @@ static uint32_t yuv_to_rgba(uint32_t ycbcr) cr = (ycbcr >> 8) & 0xFF; cb = ycbcr & 0xFF; - b = av_clip_uint8(1.164 * (y - 16) + 2.018 * (cb - 128)); - g = av_clip_uint8(1.164 * (y - 16) - 0.813 * (cr - 128) - 0.391 * (cb - 128)); - r = av_clip_uint8(1.164 * (y - 16) + 1.596 * (cr - 128)); + b = av_clip_uint8((1164 * (y - 16) + 2018 * (cb - 128)) / 1000); + g = av_clip_uint8((1164 * (y - 16) - 813 * (cr - 128) - 391 * (cb - 128)) / 1000); + r = av_clip_uint8((1164 * (y - 16) + 1596 * (cr - 128) ) / 1000); return (r << 16) | (g << 8) | b; } @@ -2169,10 +2191,11 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->sample_count = i; + av_free(buf); + if (pb->eof_reached) return AVERROR_EOF; - av_free(buf); return 0; } @@ -2211,12 +2234,6 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sample_count=avio_rb32(pb); sample_duration = avio_rb32(pb); - /* sample_duration < 0 is invalid based on the spec */ - if (sample_duration < 0) { - av_log(c->fc, AV_LOG_ERROR, "Invalid SampleDelta %d in STTS, at %d st:%d\n", - sample_duration, i, c->fc->nb_streams-1); - sample_duration = 1; - } if (sample_count < 0) { av_log(c->fc, AV_LOG_ERROR, "Invalid sample_count=%d\n", sample_count); return AVERROR_INVALIDDATA; @@ -2280,6 +2297,7 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; if (entries >= UINT_MAX / sizeof(*sc->ctts_data)) return AVERROR_INVALIDDATA; + av_freep(&sc->ctts_data); sc->ctts_data = av_malloc(entries * sizeof(*sc->ctts_data)); if (!sc->ctts_data) return AVERROR(ENOMEM); @@ -2415,10 +2433,13 @@ static void mov_build_index(MOVContext *mov, AVStream *st) unsigned int distance = 0; unsigned int rap_group_index = 0; unsigned int rap_group_sample = 0; + int64_t last_dts = 0; + int64_t dts_correction = 0; int rap_group_present = sc->rap_group_count && sc->rap_group; int key_off = (sc->keyframe_count && sc->keyframes[0] > 0) || (sc->stps_count && sc->stps_data[0] > 0); current_dts -= sc->dts_shift; + last_dts = current_dts; if (!sc->sample_count || st->nb_index_entries) return; @@ -2498,7 +2519,27 @@ static void mov_build_index(MOVContext *mov, AVStream *st) current_offset += sample_size; stream_size += sample_size; + + /* A negative sample duration is invalid based on the spec, + * but some samples need it to correct the DTS. */ + if (sc->stts_data[stts_index].duration < 0) { + av_log(mov->fc, AV_LOG_WARNING, + "Invalid SampleDelta %d in STTS, at %d st:%d\n", + sc->stts_data[stts_index].duration, stts_index, + st->index); + dts_correction += sc->stts_data[stts_index].duration - 1; + sc->stts_data[stts_index].duration = 1; + } current_dts += sc->stts_data[stts_index].duration; + if (!dts_correction || current_dts + dts_correction > last_dts) { + current_dts += dts_correction; + dts_correction = 0; + } else { + /* Avoid creating non-monotonous DTS */ + dts_correction += current_dts - last_dts - 1; + current_dts = last_dts + 1; + } + last_dts = current_dts; distance++; stts_sample++; current_sample++; @@ -2563,6 +2604,13 @@ static void mov_build_index(MOVContext *mov, AVStream *st) AVIndexEntry *e; unsigned size, samples; + if (sc->samples_per_frame > 1 && !sc->bytes_per_frame) { + avpriv_request_sample(mov->fc, + "Zero bytes per frame, but %d samples per frame", + sc->samples_per_frame); + return; + } + if (sc->samples_per_frame >= 160) { // gsm samples = sc->samples_per_frame; size = sc->bytes_per_frame; @@ -2599,9 +2647,14 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } } -static int mov_open_dref(AVIOContext **pb, const char *src, MOVDref *ref, - AVIOInterruptCB *int_cb, int use_absolute_path, AVFormatContext *fc) +static int mov_open_dref(MOVContext *c, AVIOContext **pb, const char *src, MOVDref *ref, + AVIOInterruptCB *int_cb) { + AVOpenCallback open_func = c->fc->open_cb; + + if (!open_func) + open_func = ffio_open2_wrapper; + /* try relative path, we do not try the absolute because it can leak information about our system to an attacker */ if (ref->nlvl_to > 0 && ref->nlvl_from > 0 && ref->path[0] != '/') { @@ -2634,20 +2687,28 @@ static int mov_open_dref(AVIOContext **pb, const char *src, MOVDref *ref, av_strlcat(filename, "../", sizeof(filename)); av_strlcat(filename, ref->path + l + 1, sizeof(filename)); - if (!use_absolute_path) + if (!c->use_absolute_path && !c->fc->open_cb) if(strstr(ref->path + l + 1, "..") || ref->nlvl_from > 1) return AVERROR(ENOENT); if (strlen(filename) + 1 == sizeof(filename)) return AVERROR(ENOENT); - if (!avio_open2(pb, filename, AVIO_FLAG_READ, int_cb, NULL)) + if (!open_func(c->fc, pb, filename, AVIO_FLAG_READ, int_cb, NULL)) return 0; } - } else if (use_absolute_path) { - av_log(fc, AV_LOG_WARNING, "Using absolute path on user request, " + } else if (c->use_absolute_path) { + av_log(c->fc, AV_LOG_WARNING, "Using absolute path on user request, " "this is a possible security issue\n"); - if (!avio_open2(pb, ref->path, AVIO_FLAG_READ, int_cb, NULL)) + if (!open_func(c->fc, pb, ref->path, AVIO_FLAG_READ, int_cb, NULL)) return 0; + } else if (c->fc->open_cb) { + if (!open_func(c->fc, pb, ref->path, AVIO_FLAG_READ, int_cb, NULL)) + return 0; + } else { + av_log(c->fc, AV_LOG_ERROR, + "Absolute path %s not tried for security reasons, " + "set demuxer option use_absolute_path to allow absolute paths\n", + ref->path); } return AVERROR(ENOENT); @@ -2698,8 +2759,8 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) { MOVDref *dref = &sc->drefs[sc->dref_id - 1]; - if (mov_open_dref(&sc->pb, c->fc->filename, dref, &c->fc->interrupt_callback, - c->use_absolute_path, c->fc) < 0) + if (mov_open_dref(c, &sc->pb, c->fc->filename, dref, + &c->fc->interrupt_callback) < 0) av_log(c->fc, AV_LOG_ERROR, "stream %d, error opening alias: path='%s', dir='%s', " "filename='%s', volume='%s', nlvl_from=%d, nlvl_to=%d\n", @@ -2810,7 +2871,10 @@ static int mov_read_custom_2plus(MOVContext *c, AVIOContext *pb, int size) *p = av_malloc(len + 1); if (!*p) break; - avio_read(pb, *p, len); + if (avio_read(pb, *p, len) != len) { + av_freep(p); + return AVERROR_INVALIDDATA; + } (*p)[len] = 0; } @@ -3295,11 +3359,16 @@ static int mov_read_cmov(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_free(cmov_data); return AVERROR(ENOMEM); } - avio_read(pb, cmov_data, cmov_len); + if (avio_read(pb, cmov_data, cmov_len) != cmov_len) { + av_freep(&cmov_data); + av_freep(&moov_data); + return AVERROR_INVALIDDATA; + } if (uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK) goto free_and_return; if (ffio_init_context(&ctx, moov_data, moov_len, 0, NULL, NULL, NULL, NULL) != 0) goto free_and_return; + ctx.seekable = AVIO_SEEKABLE_NORMAL; atom.type = MKTAG('m','o','o','v'); atom.size = moov_len; ret = mov_read_default(c, &ctx, atom); @@ -3556,7 +3625,8 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) c->moov_retry) { uint8_t buf[8]; uint32_t *type = (uint32_t *)buf + 1; - avio_read(pb, buf, 8); + if (avio_read(pb, buf, 8) != 8) + return AVERROR_INVALIDDATA; avio_seek(pb, -8, SEEK_CUR); if (*type == MKTAG('m','v','h','d') || *type == MKTAG('c','m','o','v')) { @@ -4221,7 +4291,10 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) mov->found_mdat = 0; if (!mov->next_root_atom) return AVERROR_EOF; - avio_seek(s->pb, mov->next_root_atom, SEEK_SET); + if (avio_seek(s->pb, mov->next_root_atom, SEEK_SET) != mov->next_root_atom) { + av_log(mov->fc, AV_LOG_ERROR, "next root atom offset 0x%"PRIx64": partial file\n", mov->next_root_atom); + return AVERROR_INVALIDDATA; + } mov->next_root_atom = 0; if (mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 || avio_feof(s->pb))