]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
QUIC: Harden ring buffer against internal misuse
authorHugo Landau <hlandau@openssl.org>
Wed, 30 Aug 2023 09:32:53 +0000 (10:32 +0100)
committerHugo Landau <hlandau@openssl.org>
Thu, 31 Aug 2023 15:34:51 +0000 (16:34 +0100)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21895)

include/internal/ring_buf.h

index 1d70439278b50c7db6d0b384c0bb7ee9a1403fc9..85a8d309bae6a70f8536d8cec127b2f12cd9f304 100644 (file)
@@ -12,6 +12,7 @@
 # pragma once
 
 # include <openssl/e_os2.h>              /* For 'ossl_inline' */
+# include "internal/safe_math.h"
 
 /*
  * ==================================================================
@@ -39,6 +40,10 @@ struct ring_buf {
     uint64_t    ctail_offset;
 };
 
+OSSL_SAFE_MATH_UNSIGNED(u64, uint64_t)
+
+#define MAX_OFFSET   (((uint64_t)1) << 62) /* QUIC-imposed limit */
+
 static ossl_inline int ring_buf_init(struct ring_buf *r)
 {
     r->start = NULL;
@@ -74,11 +79,15 @@ static ossl_inline int ring_buf_write_at(struct ring_buf *r,
 {
     size_t avail, idx, l;
     unsigned char *start = r->start;
-    int i;
+    int i, err = 0;
 
     avail = ring_buf_avail(r);
     if (logical_offset < r->ctail_offset
-        || logical_offset + buf_len > r->head_offset + avail)
+        || safe_add_u64(logical_offset, buf_len, &err)
+           > safe_add_u64(r->head_offset, avail, &err)
+        || safe_add_u64(r->head_offset, buf_len, &err)
+           > MAX_OFFSET
+        || err)
         return 0;
 
     for (i = 0; buf_len > 0 && i < 2; ++i) {
@@ -113,6 +122,9 @@ static ossl_inline size_t ring_buf_push(struct ring_buf *r,
         if (buf_len > avail)
             buf_len = avail;
 
+        if (buf_len > MAX_OFFSET - r->head_offset)
+            buf_len = (size_t)(MAX_OFFSET - r->head_offset);
+
         if (buf_len == 0)
             break;
 
@@ -190,7 +202,7 @@ static ossl_inline void ring_buf_cpop_range(struct ring_buf *r,
 {
     assert(end >= start);
 
-    if (start > r->ctail_offset)
+    if (start > r->ctail_offset || end >= MAX_OFFSET)
         return;
 
     if (cleanse && r->alloc > 0 && end > r->ctail_offset) {