summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Marko <peter.marko@siemens.com>2026-01-02 14:32:52 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2026-01-26 09:49:25 +0000
commita12f1208317b637c57f5b7a97bda92034fb90ac3 (patch)
tree838449baac993d506025da97b55cfa3833033072
parent4c8419bebefe1b686166ab08d891cdc4d29257d5 (diff)
downloadpoky-a12f1208317b637c57f5b7a97bda92034fb90ac3.tar.gz
libpcap: patch CVE-2025-11961
Pick patch per [1]. Also pick additional preparation patch to apply it cleanly. [1] https://nvd.nist.gov/vuln/detail/CVE-2025-11961 (From OE-Core rev: 714fb7c711b414407598e3a94b0600fe7f857e38) Signed-off-by: Peter Marko <peter.marko@siemens.com> Signed-off-by: Yoann Congal <yoann.congal@smile.fr> Signed-off-by: Paul Barker <paul@pbarker.dev> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch38
-rw-r--r--meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch433
-rw-r--r--meta/recipes-connectivity/libpcap/libpcap_1.10.1.bb2
3 files changed, 473 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch
new file mode 100644
index 0000000000..73c3ab3f5c
--- /dev/null
+++ b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch
@@ -0,0 +1,38 @@
1From 7224be0fe2f4beb916b7b69141f478facd0f0634 Mon Sep 17 00:00:00 2001
2From: Denis Ovsienko <denis@ovsienko.info>
3Date: Sat, 27 Dec 2025 21:36:11 +0000
4Subject: [PATCH] Rename one of the xdtoi() copies to simplify backporting.
5
6CVE: CVE-2025-11961
7Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/7224be0fe2f4beb916b7b69141f478facd0f0634]
8Signed-off-by: Peter Marko <peter.marko@siemens.com>
9---
10 nametoaddr.c | 6 +++---
11 1 file changed, 3 insertions(+), 3 deletions(-)
12
13diff --git a/nametoaddr.c b/nametoaddr.c
14index dc75495c..bdaacbf1 100644
15--- a/nametoaddr.c
16+++ b/nametoaddr.c
17@@ -646,7 +646,7 @@ pcap_nametollc(const char *s)
18
19 /* Hex digit to 8-bit unsigned integer. */
20 static inline u_char
21-xdtoi(u_char c)
22+pcapint_xdtoi(u_char c)
23 {
24 if (c >= '0' && c <= '9')
25 return (u_char)(c - '0');
26@@ -728,10 +728,10 @@ pcap_ether_aton(const char *s)
27 while (*s) {
28 if (*s == ':' || *s == '.' || *s == '-')
29 s += 1;
30- d = xdtoi(*s++);
31+ d = pcapint_xdtoi(*s++);
32 if (PCAP_ISXDIGIT(*s)) {
33 d <<= 4;
34- d |= xdtoi(*s++);
35+ d |= pcapint_xdtoi(*s++);
36 }
37 *ep++ = d;
38 }
diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch
new file mode 100644
index 0000000000..0b0dc5ac40
--- /dev/null
+++ b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch
@@ -0,0 +1,433 @@
1From b2d2f9a9a0581c40780bde509f7cc715920f1c02 Mon Sep 17 00:00:00 2001
2From: Denis Ovsienko <denis@ovsienko.info>
3Date: Fri, 19 Dec 2025 17:31:13 +0000
4Subject: [PATCH] CVE-2025-11961: Fix OOBR and OOBW in pcap_ether_aton().
5
6pcap_ether_aton() has for a long time required its string argument to be
7a well-formed MAC-48 address, which is always the case when the argument
8comes from other libpcap code, so the function has never validated the
9input and used a simple loop to parse any of the three common MAC-48
10address formats. However, the function has also been a part of the
11public API, so calling it directly with a malformed address can cause
12the loop to read beyond the end of the input string and/or to write
13beyond the end of the allocated output buffer.
14
15To handle invalid input more appropriately, replace the simple loop with
16new functions and require the input to match a supported address format.
17
18This problem was reported by Jin Wei, Kunwei Qian and Ping Chen.
19
20(backported from commit dd08e53e9380e217ae7c7768da9cc3d7bf37bf83)
21
22CVE: CVE-2025-11961
23Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/b2d2f9a9a0581c40780bde509f7cc715920f1c02]
24Signed-off-by: Peter Marko <peter.marko@siemens.com>
25---
26 gencode.c | 5 +
27 nametoaddr.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++----
28 2 files changed, 349 insertions(+), 23 deletions(-)
29
30diff --git a/gencode.c b/gencode.c
31index 3ddd15f8..76fb2d82 100644
32--- a/gencode.c
33+++ b/gencode.c
34@@ -7206,6 +7206,11 @@ gen_ecode(compiler_state_t *cstate, const char *s, struct qual q)
35 return (NULL);
36
37 if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) {
38+ /*
39+ * Because the lexer guards the input string format, in this
40+ * context the function returns NULL iff the implicit malloc()
41+ * has failed.
42+ */
43 cstate->e = pcap_ether_aton(s);
44 if (cstate->e == NULL)
45 bpf_error(cstate, "malloc");
46diff --git a/nametoaddr.c b/nametoaddr.c
47index f9fcd288..f50d0da5 100644
48--- a/nametoaddr.c
49+++ b/nametoaddr.c
50@@ -703,39 +703,360 @@ __pcap_atodn(const char *s, bpf_u_int32 *addr)
51 return(32);
52 }
53
54+// Man page: "xxxxxxxxxxxx", regexp: "^[0-9a-fA-F]{12}$".
55+static u_char
56+pcapint_atomac48_xxxxxxxxxxxx(const char *s, uint8_t *addr)
57+{
58+ if (strlen(s) == 12 &&
59+ PCAP_ISXDIGIT(s[0]) &&
60+ PCAP_ISXDIGIT(s[1]) &&
61+ PCAP_ISXDIGIT(s[2]) &&
62+ PCAP_ISXDIGIT(s[3]) &&
63+ PCAP_ISXDIGIT(s[4]) &&
64+ PCAP_ISXDIGIT(s[5]) &&
65+ PCAP_ISXDIGIT(s[6]) &&
66+ PCAP_ISXDIGIT(s[7]) &&
67+ PCAP_ISXDIGIT(s[8]) &&
68+ PCAP_ISXDIGIT(s[9]) &&
69+ PCAP_ISXDIGIT(s[10]) &&
70+ PCAP_ISXDIGIT(s[11])) {
71+ addr[0] = pcapint_xdtoi(s[0]) << 4 | pcapint_xdtoi(s[1]);
72+ addr[1] = pcapint_xdtoi(s[2]) << 4 | pcapint_xdtoi(s[3]);
73+ addr[2] = pcapint_xdtoi(s[4]) << 4 | pcapint_xdtoi(s[5]);
74+ addr[3] = pcapint_xdtoi(s[6]) << 4 | pcapint_xdtoi(s[7]);
75+ addr[4] = pcapint_xdtoi(s[8]) << 4 | pcapint_xdtoi(s[9]);
76+ addr[5] = pcapint_xdtoi(s[10]) << 4 | pcapint_xdtoi(s[11]);
77+ return 1;
78+ }
79+ return 0;
80+}
81+
82+// Man page: "xxxx.xxxx.xxxx", regexp: "^[0-9a-fA-F]{4}(\.[0-9a-fA-F]{4}){2}$".
83+static u_char
84+pcapint_atomac48_xxxx_3_times(const char *s, uint8_t *addr)
85+{
86+ const char sep = '.';
87+ if (strlen(s) == 14 &&
88+ PCAP_ISXDIGIT(s[0]) &&
89+ PCAP_ISXDIGIT(s[1]) &&
90+ PCAP_ISXDIGIT(s[2]) &&
91+ PCAP_ISXDIGIT(s[3]) &&
92+ s[4] == sep &&
93+ PCAP_ISXDIGIT(s[5]) &&
94+ PCAP_ISXDIGIT(s[6]) &&
95+ PCAP_ISXDIGIT(s[7]) &&
96+ PCAP_ISXDIGIT(s[8]) &&
97+ s[9] == sep &&
98+ PCAP_ISXDIGIT(s[10]) &&
99+ PCAP_ISXDIGIT(s[11]) &&
100+ PCAP_ISXDIGIT(s[12]) &&
101+ PCAP_ISXDIGIT(s[13])) {
102+ addr[0] = pcapint_xdtoi(s[0]) << 4 | pcapint_xdtoi(s[1]);
103+ addr[1] = pcapint_xdtoi(s[2]) << 4 | pcapint_xdtoi(s[3]);
104+ addr[2] = pcapint_xdtoi(s[5]) << 4 | pcapint_xdtoi(s[6]);
105+ addr[3] = pcapint_xdtoi(s[7]) << 4 | pcapint_xdtoi(s[8]);
106+ addr[4] = pcapint_xdtoi(s[10]) << 4 | pcapint_xdtoi(s[11]);
107+ addr[5] = pcapint_xdtoi(s[12]) << 4 | pcapint_xdtoi(s[13]);
108+ return 1;
109+ }
110+ return 0;
111+}
112+
113 /*
114- * Convert 's', which can have the one of the forms:
115+ * Man page: "xx:xx:xx:xx:xx:xx", regexp: "^[0-9a-fA-F]{1,2}(:[0-9a-fA-F]{1,2}){5}$".
116+ * Man page: "xx-xx-xx-xx-xx-xx", regexp: "^[0-9a-fA-F]{1,2}(-[0-9a-fA-F]{1,2}){5}$".
117+ * Man page: "xx.xx.xx.xx.xx.xx", regexp: "^[0-9a-fA-F]{1,2}(\.[0-9a-fA-F]{1,2}){5}$".
118+ * (Any "xx" above can be "x", which is equivalent to "0x".)
119 *
120- * "xx:xx:xx:xx:xx:xx"
121- * "xx.xx.xx.xx.xx.xx"
122- * "xx-xx-xx-xx-xx-xx"
123- * "xxxx.xxxx.xxxx"
124- * "xxxxxxxxxxxx"
125+ * An equivalent (and parametrisable for EUI-64) FSM could be implemented using
126+ * a smaller graph, but that graph would be neither acyclic nor planar nor
127+ * trivial to verify.
128 *
129- * (or various mixes of ':', '.', and '-') into a new
130- * ethernet address. Assumes 's' is well formed.
131+ * |
132+ * [.] v
133+ * +<---------- START
134+ * | |
135+ * | | [0-9a-fA-F]
136+ * | [.] v
137+ * +<--------- BYTE0_X ----------+
138+ * | | |
139+ * | | [0-9a-fA-F] |
140+ * | [.] v |
141+ * +<--------- BYTE0_XX | [:\.-]
142+ * | | |
143+ * | | [:\.-] |
144+ * | [.] v |
145+ * +<----- BYTE0_SEP_BYTE1 <-----+
146+ * | |
147+ * | | [0-9a-fA-F]
148+ * | [.] v
149+ * +<--------- BYTE1_X ----------+
150+ * | | |
151+ * | | [0-9a-fA-F] |
152+ * | [.] v |
153+ * +<--------- BYTE1_XX | <sep>
154+ * | | |
155+ * | | <sep> |
156+ * | [.] v |
157+ * +<----- BYTE1_SEP_BYTE2 <-----+
158+ * | |
159+ * | | [0-9a-fA-F]
160+ * | [.] v
161+ * +<--------- BYTE2_X ----------+
162+ * | | |
163+ * | | [0-9a-fA-F] |
164+ * | [.] v |
165+ * +<--------- BYTE2_XX | <sep>
166+ * | | |
167+ * | | <sep> |
168+ * | [.] v |
169+ * +<----- BYTE2_SEP_BYTE3 <-----+
170+ * | |
171+ * | | [0-9a-fA-F]
172+ * | [.] v
173+ * +<--------- BYTE3_X ----------+
174+ * | | |
175+ * | | [0-9a-fA-F] |
176+ * | [.] v |
177+ * +<--------- BYTE3_XX | <sep>
178+ * | | |
179+ * | | <sep> |
180+ * | [.] v |
181+ * +<----- BYTE3_SEP_BYTE4 <-----+
182+ * | |
183+ * | | [0-9a-fA-F]
184+ * | [.] v
185+ * +<--------- BYTE4_X ----------+
186+ * | | |
187+ * | | [0-9a-fA-F] |
188+ * | [.] v |
189+ * +<--------- BYTE4_XX | <sep>
190+ * | | |
191+ * | | <sep> |
192+ * | [.] v |
193+ * +<----- BYTE4_SEP_BYTE5 <-----+
194+ * | |
195+ * | | [0-9a-fA-F]
196+ * | [.] v
197+ * +<--------- BYTE5_X ----------+
198+ * | | |
199+ * | | [0-9a-fA-F] |
200+ * | [.] v |
201+ * +<--------- BYTE5_XX | \0
202+ * | | |
203+ * | | \0 |
204+ * | | v
205+ * +--> (reject) +---------> (accept)
206+ *
207+ */
208+static u_char
209+pcapint_atomac48_x_xx_6_times(const char *s, uint8_t *addr)
210+{
211+ enum {
212+ START,
213+ BYTE0_X,
214+ BYTE0_XX,
215+ BYTE0_SEP_BYTE1,
216+ BYTE1_X,
217+ BYTE1_XX,
218+ BYTE1_SEP_BYTE2,
219+ BYTE2_X,
220+ BYTE2_XX,
221+ BYTE2_SEP_BYTE3,
222+ BYTE3_X,
223+ BYTE3_XX,
224+ BYTE3_SEP_BYTE4,
225+ BYTE4_X,
226+ BYTE4_XX,
227+ BYTE4_SEP_BYTE5,
228+ BYTE5_X,
229+ BYTE5_XX,
230+ } fsm_state = START;
231+ uint8_t buf[6];
232+ const char *seplist = ":.-";
233+ char sep;
234+
235+ while (*s) {
236+ switch (fsm_state) {
237+ case START:
238+ if (PCAP_ISXDIGIT(*s)) {
239+ buf[0] = pcapint_xdtoi(*s);
240+ fsm_state = BYTE0_X;
241+ break;
242+ }
243+ goto reject;
244+ case BYTE0_X:
245+ if (strchr(seplist, *s)) {
246+ sep = *s;
247+ fsm_state = BYTE0_SEP_BYTE1;
248+ break;
249+ }
250+ if (PCAP_ISXDIGIT(*s)) {
251+ buf[0] = buf[0] << 4 | pcapint_xdtoi(*s);
252+ fsm_state = BYTE0_XX;
253+ break;
254+ }
255+ goto reject;
256+ case BYTE0_XX:
257+ if (strchr(seplist, *s)) {
258+ sep = *s;
259+ fsm_state = BYTE0_SEP_BYTE1;
260+ break;
261+ }
262+ goto reject;
263+ case BYTE0_SEP_BYTE1:
264+ if (PCAP_ISXDIGIT(*s)) {
265+ buf[1] = pcapint_xdtoi(*s);
266+ fsm_state = BYTE1_X;
267+ break;
268+ }
269+ goto reject;
270+ case BYTE1_X:
271+ if (*s == sep) {
272+ fsm_state = BYTE1_SEP_BYTE2;
273+ break;
274+ }
275+ if (PCAP_ISXDIGIT(*s)) {
276+ buf[1] = buf[1] << 4 | pcapint_xdtoi(*s);
277+ fsm_state = BYTE1_XX;
278+ break;
279+ }
280+ goto reject;
281+ case BYTE1_XX:
282+ if (*s == sep) {
283+ fsm_state = BYTE1_SEP_BYTE2;
284+ break;
285+ }
286+ goto reject;
287+ case BYTE1_SEP_BYTE2:
288+ if (PCAP_ISXDIGIT(*s)) {
289+ buf[2] = pcapint_xdtoi(*s);
290+ fsm_state = BYTE2_X;
291+ break;
292+ }
293+ goto reject;
294+ case BYTE2_X:
295+ if (*s == sep) {
296+ fsm_state = BYTE2_SEP_BYTE3;
297+ break;
298+ }
299+ if (PCAP_ISXDIGIT(*s)) {
300+ buf[2] = buf[2] << 4 | pcapint_xdtoi(*s);
301+ fsm_state = BYTE2_XX;
302+ break;
303+ }
304+ goto reject;
305+ case BYTE2_XX:
306+ if (*s == sep) {
307+ fsm_state = BYTE2_SEP_BYTE3;
308+ break;
309+ }
310+ goto reject;
311+ case BYTE2_SEP_BYTE3:
312+ if (PCAP_ISXDIGIT(*s)) {
313+ buf[3] = pcapint_xdtoi(*s);
314+ fsm_state = BYTE3_X;
315+ break;
316+ }
317+ goto reject;
318+ case BYTE3_X:
319+ if (*s == sep) {
320+ fsm_state = BYTE3_SEP_BYTE4;
321+ break;
322+ }
323+ if (PCAP_ISXDIGIT(*s)) {
324+ buf[3] = buf[3] << 4 | pcapint_xdtoi(*s);
325+ fsm_state = BYTE3_XX;
326+ break;
327+ }
328+ goto reject;
329+ case BYTE3_XX:
330+ if (*s == sep) {
331+ fsm_state = BYTE3_SEP_BYTE4;
332+ break;
333+ }
334+ goto reject;
335+ case BYTE3_SEP_BYTE4:
336+ if (PCAP_ISXDIGIT(*s)) {
337+ buf[4] = pcapint_xdtoi(*s);
338+ fsm_state = BYTE4_X;
339+ break;
340+ }
341+ goto reject;
342+ case BYTE4_X:
343+ if (*s == sep) {
344+ fsm_state = BYTE4_SEP_BYTE5;
345+ break;
346+ }
347+ if (PCAP_ISXDIGIT(*s)) {
348+ buf[4] = buf[4] << 4 | pcapint_xdtoi(*s);
349+ fsm_state = BYTE4_XX;
350+ break;
351+ }
352+ goto reject;
353+ case BYTE4_XX:
354+ if (*s == sep) {
355+ fsm_state = BYTE4_SEP_BYTE5;
356+ break;
357+ }
358+ goto reject;
359+ case BYTE4_SEP_BYTE5:
360+ if (PCAP_ISXDIGIT(*s)) {
361+ buf[5] = pcapint_xdtoi(*s);
362+ fsm_state = BYTE5_X;
363+ break;
364+ }
365+ goto reject;
366+ case BYTE5_X:
367+ if (PCAP_ISXDIGIT(*s)) {
368+ buf[5] = buf[5] << 4 | pcapint_xdtoi(*s);
369+ fsm_state = BYTE5_XX;
370+ break;
371+ }
372+ goto reject;
373+ case BYTE5_XX:
374+ goto reject;
375+ } // switch
376+ s++;
377+ } // while
378+
379+ if (fsm_state == BYTE5_X || fsm_state == BYTE5_XX) {
380+ // accept
381+ memcpy(addr, buf, sizeof(buf));
382+ return 1;
383+ }
384+
385+reject:
386+ return 0;
387+}
388+
389+// The 'addr' argument must point to an array of at least 6 elements.
390+static int
391+pcapint_atomac48(const char *s, uint8_t *addr)
392+{
393+ return s && (
394+ pcapint_atomac48_xxxxxxxxxxxx(s, addr) ||
395+ pcapint_atomac48_xxxx_3_times(s, addr) ||
396+ pcapint_atomac48_x_xx_6_times(s, addr)
397+ );
398+}
399+
400+/*
401+ * If 's' is a MAC-48 address in one of the forms documented in pcap-filter(7)
402+ * for "ether host", return a pointer to an allocated buffer with the binary
403+ * value of the address. Return NULL on any error.
404 */
405 u_char *
406 pcap_ether_aton(const char *s)
407 {
408- register u_char *ep, *e;
409- register u_char d;
410+ uint8_t tmp[6];
411+ if (! pcapint_atomac48(s, tmp))
412+ return (NULL);
413
414- e = ep = (u_char *)malloc(6);
415+ u_char *e = malloc(6);
416 if (e == NULL)
417 return (NULL);
418-
419- while (*s) {
420- if (*s == ':' || *s == '.' || *s == '-')
421- s += 1;
422- d = pcapint_xdtoi(*s++);
423- if (PCAP_ISXDIGIT(*s)) {
424- d <<= 4;
425- d |= pcapint_xdtoi(*s++);
426- }
427- *ep++ = d;
428- }
429-
430+ memcpy(e, tmp, sizeof(tmp));
431 return (e);
432 }
433
diff --git a/meta/recipes-connectivity/libpcap/libpcap_1.10.1.bb b/meta/recipes-connectivity/libpcap/libpcap_1.10.1.bb
index 584e98c76d..b3bd4f669a 100644
--- a/meta/recipes-connectivity/libpcap/libpcap_1.10.1.bb
+++ b/meta/recipes-connectivity/libpcap/libpcap_1.10.1.bb
@@ -17,6 +17,8 @@ SRC_URI = "https://www.tcpdump.org/release/${BP}.tar.gz \
17 file://CVE-2023-7256-pre4.patch \ 17 file://CVE-2023-7256-pre4.patch \
18 file://CVE-2023-7256.patch \ 18 file://CVE-2023-7256.patch \
19 file://CVE-2024-8006.patch \ 19 file://CVE-2024-8006.patch \
20 file://CVE-2025-11961-01.patch \
21 file://CVE-2025-11961-02.patch \
20 " 22 "
21 23
22SRC_URI[sha256sum] = "ed285f4accaf05344f90975757b3dbfe772ba41d1c401c2648b7fa45b711bdd4" 24SRC_URI[sha256sum] = "ed285f4accaf05344f90975757b3dbfe772ba41d1c401c2648b7fa45b711bdd4"