Integer overflow in iobuf_append
eg. if io->len == io->size = 0x1000 and len == 0xffffffff
size_t iobuf_append(struct iobuf *io, const void *buf, size_t len) {
char *p = NULL;
assert(io != NULL);
assert(io->len <= io->size);
if (len <= 0) {
} else if (io->len + len <= io->size) { <---- io->len + len = 0xfff < 0x1000
memcpy(io->buf + io->len, buf, len); <---- whoops!
io->len += len;
} else if ((p = (char *) NS_REALLOC(io->buf, io->len + len)) != NULL) {
io->buf = p;
memcpy(io->buf + io->len, buf, len);
io->len += len;
io->size = io->len;
} else {
len = 0;
}
return len;
}
Integer issues in deliver_websocket_frame
int type is used for length type; it’s not really adequate;
data_len = (int) (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) + htonl(* (uint32_t *) &buf[6]);
On 32-bit systems a packet of length > 0x7fffffff has negative length, and any packet of length > 0xffffffff will be truncated to the 32-bit component. On 64-bit systems, there are still issues with negative lengths. data_len is later assigned to a size_t type; so at the moment this code is safe, but it’s definitely not working as intended for 32-bit systems.
Integer overflow in mg_websocket_write resulting in stack corruption
eg. if data_len == 0xffffffff
size_t mg_websocket_write(struct mg_connection *conn, int opcode,
const char *data, size_t data_len) {
unsigned char mem[4192], *copy = mem;
size_t copy_len = 0;
fprintf(stderr, "mg_websocket_write %u\n", data_len);
if (data_len + 10 > sizeof(mem) && <---- data_len + 10 == 9 < sizeof(mem)
(copy = (unsigned char *) NS_MALLOC(data_len + 10)) == NULL) {
return 0;
}
fprintf(stderr, "copy = %p\n", copy);
copy[0] = 0x80 + (opcode & 0x0f);
// Frame format: http://tools.ietf.org/html/rfc6455#section-5.2
if (data_len < 126) {
// Inline 7-bit length field
copy[1] = data_len;
memcpy(copy + 2, data, data_len);
copy_len = 2 + data_len;
} else if (data_len <= 0xFFFF) {
// 16-bit length field
copy[1] = 126;
* (uint16_t *) (copy + 2) = (uint16_t) htons((uint16_t) data_len);
memcpy(copy + 4, data, data_len);
copy_len = 4 + data_len;
} else {
// 64-bit length field
copy[1] = 127;
const uint32_t hi = htonl((uint32_t) ((uint64_t) data_len >> 32));
const uint32_t lo = htonl(data_len & 0xffffffff);
memcpy(copy+2,&hi,sizeof(hi));
memcpy(copy+6,&lo,sizeof(lo));
fprintf(stderr, "copy %p %p %u\n", copy+10, data, data_len);
memcpy(copy + 10, data, data_len); <---- copying 0xffffffff bytes into 4192 byte stack buffer
copy_len = 10 + data_len;
}
if (copy_len > 0) {
mg_write(conn, copy, copy_len);
}
if (copy != mem) {
NS_FREE(copy);
}
// If we send closing frame, schedule a connection to be closed after
// data is drained to the client.
if (opcode == WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
MG_CONN_2_CONN(conn)->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
}
return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len;
}
This issue is triggerable in the example websocket_echo_server by sending a websocket request of length 0xffffffff
This bug is subject to a 90 day disclosure deadline. If 90 days elapse
without a broadly available patch, then the bug report will automatically
become visible to the public.