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

Reply via email to