• Andrii Nakryiko's avatar
    bpf: Switch BPF verifier log to be a rotating log by default · 12166409
    Andrii Nakryiko authored
    Currently, if user-supplied log buffer to collect BPF verifier log turns
    out to be too small to contain full log, bpf() syscall returns -ENOSPC,
    fails BPF program verification/load, and preserves first N-1 bytes of
    the verifier log (where N is the size of user-supplied buffer).
    
    This is problematic in a bunch of common scenarios, especially when
    working with real-world BPF programs that tend to be pretty complex as
    far as verification goes and require big log buffers. Typically, it's
    when debugging tricky cases at log level 2 (verbose). Also, when BPF program
    is successfully validated, log level 2 is the only way to actually see
    verifier state progression and all the important details.
    
    Even with log level 1, it's possible to get -ENOSPC even if the final
    verifier log fits in log buffer, if there is a code path that's deep
    enough to fill up entire log, even if normally it would be reset later
    on (there is a logic to chop off successfully validated portions of BPF
    verifier log).
    
    In short, it's not always possible to pre-size log buffer. Also, what's
    worse, in practice, the end of the log most often is way more important
    than the beginning, but verifier stops emitting log as soon as initial
    log buffer is filled up.
    
    This patch switches BPF verifier log behavior to effectively behave as
    rotating log. That is, if user-supplied log buffer turns out to be too
    short, verifier will keep overwriting previously written log,
    effectively treating user's log buffer as a ring buffer. -ENOSPC is
    still going to be returned at the end, to notify user that log contents
    was truncated, but the important last N bytes of the log would be
    returned, which might be all that user really needs. This consistent
    -ENOSPC behavior, regardless of rotating or fixed log behavior, allows
    to prevent backwards compatibility breakage. The only user-visible
    change is which portion of verifier log user ends up seeing *if buffer
    is too small*. Given contents of verifier log itself is not an ABI,
    there is no breakage due to this behavior change. Specialized tools that
    rely on specific contents of verifier log in -ENOSPC scenario are
    expected to be easily adapted to accommodate old and new behaviors.
    
    Importantly, though, to preserve good user experience and not require
    every user-space application to adopt to this new behavior, before
    exiting to user-space verifier will rotate log (in place) to make it
    start at the very beginning of user buffer as a continuous
    zero-terminated string. The contents will be a chopped off N-1 last
    bytes of full verifier log, of course.
    
    Given beginning of log is sometimes important as well, we add
    BPF_LOG_FIXED (which equals 8) flag to force old behavior, which allows
    tools like veristat to request first part of verifier log, if necessary.
    BPF_LOG_FIXED flag is also a simple and straightforward way to check if
    BPF verifier supports rotating behavior.
    
    On the implementation side, conceptually, it's all simple. We maintain
    64-bit logical start and end positions. If we need to truncate the log,
    start position will be adjusted accordingly to lag end position by
    N bytes. We then use those logical positions to calculate their matching
    actual positions in user buffer and handle wrap around the end of the
    buffer properly. Finally, right before returning from bpf_check(), we
    rotate user log buffer contents in-place as necessary, to make log
    contents contiguous. See comments in relevant functions for details.
    Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Reviewed-by: default avatarLorenz Bauer <lmb@isovalent.com>
    Link: https://lore.kernel.org/bpf/20230406234205.323208-4-andrii@kernel.org
    12166409
log.c 7.5 KB