[vlc-devel] [PATCH] Handle with resilience unknown ebml elements

Denis Charmet typx at dinauz.org
Wed Dec 26 19:04:51 CET 2012


Fix #7884 and #7887 by implementing the first proposition.
---
 modules/demux/mkv/Ebml_parser.cpp |   76 +++++++++++++++++++++++++++++++------
 modules/demux/mkv/Ebml_parser.hpp |   11 +++---
 2 files changed, 71 insertions(+), 16 deletions(-)

diff --git a/modules/demux/mkv/Ebml_parser.cpp b/modules/demux/mkv/Ebml_parser.cpp
index d7490b8..c4e22c5 100644
--- a/modules/demux/mkv/Ebml_parser.cpp
+++ b/modules/demux/mkv/Ebml_parser.cpp
@@ -30,6 +30,7 @@
  * Ebml Stream parser
  *****************************************************************************/
 EbmlParser::EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux ) :
+    p_demux( p_demux ),
     m_es( es ),
     mi_level( 1 ),
     m_got( NULL ),
@@ -103,7 +104,7 @@ void EbmlParser::Up( void )
 {
     if( mi_user_level == mi_level )
     {
-        fprintf( stderr,"MKV/Ebml Parser: Up cannot escape itself\n" );
+        msg_Warn( p_demux, "MKV/Ebml Parser: Up cannot escape itself" );
     }
 
     mi_user_level--;
@@ -133,15 +134,17 @@ void EbmlParser::Reset( demux_t *p_demux )
         m_el[mi_level] = NULL;
         mi_level--;
     }
+    this->p_demux = p_demux;
     mi_user_level = mi_level = 1;
     // a little faster and cleaner
     m_es->I_O().setFilePointer( static_cast<KaxSegment*>(m_el[0])->GetGlobalPosition(0) );
     mb_dummy = var_InheritBool( p_demux, "mkv-use-dummy" );
 }
 
-EbmlElement *EbmlParser::Get( void )
+EbmlElement *EbmlParser::Get( int n_call )
 {
     int i_ulev = 0;
+    EbmlElement *p_prev = NULL;
 
     if( mi_user_level != mi_level )
     {
@@ -155,24 +158,29 @@ EbmlElement *EbmlParser::Get( void )
         return ret;
     }
 
+    p_prev = m_el[mi_level];
     if( m_el[mi_level] )
     {
         m_el[mi_level]->SkipData( *m_es, EBML_CONTEXT(m_el[mi_level]) );
-        if( !mb_keep )
-        {
-            if( MKV_IS_ID( m_el[mi_level], KaxBlockVirtual ) )
-                static_cast<KaxBlockVirtualWorkaround*>(m_el[mi_level])->Fix();
-            delete m_el[mi_level];
-        }
-        mb_keep = false;
+
     }
     vlc_stream_io_callback & io_stream = (vlc_stream_io_callback &) m_es->I_O();
     uint64 i_size = io_stream.toRead();
     m_el[mi_level] = m_es->FindNextElement( EBML_CONTEXT(m_el[mi_level - 1]),
-                                            i_ulev, i_size, mb_dummy, 1 );
+                                            i_ulev, i_size, true, 1 );
 //    mi_remain_size[mi_level] = m_el[mi_level]->GetSize();
     if( i_ulev > 0 )
     {
+        if( p_prev )
+        {
+            if( !mb_keep )
+            {
+                if( MKV_IS_ID( p_prev, KaxBlockVirtual ) )
+                    static_cast<KaxBlockVirtualWorkaround*>(p_prev)->Fix();
+                delete p_prev;
+            }
+            mb_keep = false;
+        }
         while( i_ulev > 0 )
         {
             if( mi_level == 1 )
@@ -192,9 +200,55 @@ EbmlElement *EbmlParser::Get( void )
     }
     else if( m_el[mi_level] == NULL )
     {
-        fprintf( stderr,"MKV/Ebml Parser: m_el[mi_level] == NULL\n" );
+        msg_Warn( p_demux,"MKV/Ebml Parser: m_el[mi_level] == NULL\n" );
+    }
+    else if( m_el[mi_level]->IsDummy() && !mb_dummy )
+    {
+        bool b_bad_position = false;
+        /* We got a dummy element but don't want those... 
+         * perform a sanity check */
+        if( !mi_level )
+        {
+            msg_Err(p_demux, "Got invalid lvl 0 element... Aborting");
+            return NULL;
+        }
+
+        if( p_prev && p_prev->IsFiniteSize() &&
+            p_prev->GetEndPosition() != m_el[mi_level]->GetElementPosition())
+        {
+            msg_Err( p_demux, "Dummy Element at unexpected position... corrupted file?" );
+            b_bad_position = true;
+        }
+
+        if( n_call < 10 && !b_bad_position && m_el[mi_level]->IsFiniteSize() &&
+            ( !m_el[mi_level-1]->IsFiniteSize() ||
+              m_el[mi_level]->GetEndPosition() <= m_el[mi_level-1]->GetEndPosition() ) )
+        {
+            /* The element fits inside its upper element */
+            msg_Warn( p_demux, "Dummy element found... skipping it" );
+            return Get( ++n_call );
+        }
+        else
+        {
+            /* Too large, misplaced or 10 successive dummy elements */
+            msg_Err( p_demux, "Dummy element too large or misplaced... skipping to next upper element" );
+            delete m_el[mi_level];
+            m_el[mi_level] = NULL;
+            m_el[mi_level - 1]->SkipData( *m_es, EBML_CONTEXT(m_el[mi_level - 1]) );
+            return Get();
+        }
     }
 
+    if( p_prev )
+    {
+        if( !mb_keep )
+        {
+            if( MKV_IS_ID( p_prev, KaxBlockVirtual ) )
+                static_cast<KaxBlockVirtualWorkaround*>(p_prev)->Fix();
+            delete p_prev;
+        }
+        mb_keep = false;
+    }
     return m_el[mi_level];
 }
 
diff --git a/modules/demux/mkv/Ebml_parser.hpp b/modules/demux/mkv/Ebml_parser.hpp
index 86a856e..40abafd 100644
--- a/modules/demux/mkv/Ebml_parser.hpp
+++ b/modules/demux/mkv/Ebml_parser.hpp
@@ -39,7 +39,7 @@ class EbmlParser
     void Up( void );
     void Down( void );
     void Reset( demux_t *p_demux );
-    EbmlElement *Get( void );
+    EbmlElement *Get( int n_call = 0 );
     void        Keep( void );
     EbmlElement *UnGet( uint64 i_block_pos, uint64 i_cluster_pos );
 
@@ -49,16 +49,17 @@ class EbmlParser
     bool IsTopPresent( EbmlElement * ) const;
 
   private:
+    demux_t     *p_demux;
     EbmlStream  *m_es;
-    int         mi_level;
+    int          mi_level;
     EbmlElement *m_el[10];
     int64_t      mi_remain_size[10];
 
     EbmlElement *m_got;
 
-    int         mi_user_level;
-    bool        mb_keep;
-    bool        mb_dummy;
+    int          mi_user_level;
+    bool         mb_keep;
+    bool         mb_dummy;
 };
 
 /* This class works around a bug in KaxBlockVirtual implementation */
-- 
1.7.10.4




More information about the vlc-devel mailing list