Skip to content

Commit 11a09c7

Browse files
committed
proto_hep: validate HEPv3 chunk lengths
Reject malformed HEPv3 packet and chunk lengths before parsing chunk-specific data. This prevents zero-length chunks from stalling the parser loop and avoids length underflow while walking the advertised packet body. Reported-by: Haruto Kimura (Stella) (cherry picked from commit 41756b8a77cdf69bc3aaeb8e88b734a7fa87a26e)
1 parent 784938e commit 11a09c7

1 file changed

Lines changed: 74 additions & 5 deletions

File tree

modules/proto_hep/hep.c

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -245,13 +245,22 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
245245
_len -= _off; \
246246
} while (0);
247247

248+
#define CHECK_CHUNK_SIZE(_len, _type) \
249+
do { \
250+
if ((_len) != sizeof(_type)) { \
251+
LM_ERR("invalid HEPv3 chunk %u length %u, expected %zu\n", \
252+
chunk_id, (unsigned int)(_len), sizeof(_type)); \
253+
goto error; \
254+
} \
255+
} while (0);
256+
248257
int rc;
249258

250259
unsigned char *compressed_payload;
251260
unsigned long compress_len;
252261

253262
struct hepv3 h3;
254-
unsigned short tlen;
263+
unsigned short tlen, chunk_len;
255264
unsigned long decompress_len;
256265

257266
generic_chunk_t* gen_chunk, *it;
@@ -263,19 +272,44 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
263272

264273
h->version = 3;
265274

275+
if (len < sizeof(hep_ctrl_t)) {
276+
LM_ERR("invalid HEPv3 packet length %d\n", len);
277+
return -1;
278+
}
279+
266280
tlen = ntohs(((hep_ctrl_t*)buf)->length);
281+
if (tlen < sizeof(hep_ctrl_t) || tlen > len) {
282+
LM_ERR("invalid HEPv3 advertised length %u for packet length %d\n",
283+
(unsigned int)tlen, len);
284+
return -1;
285+
}
267286

268287
buf += sizeof(hep_ctrl_t);
269288
tlen -= sizeof(hep_ctrl_t);
270289

271290
memset( &h3, 0, sizeof(struct hepv3));
272291

273292
while (tlen > 0) {
293+
if (tlen < sizeof(hep_chunk_t)) {
294+
LM_ERR("truncated HEPv3 chunk header, remaining length %u\n",
295+
(unsigned int)tlen);
296+
goto error;
297+
}
298+
274299
/* we don't look at vendor id; we only need to parse the buffer */
275-
chunk_id = ((hep_chunk_t*)buf)->type_id;
300+
chunk_id = ntohs(((hep_chunk_t*)buf)->type_id);
301+
chunk_len = ntohs(((hep_chunk_t*)buf)->length);
302+
303+
if (chunk_len < sizeof(hep_chunk_t) || chunk_len > tlen) {
304+
LM_ERR("invalid HEPv3 chunk %u length %u, remaining length %u\n",
305+
chunk_id, (unsigned int)chunk_len, (unsigned int)tlen);
306+
goto error;
307+
}
276308

277-
switch (ntohs(chunk_id)) {
309+
switch (chunk_id) {
278310
case HEP_PROTO_FAMILY:
311+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_uint8_t);
312+
279313
/* ip family*/
280314
h3.hg.ip_family = *((hep_chunk_uint8_t*)buf);
281315

@@ -284,6 +318,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
284318

285319
break;
286320
case HEP_PROTO_ID:
321+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_uint8_t);
322+
287323
/* ip protocol ID*/
288324
h3.hg.ip_proto = *((hep_chunk_uint8_t*)buf);
289325

@@ -292,6 +328,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
292328

293329
break;
294330
case HEP_IPV4_SRC:
331+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_ip4_t);
332+
295333
/* ipv4 source */
296334
h3.addr.ip4_addr.src_ip4 = *((hep_chunk_ip4_t*)buf);
297335

@@ -300,6 +338,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
300338

301339
break;
302340
case HEP_IPV4_DST:
341+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_ip4_t);
342+
303343
/* ipv4 dest */
304344
h3.addr.ip4_addr.dst_ip4 = *((hep_chunk_ip4_t*)buf);
305345

@@ -308,6 +348,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
308348

309349
break;
310350
case HEP_IPV6_SRC:
351+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_ip6_t);
352+
311353
/* ipv6 source */
312354
h3.addr.ip6_addr.src_ip6 = *((hep_chunk_ip6_t*)buf);
313355

@@ -316,6 +358,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
316358

317359
break;
318360
case HEP_IPV6_DST:
361+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_ip6_t);
362+
319363
/* ipv6 dest */
320364
h3.addr.ip6_addr.dst_ip6 = *((hep_chunk_ip6_t*)buf);
321365

@@ -324,6 +368,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
324368

325369
break;
326370
case HEP_SRC_PORT:
371+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_uint16_t);
372+
327373
/* source port */
328374
h3.hg.src_port = *((hep_chunk_uint16_t*)buf);
329375

@@ -334,6 +380,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
334380

335381
break;
336382
case HEP_DST_PORT:
383+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_uint16_t);
384+
337385
/* dest port */
338386
h3.hg.dst_port = *((hep_chunk_uint16_t*)buf);
339387

@@ -344,6 +392,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
344392

345393
break;
346394
case HEP_TIMESTAMP:
395+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_uint32_t);
396+
347397
/* timestamp */
348398
h3.hg.time_sec = *((hep_chunk_uint32_t*)buf);
349399

@@ -354,6 +404,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
354404

355405
break;
356406
case HEP_TIMESTAMP_US:
407+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_uint32_t);
408+
357409
/* timestamp microsecs offset */
358410
h3.hg.time_usec = *((hep_chunk_uint32_t*)buf);
359411

@@ -364,6 +416,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
364416

365417
break;
366418
case HEP_PROTO_TYPE:
419+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_uint8_t);
420+
367421
/* proto type */
368422
h3.hg.proto_t = *((hep_chunk_uint8_t*)buf);
369423

@@ -372,6 +426,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
372426

373427
break;
374428
case HEP_AGENT_ID:
429+
CHECK_CHUNK_SIZE(chunk_len, hep_chunk_uint32_t);
430+
375431
/* capture agent id */
376432
h3.hg.capt_id = *((hep_chunk_uint32_t*)buf);
377433

@@ -426,7 +482,7 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
426482
* locking will be required */
427483
if ((gen_chunk = shm_malloc(sizeof(generic_chunk_t)))==NULL) {
428484
LM_ERR("no more pkg mem!\n");
429-
return -1;
485+
goto error;
430486
}
431487

432488
memset(gen_chunk, 0, sizeof(generic_chunk_t));
@@ -439,7 +495,8 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
439495

440496
if (gen_chunk->data == NULL) {
441497
LM_ERR("no more shared memory!\n");
442-
return -1;
498+
shm_free(gen_chunk);
499+
goto error;
443500
}
444501

445502
memcpy(gen_chunk->data, (char *)buf + sizeof(hep_chunk_t),
@@ -463,6 +520,18 @@ int unpack_hepv3(char *buf, int len, struct hep_desc *h)
463520
h->u.hepv3 = h3;
464521

465522
return 0;
523+
524+
error:
525+
while (h3.chunk_list) {
526+
it = h3.chunk_list;
527+
h3.chunk_list = it->next;
528+
shm_free(it->data);
529+
shm_free(it);
530+
}
531+
if (decompressed_payload.s)
532+
pkg_free(decompressed_payload.s);
533+
#undef CHECK_CHUNK_SIZE
534+
return -1;
466535
}
467536

468537
static int

0 commit comments

Comments
 (0)