TSG-8364: 增加校验长度的逻辑避免导致段错误

This commit is contained in:
liuxueli
2021-11-06 21:10:20 +03:00
parent da000d2b4b
commit fa5af89690
2 changed files with 67 additions and 20 deletions

View File

@@ -1,7 +1,7 @@
/*
* quic_process.c
*
* Created on: 2019<31><39>4<EFBFBD><34>2<EFBFBD><32>
* Created on: 2019<31><39>4<EFBFBD><34>2<EFBFBD><32>
* Author: root
*/
@@ -1134,12 +1134,20 @@ int parse_encrypt_parameter(struct _quic_stream *quic_stream, unsigned char *pay
case EXT_QUIC_PARAM_USER_AGENT: // 2021-10-20 deprecated
quic_stream->ua_idx=quic_stream->ext_tag_num++;
length=get_value(payload, &used_len, 1); // length=1
if(length+used_len>payload_len)
{
return 0;
}
get_quic_tlv((char *)payload+used_len, &(quic_stream->ext_tags[quic_stream->ua_idx]), length, EXT_QUIC_PARAM_USER_AGENT, thread_seq);
used_len+=length;
break;
case EXT_QUIC_PARAM_QUIC_VERSION:
quic_stream->ver_idx=quic_stream->ext_tag_num++;
length=get_value(payload, &used_len, 1); // length=1
if(length+used_len>payload_len)
{
return 0;
}
get_quic_tlv((char *)payload+used_len, &(quic_stream->ext_tags[quic_stream->ver_idx]), length, EXT_QUIC_PARAM_QUIC_VERSION, thread_seq);
*(unsigned int *)quic_stream->ext_tags[quic_stream->ver_idx].value=(unsigned int)htonl(*(unsigned int *)quic_stream->ext_tags[quic_stream->ver_idx].value);
used_len+=length;
@@ -1448,7 +1456,7 @@ int quic_process(struct streaminfo *pstream, struct _quic_context* _context, int
{
_context->is_decrypt=1;
ret=dissect_quic((char *)udp_detail->pdata, udp_detail->datalen, decrypt_payload, &decrypt_payload_len);
if(ret!=1 || decrypt_payload_len>2048 || decrypt_payload_len<0)
if(ret!=1 || decrypt_payload_len>2048 || decrypt_payload_len<=0)
{
return APP_STATE_GIVEME;
}

View File

@@ -132,6 +132,7 @@ typedef struct _quic_packet_info {
guint8 first_byte;
} quic_packet_info_t;
/**
* Given a QUIC message (header + non-empty payload), the actual packet number,
* try to decrypt it using the PP cipher.
@@ -168,7 +169,8 @@ static void quic_decrypt_message(quic_pp_cipher *pp_cipher, const char *payload,
// buffer_length = length - (header_length + 16);
// buffer_length = 297 - (2 + 16);
buffer_length = length - (pkn_len + 16);
if (buffer_length == 0 || buffer_length >1500) {
if (buffer_length == 0 || buffer_length >1500)
{
*error = (const guchar *)"Decryption not possible, ciphertext is too short or too long";
return;
}
@@ -669,10 +671,9 @@ static gboolean quic_create_initial_decoders(const quic_cid_t *cid, const gchar
return TRUE;
}
static int quic_extract_header(const char *payload, unsigned char *long_packet_type, unsigned int *version, quic_cid_t *dcid, quic_cid_t *scid)
static int quic_extract_header(const char *payload, unsigned int payload_len, unsigned char *long_packet_type, unsigned int *version, quic_cid_t *dcid, quic_cid_t *scid)
{
unsigned int offset = 0;
int offset = 0;
unsigned char packet_type = payload[offset];
unsigned char is_long_header = packet_type & 0x80;
if (is_long_header)
@@ -682,7 +683,10 @@ static int quic_extract_header(const char *payload, unsigned char *long_packet_t
// short header form, store dummy value that is not a long packet type.
*long_packet_type = QUIC_SHORT_PACKET;
offset++;
if(offset+6>=(int)payload_len) //verion_lenght: 4 ,scid_length_flag: 1 ,dcid_length_flag: 1
{
return -1;
}
*version = pntoh32((unsigned int *)&payload[offset]);
if (is_long_header) {
@@ -697,16 +701,23 @@ static int quic_extract_header(const char *payload, unsigned char *long_packet_t
// read DCID and SCID (both are prefixed by a length byte).
unsigned char dcil = payload[offset];
offset++;
if(offset+dcil+1>=(int)payload_len) //scid_length_flag: +1
{
return -1;
}
if (dcil && dcil <= QUIC_MAX_CID_LENGTH) {
memcpy(dcid->cid, &payload[offset], dcil);
dcid->len = dcil;
}
offset += dcil;
unsigned char scil = payload[offset];
offset++;
if(offset+scil>=(int)payload_len)
{
return -1;
}
if (scil && scil <= QUIC_MAX_CID_LENGTH) {
memcpy(scid->cid, &payload[offset], scil);
scid->len = scil;
@@ -719,6 +730,10 @@ static int quic_extract_header(const char *payload, unsigned char *long_packet_t
// For short headers, the DCID length is unknown and could be 0 or
// anything from 1 to 20 bytes. Copy the maximum possible and let the
// consumer truncate it as necessary.
if(offset+QUIC_MAX_CID_LENGTH>=(int)payload_len)
{
return -1;
}
memcpy(dcid->cid, &payload[offset], QUIC_MAX_CID_LENGTH);
dcid->len = QUIC_MAX_CID_LENGTH;
offset += QUIC_MAX_CID_LENGTH;
@@ -727,6 +742,16 @@ static int quic_extract_header(const char *payload, unsigned char *long_packet_t
return offset;
}
static void free_quic_cipher(quic_ciphers *initial_ciphers)
{
if(initial_ciphers!=NULL)
{
quic_hp_cipher_reset(&(initial_ciphers->hp_cipher));
quic_pp_cipher_reset(&(initial_ciphers->pp_cipher));
}
}
int dissect_quic(const char *payload, unsigned int length, unsigned char *out, unsigned int *out_length)
{
guint offset = 0;
@@ -739,12 +764,12 @@ int dissect_quic(const char *payload, unsigned int length, unsigned char *out, u
guint8 first_byte = 0;
const gboolean from_server = FALSE;
quic_ciphers *ciphers = NULL;
int ret;
int ret, out_len;
memset(&quic_packet, 0, sizeof(quic_packet_info_t));
memset(&conn, 0, sizeof(quic_info_data_t));
ret = quic_extract_header(payload, &long_packet_type, &conn.version, &dcid, &scid);
ret = quic_extract_header(payload, length, &long_packet_type, &conn.version, &dcid, &scid);
if (ret < 0)
{
return -1;
@@ -760,12 +785,23 @@ int dissect_quic(const char *payload, unsigned int length, unsigned char *out, u
guint32 pkn32 = 0;
// PKN is after type(1) + version(4) + DCIL+DCID + SCIL+SCID
guint pn_offset = 1 + 4 + 1 + dcid.len + 1 + scid.len;
if(pn_offset+8>=length) //tvb_get_varint max: 8
{
free_quic_cipher(&conn.client_initial_ciphers);
free_quic_cipher(&conn.server_initial_ciphers);
return 0;
}
pn_offset += tvb_get_varint(payload, pn_offset, 8, &token_length, ENC_VARINT_QUIC);
pn_offset += (guint)token_length;
// printf("%d\n", token_length);
if(pn_offset+8>=length) //tvb_get_varint max: 8
{
free_quic_cipher(&conn.client_initial_ciphers);
free_quic_cipher(&conn.server_initial_ciphers);
return 0;
}
pn_offset += tvb_get_varint(payload, pn_offset, 8, &payload_length, ENC_VARINT_QUIC);
if(payload_length==0 || payload_length >1500)
if(payload_length==0 || payload_length >length || pn_offset>=length)
{
quic_packet.decryption.error = (const guchar*)"Payload length is too small or too long";
}
@@ -775,8 +811,12 @@ int dissect_quic(const char *payload, unsigned int length, unsigned char *out, u
ciphers = &conn.client_initial_ciphers;
error = "Header deprotection failed";
if (quic_decrypt_header(payload, pn_offset, &ciphers->hp_cipher, GCRY_CIPHER_AES128, &first_byte, &pkn32))
{
error = NULL;
if (!error) {
}
if (!error)
{
quic_set_full_packet_number(&conn, &quic_packet, from_server, first_byte, pkn32);
quic_packet.first_byte = first_byte;
}
@@ -791,8 +831,9 @@ int dissect_quic(const char *payload, unsigned int length, unsigned char *out, u
// Out
if (!quic_packet.decryption.error)
{
memcpy(out, quic_packet.decryption.data, quic_packet.decryption.data_len);
*out_length = quic_packet.decryption.data_len;
out_len=MIN(quic_packet.decryption.data_len, *out_length);
memcpy(out, quic_packet.decryption.data, out_len);
*out_length = out_len;
g_free((gpointer)quic_packet.decryption.data);
quic_packet.decryption.data = NULL;
@@ -804,10 +845,8 @@ int dissect_quic(const char *payload, unsigned int length, unsigned char *out, u
ret=0;
}
quic_hp_cipher_reset(&conn.client_initial_ciphers.hp_cipher);
quic_pp_cipher_reset(&conn.client_initial_ciphers.pp_cipher);
quic_hp_cipher_reset(&conn.server_initial_ciphers.hp_cipher);
quic_pp_cipher_reset(&conn.server_initial_ciphers.pp_cipher);
free_quic_cipher(&conn.client_initial_ciphers);
free_quic_cipher(&conn.server_initial_ciphers);
return ret;
}