bpf_stream_stage_printk() increments ss->len before pushing the
formatted string to the staging log. If element allocation fails,
ss->len remains inflated and bpf_stream_stage_commit() permanently
charges the stream capacity for data that was never queued.

Only account the string length after a successful push, and use
vscnprintf() so the staged length is the truncated payload without
the trailing NUL.

Fixes: 5ab154f1463a ("bpf: Introduce BPF standard streams")
Signed-off-by: Jianlin Shi <[email protected]>
---
 kernel/bpf/stream.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/kernel/bpf/stream.c b/kernel/bpf/stream.c
index 0b157ec4e38e..a36fc9338967 100644
--- a/kernel/bpf/stream.c
+++ b/kernel/bpf/stream.c
@@ -316,17 +316,18 @@ int bpf_stream_stage_printk(struct bpf_stream_stage *ss, 
const char *fmt, ...)
 {
        struct bpf_bprintf_buffers *buf;
        va_list args;
-       int ret;
+       int len, ret;
 
        if (bpf_try_get_buffers(&buf))
                return -EBUSY;
 
        va_start(args, fmt);
-       ret = vsnprintf(buf->buf, ARRAY_SIZE(buf->buf), fmt, args);
+       len = vscnprintf(buf->buf, ARRAY_SIZE(buf->buf), fmt, args);
        va_end(args);
-       ss->len += ret;
        /* Exclude NULL byte during push. */
-       ret = __bpf_stream_push_str(&ss->log, buf->buf, ret);
+       ret = __bpf_stream_push_str(&ss->log, buf->buf, len);
+       if (!ret)
+               ss->len += len;
        bpf_put_buffers();
        return ret;
 }
-- 
2.43.0


Reply via email to