bstr_printf() returns the would-be length excluding the trailing NUL.
When that value is >= MAX_BPRINTF_BUF the message was truncated, but
bpf_stream_push_str() still tried to allocate with the inflated length
and failed with -ENOMEM. The boundary case of exactly MAX_BPRINTF_BUF
could also copy the trailing NUL into the stream element.

Reject such lengths with -E2BIG before charging stream capacity, and
tighten bpf_stream_elem_alloc() to accept only payloads strictly shorter
than the bprintf buffer.

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

diff --git a/kernel/bpf/stream.c b/kernel/bpf/stream.c
index c1077160074c..bd1e98fde4b0 100644
--- a/kernel/bpf/stream.c
+++ b/kernel/bpf/stream.c
@@ -22,11 +22,11 @@ static struct bpf_stream_elem *bpf_stream_elem_alloc(int 
len)
        size_t alloc_size;
 
        /*
-        * Length denotes the amount of data to be written as part of stream 
element,
-        * thus includes '\0' byte. We're capped by how much 
bpf_bprintf_buffers can
-        * accomodate, therefore deny allocations that won't fit into them.
+        * Length is the payload pushed into the stream, excluding the
+        * trailing NUL of the bprintf buffer. Reject anything that cannot
+        * fit without copying that NUL into the stream element.
         */
-       if (len < 0 || len > max_len)
+       if (len < 0 || len >= max_len)
                return NULL;
 
        alloc_size = offsetof(struct bpf_stream_elem, str[len]);
@@ -245,6 +245,11 @@ __bpf_kfunc int bpf_stream_vprintk(int stream_id, const 
char *fmt__str, const vo
                return ret;
 
        ret = bstr_printf(data.buf, MAX_BPRINTF_BUF, fmt__str, data.bin_args);
+       /* Truncation: reject before capacity charge (not -ENOMEM). */
+       if (ret >= MAX_BPRINTF_BUF) {
+               bpf_bprintf_cleanup(&data);
+               return -E2BIG;
+       }
        /* Exclude NULL byte during push. */
        ret = bpf_stream_push_str(stream, data.buf, ret);
        bpf_bprintf_cleanup(&data);
-- 
2.43.0


Reply via email to