bpf_stream_push_str() accounts the string length before allocating a
stream element. If the allocation fails, the length remains charged even
though no element is queued and therefore cannot be released by a reader.
Repeated failures can exhaust the stream capacity permanently until the
BPF program is freed.

Refactor bpf_stream_release_capacity() to take a length so the consume
and release sides are symmetric, and use it to roll back the charge when
creating the stream element fails.

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

diff --git a/kernel/bpf/stream.c b/kernel/bpf/stream.c
index be9ce98e9469..0b157ec4e38e 100644
--- a/kernel/bpf/stream.c
+++ b/kernel/bpf/stream.c
@@ -68,10 +68,8 @@ static int bpf_stream_consume_capacity(struct bpf_stream 
*stream, int len)
        return 0;
 }
 
-static void bpf_stream_release_capacity(struct bpf_stream *stream, struct 
bpf_stream_elem *elem)
+static void bpf_stream_release_capacity(struct bpf_stream *stream, int len)
 {
-       int len = elem->total_len;
-
        atomic_sub(len, &stream->capacity);
 }
 
@@ -79,7 +77,14 @@ static int bpf_stream_push_str(struct bpf_stream *stream, 
const char *str, int l
 {
        int ret = bpf_stream_consume_capacity(stream, len);
 
-       return ret ?: __bpf_stream_push_str(&stream->log, str, len);
+       if (ret)
+               return ret;
+
+       ret = __bpf_stream_push_str(&stream->log, str, len);
+       if (ret)
+               bpf_stream_release_capacity(stream, len);
+
+       return ret;
 }
 
 static struct bpf_stream *bpf_stream_get(enum bpf_stream_id stream_id, struct 
bpf_prog_aux *aux)
@@ -188,7 +193,7 @@ static int bpf_stream_read(struct bpf_stream *stream, void 
__user *buf, int len)
                if (cont)
                        continue;
                bpf_stream_backlog_pop(stream);
-               bpf_stream_release_capacity(stream, elem);
+               bpf_stream_release_capacity(stream, elem->total_len);
                bpf_stream_free_elem(elem);
        }
 
-- 
2.43.0


Reply via email to