mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-08-19 09:40:21 +00:00
Merge commit from fork
The 127-length extended payload field was decoded with `ntohl()`, a 32-bit byte swap, dropping the upper word of the 64-bit length. Combined with the signed `issize_t plen`, a high low-word truncated to a negative length that slipped past the signed size guard and became `SIZE_MAX` in the read loop, driving an out-of-bounds write past `wsh->buffer`. Decode the full 64-bit length in network byte order and reject any value that cannot fit the buffer with an unsigned comparison before narrowing to `issize_t`, so a truncated or oversized length can no longer yield a negative `plen` or pass the guard. `ws_write_frame()` had the symmetric defect: it encoded the 64-bit length field with a 32-bit `htonl()`, mis-framing any payload large enough to use the 8-byte (127) length field. Emit the full 8 bytes there too. Factor the byte assembly into `ws_get_be64()` / `ws_put_be64()` helpers.
This commit is contained in:
@@ -384,6 +384,32 @@ issize_t ws_close(wsh_t *wsh, int16_t reason)
|
||||
return reason * -1;
|
||||
}
|
||||
|
||||
/* Read a big-endian (network byte order) 64-bit integer from a byte buffer. */
|
||||
static uint64_t ws_get_be64(const uint8_t *p)
|
||||
{
|
||||
return ((uint64_t)p[0] << 56) |
|
||||
((uint64_t)p[1] << 48) |
|
||||
((uint64_t)p[2] << 40) |
|
||||
((uint64_t)p[3] << 32) |
|
||||
((uint64_t)p[4] << 24) |
|
||||
((uint64_t)p[5] << 16) |
|
||||
((uint64_t)p[6] << 8) |
|
||||
((uint64_t)p[7]);
|
||||
}
|
||||
|
||||
/* Write a big-endian (network byte order) 64-bit integer to a byte buffer. */
|
||||
static void ws_put_be64(uint8_t *p, uint64_t v)
|
||||
{
|
||||
p[0] = (uint8_t)(v >> 56);
|
||||
p[1] = (uint8_t)(v >> 48);
|
||||
p[2] = (uint8_t)(v >> 40);
|
||||
p[3] = (uint8_t)(v >> 32);
|
||||
p[4] = (uint8_t)(v >> 24);
|
||||
p[5] = (uint8_t)(v >> 16);
|
||||
p[6] = (uint8_t)(v >> 8);
|
||||
p[7] = (uint8_t)(v);
|
||||
}
|
||||
|
||||
issize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
{
|
||||
|
||||
@@ -447,7 +473,7 @@ issize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
wsh->payload = &wsh->buffer[2];
|
||||
|
||||
if (wsh->plen == 127) {
|
||||
uint64_t *u64;
|
||||
uint64_t plen64;
|
||||
|
||||
need += 8;
|
||||
|
||||
@@ -457,10 +483,16 @@ issize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
return ws_close(wsh, WS_PROTO_ERR);
|
||||
}
|
||||
|
||||
u64 = (uint64_t *) wsh->payload;
|
||||
plen64 = ws_get_be64((const uint8_t *)wsh->payload);
|
||||
wsh->payload += 8;
|
||||
|
||||
wsh->plen = ntohl((u_long)*u64);
|
||||
/* Bound-check unsigned, before narrowing to the signed issize_t plen. */
|
||||
if (plen64 >= wsh->buflen) {
|
||||
*oc = WSOC_CLOSE;
|
||||
return ws_close(wsh, WS_DATA_TOO_BIG);
|
||||
}
|
||||
|
||||
wsh->plen = (issize_t)plen64;
|
||||
|
||||
} else if (wsh->plen == 126) {
|
||||
uint16_t *u16;
|
||||
@@ -598,13 +630,10 @@ issize_t ws_write_frame(wsh_t *wsh, ws_opcode_t oc, void *data, size_t bytes)
|
||||
*u16 = htons((uint16_t) bytes);
|
||||
|
||||
} else {
|
||||
uint64_t *u64;
|
||||
|
||||
hdr[1] = 127;
|
||||
hlen += 8;
|
||||
|
||||
u64 = (uint64_t *) &hdr[2];
|
||||
*u64 = htonl((unsigned long)bytes);
|
||||
ws_put_be64(&hdr[2], (uint64_t)bytes);
|
||||
}
|
||||
|
||||
if (ws_raw_write(wsh, (void *) &hdr[0], hlen) != (issize_t)hlen) {
|
||||
|
||||
Reference in New Issue
Block a user