]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
ws: fix some edge cases
authorStefan Eissing <stefan@eissing.org>
Thu, 9 Oct 2025 09:23:42 +0000 (11:23 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 10 Oct 2025 21:42:29 +0000 (23:42 +0200)
Fix edge cases around handling of pending send frames and encoding
frames with size_t/curl_off_t possible flowy things.

Reported-by: Joshua Rogers
Closes #18965

lib/ws.c

index d3379c6502375abd3d196ed09040dbf2b27b5196..6c8f07e1776e18aacc02e02af0205d1b26fe245d 100644 (file)
--- a/lib/ws.c
+++ b/lib/ws.c
@@ -647,6 +647,22 @@ static CURLcode ws_enc_add_cntrl(struct Curl_easy *data,
   return CURLE_OK;
 }
 
+static curl_off_t ws_payload_remain(curl_off_t payload_total,
+                                    curl_off_t payload_offset,
+                                    size_t payload_buffered)
+{
+  curl_off_t remain = payload_total - payload_offset;
+  if((payload_total < 0) || (payload_offset < 0) || (remain < 0))
+    return -1;
+#if SIZEOF_OFF_T <= SIZEOF_SIZE_T
+  if((curl_off_t)payload_buffered < 0)
+    return -1;
+#endif
+  if(remain < (curl_off_t)payload_buffered)
+    return -1;
+  return remain - (curl_off_t)payload_buffered;
+}
+
 static CURLcode ws_cw_dec_next(const unsigned char *buf, size_t buflen,
                                int frame_age, int frame_flags,
                                curl_off_t payload_offset,
@@ -658,11 +674,16 @@ static CURLcode ws_cw_dec_next(const unsigned char *buf, size_t buflen,
   struct Curl_easy *data = ctx->data;
   struct websocket *ws = ctx->ws;
   bool auto_pong = !data->set.ws_no_auto_pong;
-  curl_off_t remain = (payload_len - (payload_offset + buflen));
+  curl_off_t remain;
   CURLcode result;
 
   (void)frame_age;
   *pnwritten = 0;
+  remain = ws_payload_remain(payload_len, payload_offset, buflen);
+  if(remain < 0) {
+    DEBUGASSERT(0); /* parameter mismatch */
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
 
   if(auto_pong && (frame_flags & CURLWS_PING) && !remain) {
     /* auto-respond to PINGs, only works for single-frame payloads atm */
@@ -981,12 +1002,18 @@ static CURLcode ws_enc_add_pending(struct Curl_easy *data,
                 result);
     goto out;
   }
-  /* our buffer should always be able to take in a control frame */
-  DEBUGASSERT(n == ws->pending.payload_len);
+  if(n != ws->pending.payload_len) {
+    DEBUGASSERT(0); /* buffer should always be able to take all */
+    CURL_TRC_WS(data, "ws_enc_cntrl(), error added only %zu/%zu payload,",
+                n, ws->pending.payload_len);
+    result = CURLE_SEND_ERROR;
+    goto out;
+  }
+  /* the frame should be complete now */
   DEBUGASSERT(!ws->enc.payload_remain);
+  memset(&ws->pending, 0, sizeof(ws->pending));
 
 out:
-  memset(&ws->pending, 0, sizeof(ws->pending));
   return result;
 }
 
@@ -1445,10 +1472,16 @@ static CURLcode ws_client_collect(const unsigned char *buf, size_t buflen,
   struct ws_collect *ctx = userp;
   struct Curl_easy *data = ctx->data;
   bool auto_pong = !data->set.ws_no_auto_pong;
-  curl_off_t remain = (payload_len - (payload_offset + buflen));
+  curl_off_t remain;
   CURLcode result = CURLE_OK;
 
   *pnwritten = 0;
+  remain = ws_payload_remain(payload_len, payload_offset, buflen);
+  if(remain < 0) {
+    DEBUGASSERT(0); /* parameter mismatch */
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
   if(!ctx->bufidx) {
     /* first write */
     ctx->frame_age = frame_age;