diff --git a/http/WebSocketParser.cpp b/http/WebSocketParser.cpp index e655a56c6..c2c9ebbde 100644 --- a/http/WebSocketParser.cpp +++ b/http/WebSocketParser.cpp @@ -12,8 +12,11 @@ static int on_frame_header(websocket_parser* parser) { if (opcode != WS_OP_CONTINUE) { wp->opcode = opcode; } - int length = parser->length; - int reserve_length = MIN(length + 1, MAX_PAYLOAD_LENGTH); + size_t length = parser->length; + if (length > (size_t)MAX_PAYLOAD_LENGTH) { + return 1; // reject oversized frames; stops parsing before s_body is entered + } + size_t reserve_length = length + 1; // safe: length <= MAX_PAYLOAD_LENGTH (16M) so no overflow if (reserve_length > wp->message.capacity()) { wp->message.reserve(reserve_length); } diff --git a/http/websocket_parser.c b/http/websocket_parser.c index c6f5670d7..6ba50d0b0 100644 --- a/http/websocket_parser.c +++ b/http/websocket_parser.c @@ -107,6 +107,12 @@ size_t websocket_parser_execute(websocket_parser *parser, const websocket_parser } p--; if(!parser->require) { + /* RFC 6455 ยง5.2: the most significant bit of the 64-bit payload + * length MUST be 0. Reject frames that violate this to prevent + * integer-wrap exploits on the pointer check below. */ + if (parser->length > ((size_t)~(size_t)0 >> 1)) { + return GET_NPARSED(); + } if (parser->flags & WS_HAS_MASK) { SET_STATE(s_mask); parser->require = 4; @@ -142,7 +148,7 @@ size_t websocket_parser_execute(websocket_parser *parser, const websocket_parser break; case s_body: if(parser->require) { - if(p + parser->require <= end) { + if(parser->require <= (size_t)(end - p)) { EMIT_DATA_CB(frame_body, p, parser->require); p += parser->require; parser->require = 0;