From 5331773cc33ba26b9e26ace643d926219e46a17b Mon Sep 17 00:00:00 2001 From: Peter Ross Date: Fri, 18 Apr 2014 14:49:40 +1000 Subject: [PATCH] ff_id3v2_read: add option to limit ID3 magic number search Several chunked formats (AIFF, IFF,DSF) store ID3 metadata within an 'ID3 ' chunk tag. If such chunks are stored sequentially, it is possible for the ID3v2 parser to confuse the chunk tag for the ID3 magic number. e.g. [1st chunk tag ('ID3 ') | chunk size] [ID3 magic number | metadata ...] [2nd chunk tag ('ID3 ') | chunk size] [ID3 magic number | metadata ...] Fixes ticket #3530. Signed-off-by: Peter Ross Signed-off-by: Michael Niedermayer --- libavformat/aiffdec.c | 2 +- libavformat/asfdec.c | 2 +- libavformat/dsfdec.c | 2 +- libavformat/id3v2.c | 19 ++++++++++++++----- libavformat/id3v2.h | 4 +++- libavformat/omadec.c | 2 +- libavformat/utils.c | 2 +- 7 files changed, 22 insertions(+), 11 deletions(-) diff --git a/libavformat/aiffdec.c b/libavformat/aiffdec.c index c3620716eb..81bcc64a0c 100644 --- a/libavformat/aiffdec.c +++ b/libavformat/aiffdec.c @@ -237,7 +237,7 @@ static int aiff_read_header(AVFormatContext *s) break; case MKTAG('I', 'D', '3', ' '): position = avio_tell(pb); - ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); + ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size); if (id3v2_extra_meta) if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) { ff_id3v2_free_extra_meta(&id3v2_extra_meta); diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c index 0e7e910cd8..a7d860927b 100644 --- a/libavformat/asfdec.c +++ b/libavformat/asfdec.c @@ -268,7 +268,7 @@ static void get_id3_tag(AVFormatContext *s, int len) { ID3v2ExtraMeta *id3v2_extra_meta = NULL; - ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); + ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, len); if (id3v2_extra_meta) ff_id3v2_parse_apic(s, &id3v2_extra_meta); ff_id3v2_free_extra_meta(&id3v2_extra_meta); diff --git a/libavformat/dsfdec.c b/libavformat/dsfdec.c index fee551df35..ae198b2e93 100644 --- a/libavformat/dsfdec.c +++ b/libavformat/dsfdec.c @@ -52,7 +52,7 @@ static void read_id3(AVFormatContext *s, uint64_t id3pos) if (avio_seek(s->pb, id3pos, SEEK_SET) < 0) return; - ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); + ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, 0); if (id3v2_extra_meta) ff_id3v2_parse_apic(s, &id3v2_extra_meta); ff_id3v2_free_extra_meta(&id3v2_extra_meta); diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index 15b58d7cf2..4cf8e9bcea 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -880,16 +880,25 @@ error: static void id3v2_read_internal(AVIOContext *pb, AVDictionary **metadata, AVFormatContext *s, const char *magic, - ID3v2ExtraMeta **extra_meta) + ID3v2ExtraMeta **extra_meta, int64_t max_search_size) { int len, ret; uint8_t buf[ID3v2_HEADER_SIZE]; int found_header; - int64_t off; + int64_t start, off; + if (max_search_size && max_search_size < ID3v2_HEADER_SIZE) + return; + + start = avio_tell(pb); do { /* save the current offset in case there's nothing to read/skip */ off = avio_tell(pb); + if (max_search_size && off - start >= max_search_size - ID3v2_HEADER_SIZE) { + avio_seek(pb, off, SEEK_SET); + break; + } + ret = avio_read(pb, buf, ID3v2_HEADER_SIZE); if (ret != ID3v2_HEADER_SIZE) { avio_seek(pb, off, SEEK_SET); @@ -916,13 +925,13 @@ static void id3v2_read_internal(AVIOContext *pb, AVDictionary **metadata, void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata, const char *magic, ID3v2ExtraMeta **extra_meta) { - id3v2_read_internal(pb, metadata, NULL, magic, extra_meta); + id3v2_read_internal(pb, metadata, NULL, magic, extra_meta, 0); } void ff_id3v2_read(AVFormatContext *s, const char *magic, - ID3v2ExtraMeta **extra_meta) + ID3v2ExtraMeta **extra_meta, unsigned int max_search_size) { - id3v2_read_internal(s->pb, &s->metadata, s, magic, extra_meta); + id3v2_read_internal(s->pb, &s->metadata, s, magic, extra_meta, max_search_size); } void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta) diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h index eb4dc799e6..9d7bf1c03c 100644 --- a/libavformat/id3v2.h +++ b/libavformat/id3v2.h @@ -112,8 +112,10 @@ void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata, const char *ma * * @param extra_meta If not NULL, extra metadata is parsed into a list of * ID3v2ExtraMeta structs and *extra_meta points to the head of the list + * @param[opt] max_search_search restrict ID3 magic number search (bytes from start) */ -void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta); +void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta, + unsigned int max_search_size); /** * Initialize an ID3v2 tag. diff --git a/libavformat/omadec.c b/libavformat/omadec.c index 44829ec9e5..9f3d3aa860 100644 --- a/libavformat/omadec.c +++ b/libavformat/omadec.c @@ -295,7 +295,7 @@ static int oma_read_header(AVFormatContext *s) ID3v2ExtraMeta *extra_meta = NULL; OMAContext *oc = s->priv_data; - ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta); + ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta, 0); ret = avio_read(s->pb, buf, EA3_HEADER_SIZE); if (ret < EA3_HEADER_SIZE) return -1; diff --git a/libavformat/utils.c b/libavformat/utils.c index ac82dc63a1..e1dfe02b6c 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -574,7 +574,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */ if (s->pb) - ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); + ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, 0); if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header) if ((ret = s->iformat->read_header(s)) < 0)