• Petr Pavlu's avatar
    tracing: Fix a possible race when disabling buffered events · c0591b1c
    Petr Pavlu authored
    Function trace_buffered_event_disable() is responsible for freeing pages
    backing buffered events and this process can run concurrently with
    trace_event_buffer_lock_reserve().
    
    The following race is currently possible:
    
    * Function trace_buffered_event_disable() is called on CPU 0. It
      increments trace_buffered_event_cnt on each CPU and waits via
      synchronize_rcu() for each user of trace_buffered_event to complete.
    
    * After synchronize_rcu() is finished, function
      trace_buffered_event_disable() has the exclusive access to
      trace_buffered_event. All counters trace_buffered_event_cnt are at 1
      and all pointers trace_buffered_event are still valid.
    
    * At this point, on a different CPU 1, the execution reaches
      trace_event_buffer_lock_reserve(). The function calls
      preempt_disable_notrace() and only now enters an RCU read-side
      critical section. The function proceeds and reads a still valid
      pointer from trace_buffered_event[CPU1] into the local variable
      "entry". However, it doesn't yet read trace_buffered_event_cnt[CPU1]
      which happens later.
    
    * Function trace_buffered_event_disable() continues. It frees
      trace_buffered_event[CPU1] and decrements
      trace_buffered_event_cnt[CPU1] back to 0.
    
    * Function trace_event_buffer_lock_reserve() continues. It reads and
      increments trace_buffered_event_cnt[CPU1] from 0 to 1. This makes it
      believe that it can use the "entry" that it already obtained but the
      pointer is now invalid and any access results in a use-after-free.
    
    Fix the problem by making a second synchronize_rcu() call after all
    trace_buffered_event values are set to NULL. This waits on all potential
    users in trace_event_buffer_lock_reserve() that still read a previous
    pointer from trace_buffered_event.
    
    Link: https://lore.kernel.org/all/20231127151248.7232-2-petr.pavlu@suse.com/
    Link: https://lkml.kernel.org/r/20231205161736.19663-4-petr.pavlu@suse.com
    
    Cc: stable@vger.kernel.org
    Fixes: 0fc1b09f ("tracing: Use temp buffer when filtering events")
    Signed-off-by: default avatarPetr Pavlu <petr.pavlu@suse.com>
    Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
    c0591b1c
trace.c 258 KB