• Steven Rostedt (Google)'s avatar
    ring-buffer: Fix writing to the buffer with max_data_size · b3ae7b67
    Steven Rostedt (Google) authored
    The maximum ring buffer data size is the maximum size of data that can be
    recorded on the ring buffer. Events must be smaller than the sub buffer
    data size minus any meta data. This size is checked before trying to
    allocate from the ring buffer because the allocation assumes that the size
    will fit on the sub buffer.
    
    The maximum size was calculated as the size of a sub buffer page (which is
    currently PAGE_SIZE minus the sub buffer header) minus the size of the
    meta data of an individual event. But it missed the possible adding of a
    time stamp for events that are added long enough apart that the event meta
    data can't hold the time delta.
    
    When an event is added that is greater than the current BUF_MAX_DATA_SIZE
    minus the size of a time stamp, but still less than or equal to
    BUF_MAX_DATA_SIZE, the ring buffer would go into an infinite loop, looking
    for a page that can hold the event. Luckily, there's a check for this loop
    and after 1000 iterations and a warning is emitted and the ring buffer is
    disabled. But this should never happen.
    
    This can happen when a large event is added first, or after a long period
    where an absolute timestamp is prefixed to the event, increasing its size
    by 8 bytes. This passes the check and then goes into the algorithm that
    causes the infinite loop.
    
    For events that are the first event on the sub-buffer, it does not need to
    add a timestamp, because the sub-buffer itself contains an absolute
    timestamp, and adding one is redundant.
    
    The fix is to check if the event is to be the first event on the
    sub-buffer, and if it is, then do not add a timestamp.
    
    This also fixes 32 bit adding a timestamp when a read of before_stamp or
    write_stamp is interrupted. There's still no need to add that timestamp if
    the event is going to be the first event on the sub buffer.
    
    Also, if the buffer has "time_stamp_abs" set, then also check if the
    length plus the timestamp is greater than the BUF_MAX_DATA_SIZE.
    
    Link: https://lore.kernel.org/all/20231212104549.58863438@gandalf.local.home/
    Link: https://lore.kernel.org/linux-trace-kernel/20231212071837.5fdd6c13@gandalf.local.home
    Link: https://lore.kernel.org/linux-trace-kernel/20231212111617.39e02849@gandalf.local.home
    
    Cc: stable@vger.kernel.org
    Cc: Mark Rutland <mark.rutland@arm.com>
    Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
    Fixes: a4543a2f ("ring-buffer: Get timestamp after event is allocated")
    Fixes: 58fbc3c6 ("ring-buffer: Consolidate add_timestamp to remove some branches")
    Reported-by: Kent Overstreet <kent.overstreet@linux.dev> # (on IRC)
    Acked-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
    Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
    b3ae7b67
ring_buffer.c 166 KB