Commit 7e1eb3c4ea for freeswitch.com

commit 7e1eb3c4ea55e06c350c4de00c9b56ce6384cfd7
Author: Dmitry Verenitsin <morbit85@gmail.com>
Date:   Sun Aug 9 01:17:57 2026 +0500

    [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.

diff --git a/src/mod/xml_int/mod_xml_rpc/ws.c b/src/mod/xml_int/mod_xml_rpc/ws.c
index c4c212ac21..bb9c22e8ba 100644
--- a/src/mod/xml_int/mod_xml_rpc/ws.c
+++ b/src/mod/xml_int/mod_xml_rpc/ws.c
@@ -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 */