diff --git a/src/gquic_process.cpp b/src/gquic_process.cpp index 2f3ce62..107a47c 100644 --- a/src/gquic_process.cpp +++ b/src/gquic_process.cpp @@ -118,6 +118,12 @@ static int get_value(unsigned char *payload, int *offset, int len) return 0; } + +static int check_length(int last_len, int field_len) +{ + return ((last_len-field_len>0) ? 1 : 0); +} + int quic_getLinkState(struct _quic_context *_context) { UCHAR state = 0; @@ -229,23 +235,39 @@ unsigned long long get_variable_length(char *p, int offset, int v_len) return 0; } -long long bit_to_value(char *payload, unsigned char flags, unsigned long long *out_value, int *used_len) +long long bit_to_value(char *payload, int payload_len, unsigned char flags, unsigned long long *out_value, int *used_len) { switch(flags&0x3) // packet number { case 0x3: // 6 bytes + if(!check_length(payload_len-*used_len, 6)) + { + return -1; + } *out_value=get_variable_length(payload, *used_len, 6); *used_len+=6; break; case 0x2: // 4 bytes + if(!check_length(payload_len-*used_len, sizeof(unsigned int))) + { + return -1; + } *out_value=(unsigned long long)ntohl(*(unsigned int *)(payload+*used_len)); *used_len+=4; break; case 0x1: // 2bytes + if(!check_length(payload_len-*used_len, sizeof(unsigned short))) + { + return -1; + } *out_value=(unsigned long long)ntohs(*(unsigned short *)(payload+*used_len)); *used_len+=2; break; default: // 1 byte + if(!check_length(payload_len-*used_len, sizeof(unsigned char))) + { + return -1; + } *out_value=payload[*used_len]; *used_len+=1; break; @@ -268,23 +290,37 @@ int get_quic_tlv(char *start_pos, quic_tlv_t *tlv, int len, int type, int thread return 0; } -int get_stream_id(struct streaminfo *pstream, struct _quic_context* _context, char* payload, unsigned char frame_type, int *used_len) +int get_stream_id(struct streaminfo *pstream, struct _quic_context* _context, char* payload, int payload_len, unsigned char frame_type, int *used_len) { int stream_len=0,offset_len=0; _context->quic_info.frame_hdr.frame_type=frame_type; stream_len=(frame_type&GQUIC_SPECIAL_FRAME_STREAM_ID)+1; + if(!check_length(payload_len-*used_len, stream_len)) + { + return -1; + } + _context->quic_info.frame_hdr.stream_id=(unsigned int)get_variable_length(payload, *used_len, stream_len); *used_len+=stream_len; // stream ID length if(frame_type&GQUIC_SPECIAL_FRAME_STREAM_DLEN) { + if(!check_length(payload_len-*used_len, 2)) + { + return -1; + } _context->quic_info.frame_hdr.data_len=ntohs(*(unsigned short *)(payload+*used_len)); *used_len+=2; //data length } offset_len=(frame_type&GQUIC_SPECIAL_FRAME_STREAM_OFFSET) ? (((frame_type&GQUIC_SPECIAL_FRAME_STREAM_OFFSET))>>2)+1 : 0; + if(!check_length(payload_len-*used_len, offset_len)) + { + return -1; + } + _context->quic_info.frame_hdr.offset=get_variable_length(payload, *used_len, offset_len); *used_len+=offset_len; @@ -325,6 +361,7 @@ unsigned long long get_packet_number(char* data, int offset, char pkn_len) // GQUIC version from 0 to 43 static enum _QUIC_VERSION parse_q0to43_header(struct streaminfo *pstream, struct _quic_context* _context, char *payload, int payload_len, int *used_len) { + int ret=0; char public_flags=0; struct _quic_public_header *gquic_hdr=&(_context->quic_info.quic_hdr); @@ -380,8 +417,12 @@ static enum _QUIC_VERSION parse_q0to43_header(struct streaminfo *pstream, struct return QUIC_VERSION_UNKNOWN; } - bit_to_value(payload, gquic_hdr->public_flags>>4, &gquic_hdr->packet_number, used_len); - + ret=bit_to_value(payload, payload_len, gquic_hdr->public_flags>>4, &gquic_hdr->packet_number, used_len); + if(ret<0) + { + return (enum _QUIC_VERSION)gquic_hdr->quic_version; + } + if(gquic_hdr->public_flags==GQUIC_PUBLIC_FLAG_NONCE) { *used_len+=32; //diversification nonce @@ -520,8 +561,8 @@ enum _QUIC_VERSION is_quic_protocol(struct streaminfo *pstream, struct _quic_con (quic_version==GQUIC_VERSION_T099) || (quic_version>=GQUIC_VERSION_Q047 && quic_version<=GQUIC_VERSION_Q050) || (quic_version>=GQUIC_VERSION_Q051 && quic_version<=GQUIC_VERSION_Q059) || - (quic_version>=GQUIC_VERSION_T048&& quic_version<=GQUIC_VERSION_T049) || - (quic_version>=GQUIC_VERSION_T050&& quic_version<=GQUIC_VERSION_T059) || + (quic_version>=GQUIC_VERSION_T048 && quic_version<=GQUIC_VERSION_T049) || + (quic_version>=GQUIC_VERSION_T050 && quic_version<=GQUIC_VERSION_T059) || (quic_version>=QUANT_VERSION_00 && quic_version<=QUANT_VERSION_FF) || (quic_version>=QUIC_GO_VERSION_00 && quic_version<=QUIC_GO_VERSION_FF) || (quic_version>=QUICLY_VERSION_00 && quic_version<=QUICLY_VERSION_FF) || @@ -647,55 +688,6 @@ int parse_extension_tag(struct streaminfo *pstream, struct _quic_stream **quic_s return 0; } -int gquic_frame_type_ack(struct streaminfo *pstream, struct _quic_context* _context, char *payload, int payload_len, int *used_len, char frame_type, void *a_packet) -{ - unsigned char num_timestamp; - unsigned char num_blocks=0;; - unsigned short largest_acked_delta_time=0; - unsigned long long ack_block_length=0; - unsigned long long largest_observed_ack=0; - - bit_to_value(payload, frame_type>>2, &largest_observed_ack, used_len); // frame_type -> LL - largest_acked_delta_time=ntohs(*(unsigned short *)(payload+*used_len)); - *used_len+=sizeof(unsigned short); - - if(frame_type&0x20) // frame_type -> n - { - num_blocks=(*(unsigned char *)(payload+*used_len))-1; - } - bit_to_value(payload, frame_type>>2, &ack_block_length, used_len); // frame_type -> mm - - if(num_blocks>0) - { - *used_len+=1; //gap_to_next_block - - *used_len+=(num_blocks*sizeof(unsigned int)); //Ack block length - } - - num_timestamp=*(unsigned char *)(payload+*used_len); - *used_len += 1; - - if(num_timestamp > 0) - { - *used_len+=sizeof(unsigned char); //Delta Largest Observed - *used_len+= sizeof(unsigned int); //First Timestamp - *used_len+=(num_timestamp-1)*(1+2); //1+2=Delta Largest Observed+Time Since Previous Timestamp - } - - MESA_handle_runtime_log(g_quic_param.logger, - RLOG_LV_DEBUG, - "QUIC_ACK", - "largest_observed_ack: %llu largest_acked_delta_time: %u num_blocks: %d ack_block_length: %d num_timestamp: %d addr: %s", - largest_observed_ack, - largest_acked_delta_time, - num_blocks, - ack_block_length, - num_timestamp, - printaddr(&pstream->addr, pstream->threadnum)); - - return 0; -} - int gquic_frame_type_stream(struct streaminfo *pstream, struct _quic_context* _context, char *payload, int payload_len, int *used_len, void *a_packet) { int ret=0; @@ -703,6 +695,11 @@ int gquic_frame_type_stream(struct streaminfo *pstream, struct _quic_context* _c unsigned short tag_num = 0; unsigned int message_tag; + if(!check_length(payload_len-*used_len, 8)) + { + return state; + } + message_tag=(unsigned int)ntohl(*(unsigned int *)(payload+*used_len)); *used_len+=4; @@ -762,6 +759,10 @@ int gquic_proc_unencrypt(struct streaminfo *pstream, struct _quic_context* _cont return APP_STATE_GIVEME; // PADDING frame break; case GQUIC_REGULAR_FRAME_RST_STREAM: + if(!check_length(payload_len-*used_len, sizeof(unsigned int)+sizeof(unsigned long long)+sizeof(unsigned int))) + { + return APP_STATE_GIVEME; + } stream_id=(unsigned int)get_variable_length(payload, *used_len, sizeof(unsigned int)); *used_len+=sizeof(unsigned int); @@ -783,12 +784,21 @@ int gquic_proc_unencrypt(struct streaminfo *pstream, struct _quic_context* _cont return quic_callPlugins(pstream, _context, NULL, 0, QUIC_INTEREST_KEY_MASK, a_packet); break; case GQUIC_REGULAR_FRAME_CONNECTION_CLOSE: + if(!check_length(payload_len-*used_len, sizeof(unsigned int)+sizeof(unsigned short))) + { + return APP_STATE_GIVEME; + } error_code=(unsigned int)get_variable_length(payload, *used_len, sizeof(unsigned int)); *used_len+=sizeof(unsigned int); reason_phrase_length=(unsigned short)get_variable_length(payload, *used_len, sizeof(unsigned short)); *used_len+=sizeof(unsigned short); + if(!check_length(payload_len-*used_len, reason_phrase_length)) + { + return APP_STATE_GIVEME; + } + *used_len+=reason_phrase_length; // skip Reason Phrase MESA_handle_runtime_log(g_quic_param.logger, @@ -802,6 +812,10 @@ int gquic_proc_unencrypt(struct streaminfo *pstream, struct _quic_context* _cont return quic_callPlugins(pstream, _context, NULL, 0, QUIC_INTEREST_KEY_MASK, a_packet); break; case GQUIC_REGULAR_FRAME_GOAWAY: + if(!check_length(payload_len-*used_len, sizeof(unsigned int)+sizeof(unsigned int)+sizeof(unsigned short))) + { + return APP_STATE_GIVEME; + } error_code=(unsigned int)get_variable_length(payload, *used_len, sizeof(unsigned int)); *used_len+=sizeof(unsigned int); @@ -811,7 +825,11 @@ int gquic_proc_unencrypt(struct streaminfo *pstream, struct _quic_context* _cont reason_phrase_length=(unsigned short)get_variable_length(payload, *used_len, sizeof(unsigned short)); *used_len+=sizeof(unsigned short); - + + if(!check_length(payload_len-*used_len, reason_phrase_length)) + { + return APP_STATE_GIVEME; + } *used_len+=reason_phrase_length; // skip Reason Phrase MESA_handle_runtime_log(g_quic_param.logger, @@ -824,6 +842,10 @@ int gquic_proc_unencrypt(struct streaminfo *pstream, struct _quic_context* _cont printaddr(&pstream->addr, pstream->threadnum)); break; case GQUIC_REGULAR_FRAME_WINDOW_UPDATE: + if(!check_length(payload_len-*used_len, sizeof(unsigned int)+sizeof(unsigned long long))) + { + return APP_STATE_GIVEME; + } stream_id=(unsigned int)get_variable_length(payload, *used_len, sizeof(unsigned int)); *used_len+=sizeof(unsigned int); @@ -839,6 +861,10 @@ int gquic_proc_unencrypt(struct streaminfo *pstream, struct _quic_context* _cont printaddr(&pstream->addr, pstream->threadnum)); break; case GQUIC_REGULAR_FRAME_BLOCKED: + if(!check_length(payload_len-*used_len, sizeof(unsigned int))) + { + return APP_STATE_GIVEME; + } stream_id=(unsigned int)get_variable_length(payload, *used_len, sizeof(unsigned int)); *used_len+=sizeof(unsigned int); @@ -850,7 +876,11 @@ int gquic_proc_unencrypt(struct streaminfo *pstream, struct _quic_context* _cont printaddr(&pstream->addr, pstream->threadnum)); break; case GQUIC_REGULAR_FRAME_STOP_WAITING: - bit_to_value(payload, _context->quic_info.quic_hdr.public_flags>>4, &least_unacked_delta, used_len); + ret=bit_to_value(payload, payload_len, _context->quic_info.quic_hdr.public_flags>>4, &least_unacked_delta, used_len); + if(ret<0) + { + return APP_STATE_GIVEME; + } MESA_handle_runtime_log(g_quic_param.logger, RLOG_LV_DEBUG, @@ -864,14 +894,13 @@ int gquic_proc_unencrypt(struct streaminfo *pstream, struct _quic_context* _cont //The receiver of a PING frame simply needs to ACK the packet containing this frame break; default: //Regular Frame Types - if(frame_type&GQUIC_SPECIAL_FRAME_STREAM) + if(frame_type&GQUIC_SPECIAL_FRAME_STREAM || (frame_type&0xC0)==GQUIC_SPECIAL_FRAME_ACK) { - stream_id=get_stream_id(pstream, _context, payload, frame_type, used_len); - ret=gquic_frame_type_stream(pstream, _context, payload, payload_len, used_len, a_packet); - } - else if((frame_type&0xC0)==GQUIC_SPECIAL_FRAME_ACK) // high bit set 0; (frame_type: 01nullmmB) - { - stream_id=get_stream_id(pstream, _context, payload, frame_type, used_len); + stream_id=get_stream_id(pstream, _context, payload, payload_len, frame_type, used_len); + if(stream_id<0) + { + return APP_STATE_GIVEME; + } ret=gquic_frame_type_stream(pstream, _context, payload, payload_len, used_len, a_packet); } else if((frame_type&0xE0)==GQUIC_SPECIAL_FRAME_CONGEST_FB) // high two bits set 0; (frame_type: 01nullmmB) @@ -898,9 +927,10 @@ int gquic_proc_unencrypt(struct streaminfo *pstream, struct _quic_context* _cont //QUIC_DATA:is quic data pcap;QUIC_TRUE:is handshake pcap;QUIC_RETURN_DROPME:not quic protocol; int parse_gquic_Q046(struct streaminfo *pstream, struct _quic_context* _context, void *a_packet, char * payload, int payload_len, int *used_len) { + int stream_id=0; int ret=APP_STATE_GIVEME; unsigned char frame_type; - + while(*used_len < payload_len) { frame_type=payload[*used_len]; @@ -908,7 +938,11 @@ int parse_gquic_Q046(struct streaminfo *pstream, struct _quic_context* _context, if(frame_type&IQUIC_FRAME_STREAM_HEX08) { - get_stream_id(pstream, _context, payload, frame_type, used_len); + stream_id=get_stream_id(pstream, _context, payload, payload_len, frame_type, used_len); + if(stream_id<0) + { + return APP_STATE_GIVEME; + } ret=gquic_frame_type_stream(pstream, _context, payload, payload_len, used_len, a_packet); } else