Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected]
Control: affects -1 + src:lwip
User: [email protected]
Usertags: pu
Hi,
I fixed CVEs CVE-2026-87121 and CVE-2026-91018 in
unstable and testing, and would like to upload the
fix to trixie.
The debdiff is attached.
diff -Nru lwip-2.2.1+dfsg1/debian/changelog lwip-2.2.1+dfsg1/debian/changelog
--- lwip-2.2.1+dfsg1/debian/changelog 2026-05-29 15:18:47.000000000 +0200
+++ lwip-2.2.1+dfsg1/debian/changelog 2026-10-06 08:53:36.000000000 +0200
@@ -1,3 +1,15 @@
+lwip (2.2.1+dfsg1-1+deb13u2) trixie; urgency=medium
+
+ * patches/CVE_2026_87121.
+ * Fix CVE-2026-87121: Validate the MQTT packet length before writing to
+ rx_buffer, preventing an out-of-bounds write.
+ * https://savannah.nongnu.org/bugs/?68590
+ * patches/CVE_2026_91018
+ * Fix CVE-2026-91018: Avoid double-freeing the input pbuf when 6LoWPAN
+ FRAG1 IPHC decompression fails.
+
+ -- Joan Lledó <[email protected]> Tue, 06 Oct 2026 08:53:36 +0200
+
lwip (2.2.1+dfsg1-1+deb13u1) trixie; urgency=medium
* Fix CVE-2026-8836: snmpv3: fix handling packets with invalid
diff -Nru lwip-2.2.1+dfsg1/debian/patches/CVE_2026_87121 lwip-2.2.1+dfsg1/debian/patches/CVE_2026_87121
--- lwip-2.2.1+dfsg1/debian/patches/CVE_2026_87121 1970-01-01 01:00:00.000000000 +0100
+++ lwip-2.2.1+dfsg1/debian/patches/CVE_2026_87121 2026-10-06 08:53:36.000000000 +0200
@@ -0,0 +1,82 @@
+Description: mqtt: fix rx_buffer overrun (CVE_2026_87121)
+Forwarded: https://savannah.nongnu.org/bugs/?68590
+Author: Simon Goldschmidt <[email protected]>
+Last-Update: 2026-10-06
+
+---
+ src/apps/mqtt/mqtt.c | 6 +++++-
+ test/unit/mqtt/test_mqtt.c | 40 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 45 insertions(+), 1 deletion(-)
+
+Index: lwip-deb/src/apps/mqtt/mqtt.c
+===================================================================
+--- lwip-deb.orig/src/apps/mqtt/mqtt.c
++++ lwip-deb/src/apps/mqtt/mqtt.c
+@@ -859,7 +859,11 @@ mqtt_parse_incoming(mqtt_client_t *clien
+ /* parse header from this pbuf and save it in client->rx_buffer in case
+ it comes in segmented */
+ b = pbuf_get_at(p, in_offset++);
+- client->rx_buffer[client->msg_idx++] = b;
++ if (client->msg_idx < MQTT_VAR_HEADER_BUFFER_LEN) {
++ client->rx_buffer[client->msg_idx++] = b;
++ } else {
++ return MQTT_CONNECT_DISCONNECTED;
++ }
+ }
+ fixed_hdr_len++;
+
+Index: lwip-deb/test/unit/mqtt/test_mqtt.c
+===================================================================
+--- lwip-deb.orig/test/unit/mqtt/test_mqtt.c
++++ lwip-deb/test/unit/mqtt/test_mqtt.c
+@@ -106,10 +106,50 @@ START_TEST(basic_connect)
+ }
+ END_TEST
+
++START_TEST(rx_overflow)
++{
++ mqtt_client_t* client;
++ struct netif netif;
++ err_t err;
++ struct mqtt_connect_client_info_t client_info = {
++ "dumm",
++ NULL, NULL,
++ 10,
++ NULL, NULL, 0, 0, 0
++ };
++ struct pbuf* p;
++ unsigned char rxbuf[400];
++ LWIP_UNUSED_ARG(_i);
++
++ test_mqtt_init_netif(&netif, &test_mqtt_local_ip, &test_mqtt_netmask);
++
++ client = mqtt_client_new();
++ fail_unless(client != NULL);
++ err = mqtt_client_connect(client, &test_mqtt_remote_ip, 1234, test_mqtt_connection_cb, NULL, &client_info);
++ fail_unless(err == ERR_OK);
++
++ client->conn->connected(client->conn->callback_arg, client->conn, ERR_OK);
++ memset(rxbuf, 0xff, sizeof(rxbuf));
++ p = pbuf_alloc(PBUF_RAW, sizeof(rxbuf), PBUF_REF);
++ fail_unless(p != NULL);
++ p->payload = rxbuf;
++ /* since we hack the rx path, we have to hack the rx window, too: */
++ client->conn->rcv_wnd -= p->tot_len;
++ if (client->conn->recv(client->conn->callback_arg, client->conn, p, ERR_OK) != ERR_OK) {
++ pbuf_free(p);
++ }
++
++ mqtt_disconnect(client);
++ /* fixme: mqtt_client_fre() is missing... */
++ mem_free(client);
++}
++END_TEST
++
+ Suite* mqtt_suite(void)
+ {
+ testfunc tests[] = {
+ TESTFUNC(basic_connect),
++ TESTFUNC(rx_overflow),
+ };
+ return create_suite("MQTT", tests, sizeof(tests)/sizeof(testfunc), mqtt_setup, mqtt_teardown);
+ }
diff -Nru lwip-2.2.1+dfsg1/debian/patches/CVE_2026_91018 lwip-2.2.1+dfsg1/debian/patches/CVE_2026_91018
--- lwip-2.2.1+dfsg1/debian/patches/CVE_2026_91018 1970-01-01 01:00:00.000000000 +0100
+++ lwip-2.2.1+dfsg1/debian/patches/CVE_2026_91018 2026-10-06 08:53:36.000000000 +0200
@@ -0,0 +1,313 @@
+Description: lowpan6: fix FRAG1 decompression failure and add unit test (CVE_2026_91018)
+Author: Simon Goldschmidt <[email protected]>
+Last-Update: 2026-10-06
+
+---
+ contrib/ports/win32/msvc/lwip_unittests.vcxproj | 2 +
+ .../win32/msvc/lwip_unittests.vcxproj.filters | 9 ++
+ src/netif/lowpan6.c | 3 +-
+ test/unit/Filelists.cmake | 1 +
+ test/unit/Filelists.mk | 1 +
+ test/unit/lowpan6/test_lowpan6.c | 148 +++++++++++++++++++++
+ test/unit/lowpan6/test_lowpan6.h | 8 ++
+ test/unit/lwip_unittests.c | 2 +
+ test/unit/lwipopts.h | 1 +
+ 9 files changed, 174 insertions(+), 1 deletion(-)
+ create mode 100644 test/unit/lowpan6/test_lowpan6.c
+ create mode 100644 test/unit/lowpan6/test_lowpan6.h
+
+diff --git a/contrib/ports/win32/msvc/lwip_unittests.vcxproj b/contrib/ports/win32/msvc/lwip_unittests.vcxproj
+index 270ba284..85e327d4 100644
+--- a/contrib/ports/win32/msvc/lwip_unittests.vcxproj
++++ b/contrib/ports/win32/msvc/lwip_unittests.vcxproj
+@@ -165,6 +165,7 @@
+ <ClCompile Include="..\..\..\..\test\unit\core\test_timers.c" />
+ <ClCompile Include="..\..\..\..\test\unit\ip4\test_ip4.c" />
+ <ClCompile Include="..\..\..\..\test\unit\ip6\test_ip6.c" />
++ <ClCompile Include="..\..\..\..\test\unit\lowpan6\test_lowpan6.c" />
+ <ClCompile Include="..\..\..\..\test\unit\mdns\test_mdns.c" />
+ <ClCompile Include="..\..\..\..\test\unit\mqtt\test_mqtt.c" />
+ <ClCompile Include="..\..\..\..\test\unit\ppp\test_pppos.c" />
+@@ -188,6 +189,7 @@
+ <ClInclude Include="..\..\..\..\test\unit\core\test_timers.h" />
+ <ClInclude Include="..\..\..\..\test\unit\ip4\test_ip4.h" />
+ <ClInclude Include="..\..\..\..\test\unit\ip6\test_ip6.h" />
++ <ClInclude Include="..\..\..\..\test\unit\lowpan6\test_lowpan6.h" />
+ <ClInclude Include="..\..\..\..\test\unit\mdns\test_mdns.h" />
+ <ClInclude Include="..\..\..\..\test\unit\mqtt\test_mqtt.h" />
+ <ClInclude Include="..\..\..\..\test\unit\ppp\test_pppos.h" />
+diff --git a/contrib/ports/win32/msvc/lwip_unittests.vcxproj.filters b/contrib/ports/win32/msvc/lwip_unittests.vcxproj.filters
+index bbac4e7b..d4e20251 100644
+--- a/contrib/ports/win32/msvc/lwip_unittests.vcxproj.filters
++++ b/contrib/ports/win32/msvc/lwip_unittests.vcxproj.filters
+@@ -37,6 +37,9 @@
+ <Filter Include="ppp">
+ <UniqueIdentifier>{4d24c808-c024-4aba-a214-e5bc276e124d}</UniqueIdentifier>
+ </Filter>
++ <Filter Include="lowpan6">
++ <UniqueIdentifier>{7b1a7667-b6c5-4f47-85ff-edfe74a7f7c7}</UniqueIdentifier>
++ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\..\..\..\test\unit\core\test_mem.c">
+@@ -100,6 +103,9 @@
+ <ClCompile Include="..\..\..\..\test\unit\tcp\test_tcp_state.c">
+ <Filter>tcp</Filter>
+ </ClCompile>
++ <ClCompile Include="..\..\..\..\test\unit\lowpan6\test_lowpan6.c">
++ <Filter>lowpan6</Filter>
++ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\..\..\test\unit\core\test_mem.h">
+@@ -164,5 +170,8 @@
+ <ClInclude Include="..\..\..\..\test\unit\tcp\test_tcp_state.h">
+ <Filter>tcp</Filter>
+ </ClInclude>
++ <ClInclude Include="..\..\..\..\test\unit\lowpan6\test_lowpan6.h">
++ <Filter>lowpan6</Filter>
++ </ClInclude>
+ </ItemGroup>
+ </Project>
+\ No newline at end of file
+diff --git a/src/netif/lowpan6.c b/src/netif/lowpan6.c
+index 8eb751c0..7f6849c2 100644
+--- a/src/netif/lowpan6.c
++++ b/src/netif/lowpan6.c
+@@ -726,7 +726,8 @@ lowpan6_input(struct pbuf *p, struct netif *netif)
+ if (lrh->reass == NULL) {
+ /* decompression failed */
+ mem_free(lrh);
+- goto lowpan6_input_discard;
++ MIB2_STATS_NETIF_INC(netif, ifindiscards);
++ return ERR_OK;
+ }
+ }
+ /* TODO: handle the case where we already have FRAGN received */
+diff --git a/test/unit/Filelists.cmake b/test/unit/Filelists.cmake
+index b3db893c..16469221 100644
+--- a/test/unit/Filelists.cmake
++++ b/test/unit/Filelists.cmake
+@@ -27,6 +27,7 @@ set(LWIP_TESTFILES
+ ${LWIP_TESTDIR}/etharp/test_etharp.c
+ ${LWIP_TESTDIR}/ip4/test_ip4.c
+ ${LWIP_TESTDIR}/ip6/test_ip6.c
++ ${LWIP_TESTDIR}/lowpan6/test_lowpan6.c
+ ${LWIP_TESTDIR}/mdns/test_mdns.c
+ ${LWIP_TESTDIR}/mqtt/test_mqtt.c
+ ${LWIP_TESTDIR}/tcp/tcp_helper.c
+diff --git a/test/unit/Filelists.mk b/test/unit/Filelists.mk
+index c33e1b04..578cc697 100644
+--- a/test/unit/Filelists.mk
++++ b/test/unit/Filelists.mk
+@@ -43,6 +43,7 @@ TESTFILES=$(TESTDIR)/lwip_unittests.c \
+ $(TESTDIR)/etharp/test_etharp.c \
+ $(TESTDIR)/ip4/test_ip4.c \
+ $(TESTDIR)/ip6/test_ip6.c \
++ $(TESTDIR)/lowpan6/test_lowpan6.c \
+ $(TESTDIR)/mdns/test_mdns.c \
+ $(TESTDIR)/mqtt/test_mqtt.c \
+ $(TESTDIR)/tcp/tcp_helper.c \
+diff --git a/test/unit/lowpan6/test_lowpan6.c b/test/unit/lowpan6/test_lowpan6.c
+new file mode 100644
+index 00000000..b5540721
+--- /dev/null
++++ b/test/unit/lowpan6/test_lowpan6.c
+@@ -0,0 +1,148 @@
++#include "test_lowpan6.h"
++
++#include "netif/lowpan6.h"
++
++#include "lwip/tcpip.h"
++
++#if LWIP_IPV6 /* allow to build the unit tests without IPv6 support */
++
++static struct netif test_netif_lowpan6;
++static int linkoutput_ctr;
++static int linkoutput_byte_ctr;
++
++/* Helper functions */
++static err_t
++default_netif_linkoutput(struct netif *netif, struct pbuf *p)
++{
++ fail_unless(netif == &test_netif_lowpan6);
++ fail_unless(p != NULL);
++ linkoutput_ctr++;
++ linkoutput_byte_ctr += p->tot_len;
++ return ERR_OK;
++}
++
++static err_t
++default_netif_init(struct netif *netif)
++{
++ fail_unless(netif == &test_netif_lowpan6);
++ netif->name[0] = 'L';
++ netif->name[1] = '6';
++ netif->output_ip6 = lowpan6_output;
++ netif->linkoutput = default_netif_linkoutput;
++ netif->mtu = IP6_MIN_MTU_LENGTH;
++ netif->hwaddr_len = 8;
++ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_MLD6;
++ netif->hwaddr[0] = 0x00;
++ netif->hwaddr[1] = 0x23;
++ netif->hwaddr[2] = 0xC1;
++ netif->hwaddr[3] = 0xDE;
++ netif->hwaddr[4] = 0xD0;
++ netif->hwaddr[5] = 0x0D;
++#if NETIF_MAX_HWADDR_LEN < 8
++#error "6LowPAN needs NETIF_MAX_HWADDR_LEN == 8"
++#endif
++ netif->hwaddr[6] = 0x00;
++ netif->hwaddr[7] = 0x01;
++ netif_create_ip6_linklocal_address(netif, 1);
++ return ERR_OK;
++}
++
++static void
++default_netif_add(void)
++{
++ struct netif *n;
++ fail_unless(netif_default == NULL);
++ n = netif_add_noaddr(&test_netif_lowpan6, NULL, default_netif_init, lowpan6_input);
++ fail_unless(n == &test_netif_lowpan6);
++ netif_set_default(&test_netif_lowpan6);
++}
++
++static void
++default_netif_remove(void)
++{
++ fail_unless(netif_default == &test_netif_lowpan6);
++ netif_remove(&test_netif_lowpan6);
++}
++
++/* Setups/teardown functions */
++
++static void
++lowpan6_setup(void)
++{
++ default_netif_add();
++ lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
++}
++
++static void
++lowpan6_teardown(void)
++{
++ if (netif_list->loop_first != NULL) {
++ pbuf_free(netif_list->loop_first);
++ netif_list->loop_first = NULL;
++ }
++ netif_list->loop_last = NULL;
++ /* poll until all memory is released... */
++ tcpip_thread_poll_one();
++ default_netif_remove();
++ lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
++}
++
++START_TEST(test_6low_frag1_short)
++{
++ unsigned char frame[] = {
++ 0x61, 0xC8, /* Frame Control */
++ 0x01, /* Sequence Number */
++ 0xCD, 0xAB, /* Dst PAN ID (LE) */
++ 0xFF, 0xFF, /* Dst Short Addr (LE) */
++ 0x01, 0x00, 0x0D, 0xD0, 0xDE, 0xC1, 0x23, 0x00, /* Src Ext Addr */
++ /* 6LoWPAN FRAG1 dispatch: b & 0xf8 == 0xc0 */
++ 0xC0, 0x08, /* datagram_size=8, high bits */
++ 0x00, 0x00, /* datagram_tag=0 */
++ /* IPHC dispatch byte (0x60) - triggers lowpan6_decompress which will
++ * fail because there's not enough data for the IPHC header */
++ 0x60 };
++
++ struct pbuf* p;
++ err_t err;
++ LWIP_UNUSED_ARG(_i);
++
++ p = pbuf_alloc(PBUF_RAW, sizeof(frame), PBUF_POOL);
++ fail_unless(p != NULL);
++ if (p == NULL) {
++ return;
++ }
++ pbuf_take(p, frame, sizeof(frame));
++
++ err = lowpan6_input(p, &test_netif_lowpan6);
++ fail_unless(err == ERR_OK);
++}
++END_TEST
++
++/** Create the suite including all tests for this module */
++Suite *
++lowpan6_suite(void)
++{
++ testfunc tests[] = {
++ TESTFUNC(test_6low_frag1_short)
++ };
++ return create_suite("6LoWPAN", tests, sizeof(tests)/sizeof(testfunc), lowpan6_setup, lowpan6_teardown);
++}
++
++#else /* LWIP_IPV6 */
++
++/* allow to build the unit tests without IPv6 support */
++START_TEST(test_lowpan6_dummy)
++{
++ LWIP_UNUSED_ARG(_i);
++}
++END_TEST
++
++Suite *
++lowpan6_suite(void)
++{
++ testfunc tests[] = {
++ TESTFUNC(test_lowpan6_dummy),
++ };
++ return create_suite("6LoWPAN", tests, sizeof(tests)/sizeof(testfunc), NULL, NULL);
++}
++#endif /* LWIP_IPV6 */
+diff --git a/test/unit/lowpan6/test_lowpan6.h b/test/unit/lowpan6/test_lowpan6.h
+new file mode 100644
+index 00000000..4635ba92
+--- /dev/null
++++ b/test/unit/lowpan6/test_lowpan6.h
+@@ -0,0 +1,8 @@
++#ifndef LWIP_HDR_TEST_LOWPAN6_H
++#define LWIP_HDR_TEST_LOWPAN6_H
++
++#include "../lwip_check.h"
++
++Suite* lowpan6_suite(void);
++
++#endif
+diff --git a/test/unit/lwip_unittests.c b/test/unit/lwip_unittests.c
+index d088a066..3dd9e9ac 100644
+--- a/test/unit/lwip_unittests.c
++++ b/test/unit/lwip_unittests.c
+@@ -18,6 +18,7 @@
+ #include "mqtt/test_mqtt.h"
+ #include "api/test_sockets.h"
+ #include "ppp/test_pppos.h"
++#include "lowpan6//test_lowpan6.h"
+
+ #include "lwip/init.h"
+ #if !NO_SYS
+@@ -83,6 +84,7 @@ int main(void)
+ suite_getter_fn* suites[] = {
+ ip4_suite,
+ ip6_suite,
++ lowpan6_suite,
+ udp_suite,
+ tcp_suite,
+ tcp_oos_suite,
+diff --git a/test/unit/lwipopts.h b/test/unit/lwipopts.h
+index 03579ee7..d42ff0bf 100644
+--- a/test/unit/lwipopts.h
++++ b/test/unit/lwipopts.h
+@@ -35,6 +35,7 @@
+ #define LWIP_TESTMODE 1
+
+ #define LWIP_IPV6 1
++#define NETIF_MAX_HWADDR_LEN 8U /* for 6LoWPAN tests */
+
+ #define LWIP_CHECKSUM_ON_COPY 1
+ #define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 1
+--
+cgit v1.2.3
+
diff -Nru lwip-2.2.1+dfsg1/debian/patches/series lwip-2.2.1+dfsg1/debian/patches/series
--- lwip-2.2.1+dfsg1/debian/patches/series 2026-05-29 15:18:47.000000000 +0200
+++ lwip-2.2.1+dfsg1/debian/patches/series 2026-10-06 08:53:36.000000000 +0200
@@ -3,3 +3,5 @@
max_sockets
doxygen
CVE_2026_8836
+CVE_2026_87121
+CVE_2026_91018