[2/5] flvdec: Check the parsed index for validity

Message ID 1329903034-45259-2-git-send-email-martin@martin.st
State Superseded
Headers show

Commit Message

Martin Storsjö Feb. 22, 2012, 9:30 a.m.
From: Michael Niedermayer <michaelni@gmx.at>

This avoids adding index entries for files where the index
is defined in an incompatible way, or where it simply is broken.

This requires doing a short seek to the second index entry to
validate the index, and thus we need to seek back at the end
of the parsing function, even if we were able to parse the whole
index successfully.
---
 libavformat/flvdec.c |   32 +++++++++++++++++++++++++-------
 1 files changed, 25 insertions(+), 7 deletions(-)

Comments

Luca Barbato Feb. 22, 2012, 10:26 a.m. | #1
On 22/02/12 10:30, Martin Storsjö wrote:
> FFABS(dts - times[1]*1000) > 5000

Why that?

lu

Patch

diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index de6168c..c652baa 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -203,20 +203,38 @@  static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, AVStream
         }
     }
 
-    if (!ret && timeslen == fileposlen)
+    if (!ret && timeslen == fileposlen && fileposlen > 1 &&
+        max_pos <= filepositions[0]) {
+        int64_t dts, size0, size1;
+        /* Seek back to the end of the index (instead to before it)
+         * afterwards, since we parsed it successfully. */
+        initial_pos = avio_tell(ioc);
+        avio_seek(ioc, filepositions[1] - 4, SEEK_SET);
+        size0 = avio_rb32(ioc);
+                avio_r8(ioc);
+        size1 = avio_rb24(ioc);
+        dts   = avio_rb24(ioc);
+        dts  |= avio_r8(ioc) << 24;
+        /* A quick index sanity check: size0, the size of the packet
+         * preceding the second index entry, should be less than the
+         * file position. The timestamp of the packet should be
+         * within 5 seconds from what the index claimed it to be.
+         * Anything else indicates an incorrectly interpreted or simply
+         * broken index.
+         */
+        if (size0 > filepositions[1] || FFABS(dts - times[1]*1000) > 5000)
+            goto finish;
         for (i = 0; i < fileposlen; i++)
             av_add_index_entry(vstream, filepositions[i], times[i]*1000, 0, 0, AVINDEX_KEYFRAME);
-    else
+    } else
         av_log(s, AV_LOG_WARNING, "Invalid keyframes object, skipping.\n");
 
 finish:
     av_freep(&times);
     av_freep(&filepositions);
-    // If we got unexpected data, but successfully reset back to
-    // the start pos, the caller can continue parsing
-    if (ret < 0 && avio_seek(ioc, initial_pos, SEEK_SET) > 0)
-        return 0;
-    return ret;
+    if (avio_seek(ioc, initial_pos, SEEK_SET) != initial_pos)
+        return ret ? ret : AVERROR(EIO);
+    return 0;
 }
 
 static int amf_parse_object(AVFormatContext *s, AVStream *astream, AVStream *vstream, const char *key, int64_t max_pos, int depth) {