ff_id3v2_read: add option to limit ID3 magic number search
authorPeter Ross <pross@xvid.org>
Fri, 18 Apr 2014 04:49:40 +0000 (14:49 +1000)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 19 Apr 2014 02:25:01 +0000 (04:25 +0200)
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 <pross@xvid.org>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
libavformat/aiffdec.c
libavformat/asfdec.c
libavformat/dsfdec.c
libavformat/id3v2.c
libavformat/id3v2.h
libavformat/omadec.c
libavformat/utils.c

index c362071..81bcc64 100644 (file)
@@ -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);
index 0e7e910..a7d8609 100644 (file)
@@ -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);
index fee551d..ae198b2 100644 (file)
@@ -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);
index 15b58d7..4cf8e9b 100644 (file)
@@ -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)
index eb4dc79..9d7bf1c 100644 (file)
@@ -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.
index 44829ec..9f3d3aa 100644 (file)
@@ -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;
index ac82dc6..e1dfe02 100644 (file)
@@ -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)