From 5b5644356693f5c68dd4295e86f24f1d0a515d60 Mon Sep 17 00:00:00 2001
From: Fred Klassen <fred.klassen@broadcom.com>
Date: Sat, 1 Jun 2024 11:46:10 -0700
Subject: [PATCH 1/2] Bug #827 PR# 842: add check for IPv6 extension header
 length

CVE: CVE-2024-22654

Upstream-Status: Backport [https://github.com/appneta/tcpreplay/commit/5b5644356693f5c68dd4295e86f24f1d0a515d60]

Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
---
 src/common/get.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/src/common/get.c b/src/common/get.c
index 2d91116..89fe95b 100644
--- a/src/common/get.c
+++ b/src/common/get.c
@@ -41,8 +41,8 @@ extern const char pcap_version[];
 static void *get_ipv6_next(struct tcpr_ipv6_ext_hdr_base *exthdr, const u_char *end_ptr);
 
 /**
- * Depending on what version of libpcap/WinPcap there are different ways to get
- * the version of the libpcap/WinPcap library.  This presents a unified way to
+ * Depending on what version of libpcap there are different ways to get
+ * the version of the libpcap library.  This presents a unified way to
  * get that information.
  */
 const char *
@@ -196,8 +196,15 @@ parse_metadata(const u_char *pktdata,
                uint32_t *vlan_offset)
 {
     bool done = false;
-    int res = 0;
-    while (!done && res == 0) {
+    assert(next_protocol);
+    assert(l2len);
+    assert(l2offset);
+    assert(vlan_offset);
+
+    if (!pktdata || !datalen)
+        errx(-1, "parse_metadata: invalid L2 parameters: pktdata=0x%p len=%d", pktdata, datalen);
+
+    while (!done) {
         switch (*next_protocol) {
         case ETHERTYPE_VLAN:
         case ETHERTYPE_Q_IN_Q:
@@ -205,18 +212,22 @@ parse_metadata(const u_char *pktdata,
             if (*vlan_offset == 0)
                 *vlan_offset = *l2len;
 
-            res = parse_vlan(pktdata, datalen, next_protocol, l2len);
+            if (parse_vlan(pktdata, datalen, next_protocol, l2len))
+                return -1;
+
             break;
         case ETHERTYPE_MPLS:
         case ETHERTYPE_MPLS_MULTI:
-            res = parse_mpls(pktdata, datalen, next_protocol, l2len, l2offset);
+            if (parse_mpls(pktdata, datalen, next_protocol, l2len, l2offset))
+                return -1;
+
             break;
         default:
             done = true;
         }
     }
 
-    return res;
+    return 0;
 }
 
 /*
@@ -605,9 +616,11 @@ get_layer4_v6(const ipv6_hdr_t *ip6_hdr, const u_char *end_ptr)
          * no further processing, either TCP, UDP, ICMP, etc...
          */
         default:
-            if (proto != ip6_hdr->ip_nh) {
+            if (proto != ip6_hdr->ip_nh && next) {
                 dbgx(3, "Returning byte offset of this ext header: %u", IPV6_EXTLEN_TO_BYTES(next->ip_len));
                 next = (void *)((u_char *)next + IPV6_EXTLEN_TO_BYTES(next->ip_len));
+                if ((u_char*)next > end_ptr)
+                    return NULL;
             } else {
                 dbgx(3, "%s", "Returning end of IPv6 Header");
             }
-- 
2.40.0

