Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
07/23/2026 Version 4.5.5
- SECURITY: fix heap buffer over-read in get_layer4_v6() (GHSA-jj65-mrgg-f5fx, CWE-125).
get_ipv6_next() (src/common/get.c) validates the header it is given, but the pointer it
returns is only checked with "ptr > end_ptr" - so it may be exactly end_ptr, or leave
fewer bytes than a tcpr_ipv6_ext_hdr_base needs. get_layer4_v6() then read ip_nh straight
off that pointer, one byte past the packet buffer, for a crafted IPv6 packet whose
extension header chain runs to the end of the captured data. Reachable from tcpprep,
tcprewrite and tcpreplay when reading an untrusted pcap. A bounds check is now applied at
the three sites that dereference such a pointer. This was reported in 2024 against 4.4.4
and marked patched, but the reporter's proof-of-concept still reproduced on 4.5.4.
Reported by msxfXF.
- SECURITY: fix stack buffer overflow in the fragroute rules-file parser
(GHSA-777w-9599-w8g4, CWE-787). On a successful parse, mod_open()
(src/fragroute/mod.c) accumulated a "<mod> -> <mod> -> ..." diagnostic of every parsed
Expand Down
4 changes: 4 additions & 0 deletions docs/CREDIT
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ Gabriel Ganne <GitHub @GabrielGanne>
- tcprewrite: fix vlan tag add silently truncating output when --enet-vlan-pri/-cfi omitted (#994)
- tcpprep: fix buffer overflow in check_dst_port() on truncated L4 headers (#995)

msxfXF <GitHub @msxfXF>
- common: reported heap buffer over-read in get_layer4_v6() when walking IPv6
extension headers (GHSA-jj65-mrgg-f5fx)

tinyb0y <GitHub @tinyb0y>
- fragroute: reported heap buffer overflow in tcp_opt module (GHSA-pfqg-243f-8q25)
- fragroute: reported heap buffer overflow in ip6_opt module (GHSA-2wmf-4p77-784q)
Expand Down
23 changes: 21 additions & 2 deletions src/common/get.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* along with the Tcpreplay Suite. If not, see <http://www.gnu.org/licenses/>.
*/

#include "defines.h"

Check failure on line 21 in src/common/get.c

View workflow job for this annotation

GitHub Actions / cpp-linter

src/common/get.c:21:10 [clang-diagnostic-error]

'defines.h' file not found
#include "config.h"
#include "common.h"
#include <lib/sll.h>
Expand Down Expand Up @@ -624,6 +624,20 @@
return ((void *)ptr);
}

/*
* Is a complete extension-header base (ip_nh + ip_len) readable at hdr?
*
* get_ipv6_next() only guarantees that the pointer it returns is not past
* end_ptr - it may be exactly end_ptr, or leave fewer bytes than the base
* header needs. Any caller that dereferences that pointer has to check first,
* or it reads off the end of the packet buffer.
*/
static inline bool
ipv6_exthdr_fits(const struct tcpr_ipv6_ext_hdr_base *hdr, const u_char *end_ptr)
{
return hdr != NULL && (const u_char *)hdr + sizeof(*hdr) <= end_ptr;
}

/**
* returns a pointer to the layer 4 header which is just beyond the IPv6 header
* and any extension headers or NULL when there is none as in the case of
Expand Down Expand Up @@ -662,7 +676,7 @@
case TCPR_IPV6_NH_HBH:
dbgx(3, "Going deeper due to extension header 0x%02X", proto);
exthdr = get_ipv6_next(next, end_ptr);
if (exthdr == NULL) {
if (!ipv6_exthdr_fits(exthdr, end_ptr)) {
next = NULL;
done = true;
break;
Expand All @@ -678,7 +692,7 @@
// next points to l4 data
dbgx(3, "Go deeper due to fragment extension header 0x%02X", proto);
exthdr = get_ipv6_next(next, end_ptr);
if ((exthdr == NULL) || ((u_char *)exthdr > end_ptr)) {
if (!ipv6_exthdr_fits(exthdr, end_ptr)) {
next = NULL;
done = true;
break;
Expand All @@ -701,6 +715,11 @@
*/
default:
if (proto != ip6_hdr->ip_nh && next) {
/* reading next->ip_len needs the base header to be present */
if (!ipv6_exthdr_fits(next, end_ptr)) {
return NULL;
}

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)
Expand Down
Loading