ws: fix some edge cases

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
This commit is contained in:
Stefan Eissing 2025-10-09 11:23:42 +02:00 committed by Daniel Stenberg
parent 4cc476b37f
commit a4d3c4e847
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -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;