[vlc-devel] [PATCHv2 08/10] es_out: add priv controls to set/unset vlc_es_id_t

Thomas Guillem thomas at gllm.fr
Thu Feb 27 16:19:15 CET 2020


It's now illegal to control a es_out_id_t directly from input.c.

A refcounted vlc_es_id_t should be used instead. It fixes a potential (but
not enabled) use-after-free if a es_out_id_t was passed to the timeshift
thread.
---
 src/input/es_out.c           | 16 ++++++++++++++++
 src/input/es_out.h           | 17 +++++++++++++++++
 src/input/es_out_timeshift.c |  3 +++
 src/input/input.c            | 10 +++-------
 4 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/src/input/es_out.c b/src/input/es_out.c
index 342b665c63e..ac9dae2f171 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -3278,6 +3278,22 @@ static int EsOutVaPrivControlLocked( es_out_t *out, int query, va_list args )
             EsOutTerminate( out );
         return VLC_SUCCESS;
     }
+    case ES_OUT_PRIV_SET_ES:
+    case ES_OUT_PRIV_UNSET_ES:
+    case ES_OUT_PRIV_RESTART_ES:
+    {
+        vlc_es_id_t *es_id = va_arg( args, vlc_es_id_t * );
+        es_out_id_t *es = vlc_es_id_get_out( es_id );
+        int new_query;
+        switch( query )
+        {
+            case ES_OUT_PRIV_SET_ES: new_query = ES_OUT_SET_ES; break;
+            case ES_OUT_PRIV_UNSET_ES: new_query = ES_OUT_UNSET_ES; break;
+            case ES_OUT_PRIV_RESTART_ES: new_query = ES_OUT_RESTART_ES; break;
+            default: vlc_assert_unreachable();
+        }
+        return EsOutControlLocked( out, new_query, es );
+    }
     case ES_OUT_PRIV_GET_WAKE_UP:
     {
         vlc_tick_t *pi_wakeup = va_arg( args, vlc_tick_t* );
diff --git a/src/input/es_out.h b/src/input/es_out.h
index 92f646602ef..d3fab22fb72 100644
--- a/src/input/es_out.h
+++ b/src/input/es_out.h
@@ -40,6 +40,11 @@ enum es_out_query_private_e
     /* set/get mode */
     ES_OUT_PRIV_SET_MODE,                           /* arg1= int */
 
+    /* Same than ES_OUT_SET_ES/ES_OUT_UNSET_ES/ES_OUT_RESTART_ES, but with vlc_es_id_t * */
+    ES_OUT_PRIV_SET_ES,      /* arg1= vlc_es_id_t*                   */
+    ES_OUT_PRIV_UNSET_ES,    /* arg1= vlc_es_id_t* res=can fail      */
+    ES_OUT_PRIV_RESTART_ES,  /* arg1= vlc_es_id_t*                   */
+
     /* Get date to wait before demuxing more data */
     ES_OUT_PRIV_GET_WAKE_UP,                        /* arg1=vlc_tick_t*            res=cannot fail */
 
@@ -121,6 +126,18 @@ static inline void es_out_SetMode( es_out_t *p_out, int i_mode )
     int i_ret = es_out_PrivControl( p_out, ES_OUT_PRIV_SET_MODE, i_mode );
     assert( !i_ret );
 }
+static inline int es_out_SetEs( es_out_t *p_out, vlc_es_id_t *id )
+{
+    return es_out_PrivControl( p_out, ES_OUT_PRIV_SET_ES, id );
+}
+static inline int es_out_UnsetEs( es_out_t *p_out, vlc_es_id_t *id )
+{
+    return es_out_PrivControl( p_out, ES_OUT_PRIV_UNSET_ES, id );
+}
+static inline int es_out_RestartEs( es_out_t *p_out, vlc_es_id_t *id )
+{
+    return es_out_PrivControl( p_out, ES_OUT_PRIV_RESTART_ES, id );
+}
 static inline vlc_tick_t es_out_GetWakeup( es_out_t *p_out )
 {
     vlc_tick_t i_wu;
diff --git a/src/input/es_out_timeshift.c b/src/input/es_out_timeshift.c
index c78b35160e4..f51305e1396 100644
--- a/src/input/es_out_timeshift.c
+++ b/src/input/es_out_timeshift.c
@@ -789,6 +789,9 @@ static int PrivControlLocked( es_out_t *p_out, int i_query, va_list args )
     case ES_OUT_PRIV_GET_GROUP_FORCED:
         return es_out_vaPrivControl( p_sys->p_out, i_query, args );
     /* Invalid queries for this es_out level */
+    case ES_OUT_PRIV_SET_ES:
+    case ES_OUT_PRIV_UNSET_ES:
+    case ES_OUT_PRIV_RESTART_ES:
     case ES_OUT_PRIV_SET_ES_LIST:
     case ES_OUT_PRIV_SET_ES_BY_ID:
     case ES_OUT_PRIV_RESTART_ES_BY_ID:
diff --git a/src/input/input.c b/src/input/input.c
index 94458a68cef..0834bbd8385 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -2006,9 +2006,7 @@ static bool Control( input_thread_t *p_input,
             break;
 
         case INPUT_CONTROL_SET_ES:
-            if( es_out_Control( input_priv(p_input)->p_es_out_display,
-                                ES_OUT_SET_ES, vlc_es_id_get_out( param.id ) )
-                                == VLC_SUCCESS )
+            if( es_out_SetEs( priv->p_es_out_display, param.id ) == VLC_SUCCESS )
                 demux_Control( input_priv(p_input)->master->p_demux, DEMUX_SET_ES,
                                vlc_es_id_GetInputId( param.id ) );
             break;
@@ -2041,12 +2039,10 @@ static bool Control( input_thread_t *p_input,
             break;
         }
         case INPUT_CONTROL_UNSET_ES:
-            es_out_Control( input_priv(p_input)->p_es_out_display,
-                            ES_OUT_UNSET_ES, vlc_es_id_get_out(param.id) );
+            es_out_UnsetEs( priv->p_es_out_display, param.id );
             break;
         case INPUT_CONTROL_RESTART_ES:
-            es_out_Control( input_priv(p_input)->p_es_out_display,
-                            ES_OUT_RESTART_ES, vlc_es_id_get_out( param.id ) );
+            es_out_RestartEs( priv->p_es_out_display, param.id );
             break;
 
         case INPUT_CONTROL_SET_VIEWPOINT:
-- 
2.20.1



More information about the vlc-devel mailing list