diff --git a/rpm/libtrace4.spec b/rpm/libtrace4.spec index d9776481..0c7f60a4 100644 --- a/rpm/libtrace4.spec +++ b/rpm/libtrace4.spec @@ -1,18 +1,12 @@ Name: libtrace4 Version: 4.0.32 -Release: 1%{?rhel_release} +Release: 2%{?rhel_release} Summary: C Library for capturing and analysing network packets License: LGPLv3 URL: https://github.com/LibtraceTeam/libtrace Source0: https://github.com/LibtraceTeam/libtrace/archive/%{version}.tar.gz -%define dpdk_version %(pkg-config --modversion libdpdk 2>/dev/null || echo "unknown") -%define dpdk_major %(echo %{dpdk_version} | cut -d. -f1-2) - -%global __requires_exclude ^librte_.*$ -Provides: bundled(dpdk) = %{dpdk_major} - BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: make @@ -28,6 +22,7 @@ BuildRequires: libwandder2-devel >= 2.0.14 BuildRequires: libwandio1-devel BuildRequires: dpdk-devel BuildRequires: (flex-devel or libfl-static) +Requires: dpdk Provides: libtrace4 @@ -42,10 +37,11 @@ University in New Zealand. %package devel Summary: Development files for %{name} Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: dpdk-devel %package tools Summary: Helper utilities for use with the %{name} library -Requires: %{name}%{?_isa} = %{version}-%{release}, libpacketdump4%{?_isa} = %{version}-%{release} +Requires: %{name}%{?_isa} = %{version}-%{release}, libpacketdump4%{?_isa} = %{version}-%{release}, dpdk %package -n libpacketdump4 Summary: Network packet parsing and human-readable display library @@ -132,6 +128,9 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' %changelog +* Wed Jun 3 2026 Shane Alcock - 4.0.32-2 +- Fix broken DPDK dependency + * Thu May 28 2026 Shane Alcock - 4.0.32-1 - Updated for 4.0.32 release diff --git a/rpmpkg-setup.sh b/rpmpkg-setup.sh index df9ac16f..2d4b9569 100755 --- a/rpmpkg-setup.sh +++ b/rpmpkg-setup.sh @@ -12,7 +12,6 @@ dnf config-manager --set-enabled powertools || true dnf module disable -y mariadb || true /usr/bin/crb enable || true - curl -1sLf \ 'https://dl.cloudsmith.io/public/wand/libwandio/cfg/setup/bash.rpm.sh' \ | bash diff --git a/tests/test_invariant_tracereplay.c b/tests/test_invariant_tracereplay.c new file mode 100644 index 00000000..3aa4efc5 --- /dev/null +++ b/tests/test_invariant_tracereplay.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include + +/* We need to test that the memcpy in tracereplay doesn't overflow. + * The vulnerable pattern is: + * newbuf = malloc(sizeof(libtrace_ether_t) + remaining); + * memcpy(newbuf + sizeof(libtrace_ether_t), l2_header, remaining); + * where 'remaining' comes from untrusted packet metadata. + * + * We simulate the allocation logic and check the invariant: + * bytes copied must never exceed (allocated_size - header_size). + */ + +#define LIBTRACE_ETHER_SIZE 14 /* sizeof(libtrace_ether_t) */ +#define MAX_SAFE_PACKET 65535 + +/* Simulates the vulnerable allocation+copy logic from tracereplay.c lines 127-128. + * Returns 0 if safe (no overflow), -1 if overflow would occur. */ +static int check_copy_bounds(uint32_t wire_length, uint32_t capture_length, size_t actual_data_size) +{ + /* In the vulnerable code, 'remaining' is derived from packet metadata (wire_length or cap_length) */ + uint32_t remaining = capture_length; + + /* The allocation in tracereplay: newbuf = malloc(sizeof(libtrace_ether_t) + remaining) */ + size_t alloc_size = LIBTRACE_ETHER_SIZE + remaining; + + /* SECURITY INVARIANT: remaining must not exceed actual_data_size, + * and the copy must not exceed (alloc_size - LIBTRACE_ETHER_SIZE) */ + if (remaining > actual_data_size) { + /* This is the overflow condition - reading beyond l2_header buffer */ + return -1; + } + if (remaining > alloc_size - LIBTRACE_ETHER_SIZE) { + return -1; + } + return 0; +} + +START_TEST(test_buffer_read_bounds) +{ + /* Invariant: Buffer reads never exceed the declared/actual data length */ + struct { + uint32_t wire_len; + uint32_t cap_len; /* attacker-controlled metadata */ + size_t actual_data; /* real data available */ + int expect_safe; /* 0 = safe, -1 = overflow */ + } cases[] = { + /* Exact exploit: cap_len claims 2x actual data */ + { 2000, 2000, 1000, -1 }, + /* Extreme: cap_len claims 10x actual data */ + { 10000, 10000, 1000, -1 }, + /* Boundary: cap_len equals actual data exactly */ + { 1000, 1000, 1000, 0 }, + /* Valid small packet */ + { 64, 64, 64, 0 }, + /* cap_len is UINT32_MAX (integer overflow attempt) */ + { 0xFFFFFFFF, 0xFFFFFFFF, 100, -1 }, + }; + int num_cases = sizeof(cases) / sizeof(cases[0]); + + for (int i = 0; i < num_cases; i++) { + int result = check_copy_bounds(cases[i].wire_len, cases[i].cap_len, cases[i].actual_data); + /* The security invariant: if cap_len > actual_data, it MUST be detected as unsafe */ + if (cases[i].cap_len > cases[i].actual_data) { + ck_assert_msg(result == -1, + "Case %d: overflow not detected (cap_len=%u, actual=%zu)", + i, cases[i].cap_len, cases[i].actual_data); + } else { + ck_assert_msg(result == 0, + "Case %d: false positive (cap_len=%u, actual=%zu)", + i, cases[i].cap_len, cases[i].actual_data); + } + } +} +END_TEST + +Suite *security_suite(void) +{ + Suite *s; + TCase *tc_core; + + s = suite_create("Security"); + tc_core = tcase_create("Core"); + + tcase_add_test(tc_core, test_buffer_read_bounds); + suite_add_tcase(s, tc_core); + + return s; +} + +int main(void) +{ + int number_failed; + Suite *s; + SRunner *sr; + + s = security_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + number_failed = \ No newline at end of file diff --git a/tools/tracereplay/tracereplay.c b/tools/tracereplay/tracereplay.c index 411663aa..e74b02e7 100644 --- a/tools/tracereplay/tracereplay.c +++ b/tools/tracereplay/tracereplay.c @@ -124,7 +124,8 @@ static libtrace_packet_t *per_packet(libtrace_packet_t *packet, char **localbuf) if (linktype == TRACE_TYPE_NONE) { newbuf = calloc(wire_length + sizeof(libtrace_ether_t), sizeof(char)); - memcpy(newbuf + sizeof(libtrace_ether_t), l2_header, remaining); + memcpy(newbuf + sizeof(libtrace_ether_t), l2_header, + remaining < wire_length ? remaining : wire_length); memcpy(newbuf, FAKE_ETHERNET_HEADER, sizeof(libtrace_ether_t)); l2_header = newbuf; wire_length += sizeof(libtrace_ether_t);