Fix segfault in parse_quic_decrypted

This commit is contained in:
Vadim Vetrov
2025-01-06 19:04:44 +03:00
parent 40e1101d68
commit 1b62bb6cb2
3 changed files with 73 additions and 30 deletions

View File

@@ -109,11 +109,11 @@ int quic_parse_data(const uint8_t *raw_payload, uint32_t raw_payload_len,
int64_t qversion = quic_get_version(nqch); int64_t qversion = quic_get_version(nqch);
if (qversion < 0) { if (qversion < 0) {
lgtrace_addp("quic version undefined %ld", -qversion); lgtrace_addp("quic version undefined %u", (uint32_t)(-qversion));
return -EPROTO; return -EPROTO;
} }
lgtrace_addp("quic version valid %ld", qversion); lgtrace_addp("quic version valid %u", (uint32_t)qversion);
if (left_len < 2) goto invalid_packet; if (left_len < 2) goto invalid_packet;
struct quic_cids nqci = {0}; struct quic_cids nqci = {0};
@@ -336,9 +336,10 @@ int gen_fake_udp(struct udp_fake_type type,
return 0; return 0;
} }
struct tls_verdict parse_quic_decrypted( int parse_quic_decrypted(
const struct section_config_t *section, const struct section_config_t *section,
const uint8_t *decrypted_message, uint32_t decrypted_message_len const uint8_t *decrypted_message, uint32_t decrypted_message_len,
uint8_t **crypto_message_buf, uint32_t *crypto_message_buf_len
) { ) {
const uint8_t *curptr = decrypted_message; const uint8_t *curptr = decrypted_message;
ssize_t curptr_len = decrypted_message_len; ssize_t curptr_len = decrypted_message_len;
@@ -350,7 +351,7 @@ struct tls_verdict parse_quic_decrypted(
uint8_t *crypto_message = calloc(AVAILABLE_MTU, 1); uint8_t *crypto_message = calloc(AVAILABLE_MTU, 1);
if (crypto_message == NULL) { if (crypto_message == NULL) {
lgerror(-ENOMEM, "No memory"); lgerror(-ENOMEM, "No memory");
return tlsv; return -ENOMEM;
} }
int crypto_message_len = AVAILABLE_MTU; int crypto_message_len = AVAILABLE_MTU;
@@ -371,7 +372,7 @@ pl_incr:
break; break;
case QUIC_FRAME_CRYPTO: case QUIC_FRAME_CRYPTO:
fret = quic_parse_crypto(&fr_cr, curptr, curptr_len); fret = quic_parse_crypto(&fr_cr, curptr, curptr_len);
lgtrace_addp("crypto %lu", fr_cr.offset); lgtrace_addp("crypto %d %d %d", (int)fr_cr.offset, (int)fr_cr.payload_length, (int)fret);
if (fret < 0) if (fret < 0)
break; break;
curptr += fret; curptr += fret;
@@ -391,16 +392,10 @@ pl_incr:
} }
out: out:
if (section->sni_detection == SNI_DETECTION_BRUTE) { *crypto_message_buf = crypto_message;
ret = bruteforce_analyze_sni_str(section, crypto_message, crypto_message_len, &tlsv); *crypto_message_buf_len = crypto_message_len;
} else {
ret = analyze_tls_message(
section, crypto_message, crypto_message_len, &tlsv
);
}
free(crypto_message); return 0;
return tlsv;
} }
int detect_udp_filtered(const struct section_config_t *section, int detect_udp_filtered(const struct section_config_t *section,
@@ -461,6 +456,8 @@ int detect_udp_filtered(const struct section_config_t *section,
uint32_t decrypted_payload_len; uint32_t decrypted_payload_len;
const uint8_t *decrypted_message; const uint8_t *decrypted_message;
uint32_t decrypted_message_len; uint32_t decrypted_message_len;
uint8_t *crypto_message;
uint32_t crypto_message_len;
struct tls_verdict tlsv; struct tls_verdict tlsv;
ret = quic_parse_initial_message( ret = quic_parse_initial_message(
@@ -473,9 +470,24 @@ int detect_udp_filtered(const struct section_config_t *section,
goto match_port; goto match_port;
} }
tlsv = parse_quic_decrypted(section, ret = parse_quic_decrypted(section,
decrypted_message, decrypted_message_len decrypted_message, decrypted_message_len,
&crypto_message, &crypto_message_len
); );
free(decrypted_payload);
decrypted_payload = NULL;
if (ret < 0) {
goto match_port;
}
if (section->sni_detection == SNI_DETECTION_BRUTE) {
ret = bruteforce_analyze_sni_str(section, crypto_message, crypto_message_len, &tlsv);
} else {
ret = analyze_tls_message(
section, crypto_message, crypto_message_len, &tlsv
);
}
if (tlsv.sni_len != 0) { if (tlsv.sni_len != 0) {
lgtrace_addp("QUIC SNI detected: %.*s", tlsv.sni_len, tlsv.sni_ptr); lgtrace_addp("QUIC SNI detected: %.*s", tlsv.sni_len, tlsv.sni_ptr);
@@ -483,11 +495,13 @@ int detect_udp_filtered(const struct section_config_t *section,
if (tlsv.target_sni) { if (tlsv.target_sni) {
lgdebugmsg("QUIC target SNI detected: %.*s", tlsv.sni_len, tlsv.sni_ptr); lgdebugmsg("QUIC target SNI detected: %.*s", tlsv.sni_len, tlsv.sni_ptr);
free(decrypted_payload); free(crypto_message);
crypto_message = NULL;
goto approve; goto approve;
} }
free(decrypted_payload); free(crypto_message);
crypto_message = NULL;
} }
match_port: match_port:

View File

@@ -221,11 +221,14 @@ int quic_parse_initial_message(
); );
/** /**
* Like analyze_tls_data for QUIC * CRYPTO frames may be randomly spried in the message.
* This function _allocates_ crypto_message_buf and fills it with CRYPTO frames
* according to offset and payload_length
*/ */
struct tls_verdict parse_quic_decrypted( int parse_quic_decrypted(
const struct section_config_t *section, const struct section_config_t *section,
const uint8_t *decrypted_message, uint32_t decrypted_message_len const uint8_t *decrypted_message, uint32_t decrypted_message_len,
uint8_t **crypto_message_buf, uint32_t *crypto_message_buf_len
); );
// Like fail_packet for TCP // Like fail_packet for TCP

View File

@@ -141,11 +141,15 @@ TEST(QuicTest, Test_varlength_parser)
TEST(QuicTest, Test_parse_quic_decrypted) TEST(QuicTest, Test_parse_quic_decrypted)
{ {
#undef free
int ret; int ret;
uint8_t *decrypted_payload; uint8_t *decrypted_payload;
uint32_t decrypted_payload_len; uint32_t decrypted_payload_len;
const uint8_t *decrypted_message; const uint8_t *decrypted_message;
uint32_t decrypted_message_len; uint32_t decrypted_message_len;
uint8_t *crypto_message;
uint32_t crypto_message_len;
struct tls_verdict tlsv = {0}; struct tls_verdict tlsv = {0};
ret = quic_parse_initial_message( ret = quic_parse_initial_message(
@@ -153,22 +157,35 @@ TEST(QuicTest, Test_parse_quic_decrypted)
&decrypted_payload, &decrypted_payload_len, &decrypted_payload, &decrypted_payload_len,
&decrypted_message, &decrypted_message_len &decrypted_message, &decrypted_message_len
); );
TEST_ASSERT_EQUAL(ret, 0); TEST_ASSERT_EQUAL(0, ret);
tlsv = parse_quic_decrypted(&sconf, decrypted_message, decrypted_message_len); ret = parse_quic_decrypted(
TEST_ASSERT_EQUAL_STRING_LEN("example.com", tlsv.sni_ptr, 11); &sconf, decrypted_message, decrypted_message_len,
#undef free &crypto_message, &crypto_message_len);
TEST_ASSERT_EQUAL(0, ret);
free(decrypted_payload); free(decrypted_payload);
decrypted_payload = NULL;
ret = analyze_tls_message(
&sconf, crypto_message, crypto_message_len, &tlsv
);
TEST_ASSERT_EQUAL_STRING_LEN("example.com", tlsv.sni_ptr, 11);
free(crypto_message);
#define free unity_free #define free unity_free
} }
TEST(QuicTest, Test_parse_quic_decrypted_on_sparse) TEST(QuicTest, Test_parse_quic_decrypted_on_sparse)
{ {
#undef free
int ret; int ret;
uint8_t *decrypted_payload; uint8_t *decrypted_payload;
uint32_t decrypted_payload_len; uint32_t decrypted_payload_len;
const uint8_t *decrypted_message; const uint8_t *decrypted_message;
uint32_t decrypted_message_len; uint32_t decrypted_message_len;
uint8_t *crypto_message;
uint32_t crypto_message_len;
struct tls_verdict tlsv = {0}; struct tls_verdict tlsv = {0};
ret = quic_parse_initial_message( ret = quic_parse_initial_message(
@@ -176,13 +193,22 @@ TEST(QuicTest, Test_parse_quic_decrypted_on_sparse)
&decrypted_payload, &decrypted_payload_len, &decrypted_payload, &decrypted_payload_len,
&decrypted_message, &decrypted_message_len &decrypted_message, &decrypted_message_len
); );
TEST_ASSERT_EQUAL(ret, 0); TEST_ASSERT_EQUAL(0, ret);
tlsv = parse_quic_decrypted(&sconf, decrypted_message, decrypted_message_len); ret = parse_quic_decrypted(
&sconf, decrypted_message, decrypted_message_len,
&crypto_message, &crypto_message_len);
TEST_ASSERT_EQUAL(0, ret);
free(decrypted_payload);
decrypted_payload = NULL;
ret = analyze_tls_message(
&sconf, crypto_message, crypto_message_len, &tlsv
);
TEST_ASSERT_EQUAL(19, tlsv.sni_len); TEST_ASSERT_EQUAL(19, tlsv.sni_len);
TEST_ASSERT_EQUAL_STRING_LEN("ipm.adblockplus.dev", tlsv.sni_ptr, 19); TEST_ASSERT_EQUAL_STRING_LEN("ipm.adblockplus.dev", tlsv.sni_ptr, 19);
#undef free free(crypto_message);
free(decrypted_payload);
#define free unity_free #define free unity_free
} }