mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-08-19 09:40:21 +00:00
[mod_xml_rpc] Fix OOB write and read-loop hang in WebSocket parser (#3114)
`ws_read_frame()` had two defects in the framing path: - After header parsing, the remaining payload count `need = plen - (datalen - header)` could go negative when the initial read buffered more bytes than the frame's declared length, even with an in-range `plen`. A negative `need` passed the signed size guard and reached `ws_raw_read()` as a `size_t` near its maximum, driving a `memcpy` past `wsh->buffer`. Reject `need < 0` with a protocol-error close before the read loop. - The loop filling the frame header called `ws_raw_read()` without checking its result, so a connection that stopped delivering header bytes left the loop with no terminating condition, spinning or hanging the handler thread. Close on a non-advancing read, matching the payload read loop.
This commit is contained in:
@@ -430,14 +430,17 @@ issize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
}
|
||||
|
||||
if ((wsh->datalen = ws_raw_read(wsh, wsh->buffer, 14)) < need) {
|
||||
while (!wsh->down && (wsh->datalen += ws_raw_read(wsh, wsh->buffer + wsh->datalen, 14 - wsh->datalen)) < need) ;
|
||||
while (!wsh->down && wsh->datalen < need) {
|
||||
issize_t r = ws_raw_read(wsh, wsh->buffer + wsh->datalen, 14 - wsh->datalen);
|
||||
|
||||
#if 0
|
||||
if (0 && (wsh->datalen += ws_raw_read(wsh, wsh->buffer + wsh->datalen, 14 - wsh->datalen)) < need) {
|
||||
/* too small - protocol err */
|
||||
return ws_close(wsh, WS_PROTO_ERR);
|
||||
if (r < 1) {
|
||||
/* invalid read - protocol err .. */
|
||||
*oc = WSOC_CLOSE;
|
||||
return ws_close(wsh, WS_PROTO_ERR);
|
||||
}
|
||||
|
||||
wsh->datalen += r;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
*oc = *wsh->buffer & 0xf;
|
||||
@@ -517,6 +520,12 @@ issize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
|
||||
need = (wsh->plen - (wsh->datalen - need));
|
||||
|
||||
if (need < 0) {
|
||||
/* more buffered than the frame declares - protocol err */
|
||||
*oc = WSOC_CLOSE;
|
||||
return ws_close(wsh, WS_PROTO_ERR);
|
||||
}
|
||||
|
||||
/* Reserve 1 byte for the trailing NUL below. */
|
||||
if ((need + wsh->datalen) >= (issize_t)wsh->buflen) {
|
||||
/* too big - Ain't nobody got time fo' dat */
|
||||
|
||||
Reference in New Issue
Block a user