libpcap: Fix CVE-2026-18238

NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-18238
Upstream-commit: https://github.com/the-tcpdump-group/libpcap/commit/b9590d482986d64673712460aae1d48d11fa0473

(From OE-Core rev: 940dee79d02890b06b91bb394ba51b933e3a1dbb)

Signed-off-by: Jaipaul Cheernam <jaipaul.cheernam@est.tech>
Signed-off-by: Yoann Congal <yoann.congal@smile.fr>
Signed-off-by: Paul Barker <paul@pbarker.dev>
This commit is contained in:
Jaipaul Cheernam authored and Paul Barker committed 2026-10-19 09:03:19 +01:00
1 parent 358a044360
commit 63f658cb2b
2 files changed
+223

No files matched your search

@@ -0,0 +1,222 @@
From b9590d482986d64673712460aae1d48d11fa0473 Mon Sep 17 00:00:00 2001
From: Denis Ovsienko <denis@ovsienko.info>
Date: Sat, 8 Aug 2026 00:31:10 +0100
Subject: [PATCH] CVE-2026-18238: Fix RPCAP_MSG_PACKET validation.
This vulnerability was originally reported publicly, hence no credit is
given.
When pcap_read_nocb_remote() validates a received message, it does not
verify that there is a complete RPCAP_MSG_PACKET header in the rpcap
general payload, also it uses an incorrect value to validate the length
declared in the RPCAP_MSG_PACKET header. The latter can lead the
protocol client to over-read the message buffer by 20 bytes, which in at
least one scenario can cause a SIGSEGV.
Fix this problem, as well as a potential integer overflow in the UDP
code path on 32-bit architectures. To make message encoding and
validation easier to follow, re-jig a few variables and update comments.
(backported from commit 2d67e814e8d3791a8b508c359f94688c5669cce9)
(cherry picked from commit b9590d482986d64673712460aae1d48d11fa0473)
Notes on backporting to 1.10.4:
- The upstream CHANGES/changelog hunk is not backported.
Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/b9590d482986d64673712460aae1d48d11fa0473]
CVE: CVE-2026-18238
Signed-off-by: Jaipaul Cheernam <jaipaul.cheernam@est.tech>
---
diff --git a/pcap-rpcap.c b/pcap-rpcap.c
index 22fc7363..30fbd6d6 100644
--- a/pcap-rpcap.c
+++ b/pcap-rpcap.c
@@ -388,10 +388,9 @@ rpcap_deseraddr(struct rpcap_sockaddr *sockaddrin, struct sockaddr_storage **soc
static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_char **pkt_data)
{
struct pcap_rpcap *pr = p->priv; /* structure used when doing a remote live capture */
- struct rpcap_header *header; /* general header according to the RPCAP format */
- struct rpcap_pkthdr *net_pkt_header; /* header of the packet, from the message */
+ struct rpcap_header *gen_header; /* rpcap general header */
+ struct rpcap_pkthdr *net_pkt_header; /* RPCAP_MSG_PACKET header */
u_char *net_pkt_data; /* packet data from the message */
- uint32 plen;
int retval = 0; /* generic return value */
int msglen;
@@ -448,13 +447,35 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
return 0;
/*
- * We have to define 'header' as a pointer to a larger buffer,
- * because in case of UDP we have to read all the message within a single call
+ * pcap_startcapture_remote() has pointed p->buffer to a buffer large
+ * enough to contain all of the following data at once:
+ *
+ * - a fixed-size rpcap general header
+ * - a fixed-size RPCAP_MSG_PACKET header
+ * - p->snapshot worth of bytes of a captured packet
+ *
+ * This is sufficient for all code paths below.
*/
- header = (struct rpcap_header *) p->buffer;
+ gen_header = (struct rpcap_header *)p->buffer;
net_pkt_header = (struct rpcap_pkthdr *) ((char *)p->buffer + sizeof(struct rpcap_header));
net_pkt_data = (u_char *)p->buffer + sizeof(struct rpcap_header) + sizeof(struct rpcap_pkthdr);
+ /*
+ * Step 1: to receive a message that does not immediately look
+ * malformed, consider it as a fixed-size rpcap general header followed
+ * by a variable-size rpcap general payload and require:
+ *
+ * - a complete rpcap general header to land in the buffer, and
+ * - the header to declare an rpcap general payload length that fits
+ * in the buffer after the header, and
+ * - the complete declared payload to land in the buffer after the
+ * header.
+ *
+ * Since this step loosely corresponds to rpcap_process_msg_header(),
+ * which among other things converts rpcap_header.plen to host byte
+ * order, mimic that as well to produce a valid argument for
+ * rpcap_check_msg_ver() later on.
+ */
if (pr->rmt_flags & PCAP_OPENFLAG_DATATX_UDP)
{
/* Read the entire message from the network */
@@ -470,6 +491,8 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
/* Interrupted receive. */
return 0;
}
+
+ // Require a complete rpcap general header to be present.
if ((size_t)msglen < sizeof(struct rpcap_header))
{
/*
@@ -479,8 +502,18 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
"UDP packet message is shorter than an rpcap header");
return -1;
}
- plen = ntohl(header->plen);
- if ((size_t)msglen < sizeof(struct rpcap_header) + plen)
+ gen_header->plen = ntohl(gen_header->plen);
+
+ /*
+ * Validate the rpcap general payload length declared in the
+ * rpcap general header. Use subtraction to avoid an integer
+ * overflow:
+ *
+ * 0 <= gen_header->plen <= UINT32_MAX
+ * sizeof(struct rpcap_header) <= msglen <= p->bufsize
+ * p->bufsize is significantly less than UINT32_MAX
+ */
+ if (gen_header->plen > (size_t)msglen - sizeof(struct rpcap_header))
{
/*
* Message is shorter than the header claims it
@@ -495,6 +528,7 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
{
int status;
+ // Receive a complete rpcap general header from the network.
if ((size_t)p->cc < sizeof(struct rpcap_header))
{
/*
@@ -514,27 +548,35 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
return 0;
}
}
+ gen_header->plen = ntohl(gen_header->plen);
/*
- * We have the header, so we know how long the
- * message payload is. The size we should get
- * is the size of the packet header plus the
- * size of the payload.
+ * Validate the rpcap general payload length declared in the
+ * rpcap general header. Use subtraction to avoid an integer
+ * overflow:
+ *
+ * 0 <= gen_header->plen <= UINT32_MAX
+ * sizeof(struct rpcap_header) < p->bufsize
+ * p->bufsize is significantly less than UINT32_MAX
*/
- plen = ntohl(header->plen);
- if (plen > p->bufsize - sizeof(struct rpcap_header))
+ if (gen_header->plen > p->bufsize - sizeof(struct rpcap_header))
{
/*
* This is bigger than the largest
- * record we'd expect. (We do it by
- * subtracting in order to avoid an
- * overflow.)
+ * record we'd expect.
*/
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Server sent us a message larger than the largest expected packet message");
return -1;
}
- status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header) + plen);
+
+ /*
+ * Receive the declared rpcap general payload from the network.
+ *
+ * p->cc == sizeof(struct rpcap_header)
+ * p->bp == p->buffer + sizeof(struct rpcap_header)
+ */
+ status = rpcap_read_packet_msg(pr, p, sizeof(struct rpcap_header) + gen_header->plen);
if (status == -1)
{
/* Network error. */
@@ -557,27 +599,36 @@ static int pcap_read_nocb_remote(pcap_t *p, struct pcap_pkthdr *pkt_header, u_ch
/*
* We have the entire message.
- */
- header->plen = plen;
-
- /*
- * Did the server specify the version we negotiated?
+ * Step 2: to validate the received message further, require:
+ *
+ * - the rpcap general header to have the correct version and type, and
+ * - the rpcap general payload to be large enough to contain at least a
+ * complete RPCAP_MSG_PACKET header, and
+ * - the RPCAP_MSG_PACKET header to declare an RPCAP_MSG_PACKET payload
+ * (i.e. the captured packet) length that fits in the rpcap general
+ * payload (not the entire buffer) after the RPCAP_MSG_PACKET header.
*/
if (rpcap_check_msg_ver(pr->rmt_sockdata, pr->data_ssl, pr->protocol_version,
- header, p->errbuf) == -1)
- {
+ gen_header, p->errbuf) == -1)
+ return 0; /* Return 'no packets received' */
+ if (gen_header->type != RPCAP_MSG_PACKET)
return 0; /* Return 'no packets received' */
+ if (gen_header->plen < sizeof(struct rpcap_pkthdr))
+ {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "Received an incomplete RPCAP_MSG_PACKET header.");
+ return -1;
}
-
/*
- * Is this a RPCAP_MSG_PACKET message?
+ * Validate the RPCAP_MSG_PACKET payload length declared in the
+ * RPCAP_MSG_PACKET header. Use subtraction to avoid an integer
+ * overflow:
+ *
+ * 0 <= ntohl(net_pkt_header->caplen) <= UINT32_MAX
+ * sizeof(struct rpcap_pkthdr) <= gen_header->plen
+ * gen_header->plen is significantly less than UINT32_MAX
*/
- if (header->type != RPCAP_MSG_PACKET)
- {
- return 0; /* Return 'no packets received' */
- }
-
- if (ntohl(net_pkt_header->caplen) > plen)
+ if (ntohl(net_pkt_header->caplen) > gen_header->plen - sizeof(struct rpcap_pkthdr))
{
snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
"Packet's captured data goes past the end of the received packet message.");
@@ -23,6 +23,7 @@ SRC_URI = "https://www.tcpdump.org/release/${BP}.tar.gz \
file://04-CVE-2026-6244.patch \
file://05-CVE-2026-6554.patch \
file://06-CVE-2026-18313.patch \
file://07-CVE-2026-18238.patch \
"
SRC_URI[sha256sum] = "ed19a0383fad72e3ad435fd239d7cd80d64916b87269550159d20e47160ebe5f"