On Fri, Apr 7, 2023 at 12:42 AM Andrii Nakryiko <andrii@xxxxxxxxxx> wrote: > > 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: Andrii Nakryiko <andrii@xxxxxxxxxx> Reviewed-by: Lorenz Bauer <lmb@xxxxxxxxxxxxx>