Bug#1014447: bullseye-pu: package lwip/2.1.2+dfsg1-8
Package: release.debian.org
Severity: important
Tags: bullseye
User: release.debian.org@packages.debian.org
Usertags: pu
Hi,
This patch fixes CVE-2020-22283 and CVE-2020-22284 in bullseye.
Attached is the debdiff.
[1] https://security-tracker.debian.org/tracker/CVE-2020-22283
[2] https://security-tracker.debian.org/tracker/CVE-2020-22284
*** /home/jlledom/CVEsdebdiff.diff
diff -Nru lwip-2.1.2+dfsg1/debian/changelog
lwip-2.1.2+dfsg1/debian/changelog
--- lwip-2.1.2+dfsg1/debian/changelog 2020-08-09 09:55:09.000000000 +0200
+++ lwip-2.1.2+dfsg1/debian/changelog 2022-07-06 10:55:52.000000000 +0200
@@ -1,3 +1,10 @@
+lwip (2.1.2+dfsg1-8+deb11u1) bullseye; urgency=high
+
+ * Fix CVE-2020-22283
+ * Fix CVE-2020-22284
+
+ -- Joan Lledó <jlledom@member.fsf.org> Wed, 06 Jul 2022 10:55:52 +0200
+
lwip (2.1.2+dfsg1-8) unstable; urgency=medium
* No-change source-only upload to allow testing migration.
diff -Nru lwip-2.1.2+dfsg1/debian/patches/CVE-2020-22283_22284
lwip-2.1.2+dfsg1/debian/patches/CVE-2020-22283_22284
--- lwip-2.1.2+dfsg1/debian/patches/CVE-2020-22283_22284 1970-01-01
01:00:00.000000000 +0100
+++ lwip-2.1.2+dfsg1/debian/patches/CVE-2020-22283_22284 2022-07-06
10:48:50.000000000 +0200
@@ -0,0 +1,261 @@
+--- a/src/core/ipv6/icmp6.c
++++ b/src/core/ipv6/icmp6.c
+@@ -57,9 +57,9 @@
+
+ #include <string.h>
+
+-#if LWIP_ICMP6_DATASIZE == 0
++#if !LWIP_ICMP6_DATASIZE || (LWIP_ICMP6_DATASIZE > (IP6_MIN_MTU_LENGTH -
IP6_HLEN - ICMP6_HLEN))
+ #undef LWIP_ICMP6_DATASIZE
+-#define LWIP_ICMP6_DATASIZE 8
++#define LWIP_ICMP6_DATASIZE (IP6_MIN_MTU_LENGTH - IP6_HLEN - ICMP6_HLEN)
+ #endif
+
+ /* Forward declarations */
+@@ -387,26 +387,35 @@
+ {
+ struct pbuf *q;
+ struct icmp6_hdr *icmp6hdr;
++ u16_t datalen = LWIP_MIN(p->tot_len, LWIP_ICMP6_DATASIZE);
++ u16_t offset;
+
+- /* ICMPv6 header + IPv6 header + data */
+- q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN +
LWIP_ICMP6_DATASIZE,
++ /* ICMPv6 header + datalen (as much of the offending packet as
possible) */
++ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + datalen,
+ PBUF_RAM);
+ if (q == NULL) {
+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate
pbuf for
ICMPv6 packet.\n"));
+ ICMP6_STATS_INC(icmp6.memerr);
+ return;
+ }
+- LWIP_ASSERT("check that first pbuf can hold icmp 6message",
+- (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN +
LWIP_ICMP6_DATASIZE)));
++ LWIP_ASSERT("check that first pbuf can hold icmp6 header",
++ (q->len >= (sizeof(struct icmp6_hdr))));
+
+ icmp6hdr = (struct icmp6_hdr *)q->payload;
+ icmp6hdr->type = type;
+ icmp6hdr->code = code;
+ icmp6hdr->data = lwip_htonl(data);
+
+- /* copy fields from original packet */
+- SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t
*)p->payload,
+- IP6_HLEN + LWIP_ICMP6_DATASIZE);
++ /* copy fields from original packet (which may be a chain of pbufs) */
++ offset = sizeof(struct icmp6_hdr);
++ while (p && datalen) {
++ u16_t len = LWIP_MIN(datalen, p->len);
++ err_t res = pbuf_take_at(q, p->payload, len, offset);
++ if (res != ERR_OK) break;
++ datalen -= len;
++ offset += len;
++ p = p->next;
++ }
+
+ /* calculate checksum */
+ icmp6hdr->chksum = 0;
+--- a/src/core/ipv6/nd6.c
++++ b/src/core/ipv6/nd6.c
+@@ -693,7 +693,7 @@
+ }
+ mtu_opt = (struct mtu_option *)buffer;
+ mtu32 = lwip_htonl(mtu_opt->mtu);
+- if ((mtu32 >= 1280) && (mtu32 <= 0xffff)) {
++ if ((mtu32 >= IP6_MIN_MTU_LENGTH) && (mtu32 <= 0xffff)) {
+ #if LWIP_ND6_ALLOW_RA_UPDATES
+ if (inp->mtu) {
+ /* don't set the mtu for IPv6 higher than the netif driver
supports */
+@@ -2300,7 +2300,7 @@
+ return netif_mtu6(netif);
+ }
+
+- return 1280; /* Minimum MTU */
++ return IP6_MIN_MTU_LENGTH; /* Minimum MTU */
+ }
+
+
+--- a/src/core/pbuf.c
++++ b/src/core/pbuf.c
+@@ -960,54 +960,88 @@
+ err_t
+ pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from)
+ {
+- size_t offset_to = 0, offset_from = 0, len;
+-
+ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
+ (const void *)p_to, (const void *)p_from));
+
++ LWIP_ERROR("pbuf_copy: invalid source", p_from != NULL, return
ERR_ARG;);
++ return pbuf_copy_partial_pbuf(p_to, p_from, p_from->tot_len, 0);
++}
++
++/**
++ * @ingroup pbuf
++ * Copy part or all of one packet buffer into another, to a specified
offset.
++ *
++ * @note Only data in one packet is copied, no packet queue!
++ * @note Argument order is shared with pbuf_copy, but different than
pbuf_copy_partial.
++ *
++ * @param p_to pbuf destination of the copy
++ * @param p_from pbuf source of the copy
++ * @param copy_len number of bytes to copy
++ * @param offset offset in destination pbuf where to copy to
++ *
++ * @return ERR_OK if copy_len bytes were copied
++ * ERR_ARG if one of the pbufs is NULL or p_from is shorter than
copy_len
++ * or p_to is not big enough to hold copy_len at offset
++ * ERR_VAL if any of the pbufs are part of a queue
++ */
++err_t
++pbuf_copy_partial_pbuf(struct pbuf *p_to, const struct pbuf *p_from, u16_t
copy_len, u16_t offset)
++{
++ size_t offset_to = offset, offset_from = 0, len_calc;
++ u16_t len;
++
++ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
("pbuf_copy_partial_pbuf(%p, %p,
%"U16_F", %"U16_F")\n",
++ (const void *)p_to, (const void *)p_from, copy_len,
offset));
++
++ /* is the copy_len in range? */
++ LWIP_ERROR("pbuf_copy_partial_pbuf: copy_len bigger than source",
((p_from
!= NULL) &&
++ (p_from->tot_len >= copy_len)), return ERR_ARG;);
+ /* is the target big enough to hold the source? */
+- LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to !=
NULL) &&
+- (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)),
return
ERR_ARG;);
++ LWIP_ERROR("pbuf_copy_partial_pbuf: target not big enough", ((p_to
!= NULL)
&&
++ (p_to->tot_len >= (offset + copy_len))), return ERR_ARG;);
+
+ /* iterate through pbuf chain */
+ do {
+ /* copy one part of the original chain */
+ if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
+ /* complete current p_from fits into current p_to */
+- len = p_from->len - offset_from;
++ len_calc = p_from->len - offset_from;
+ } else {
+ /* current p_from does not fit into current p_to */
+- len = p_to->len - offset_to;
++ len_calc = p_to->len - offset_to;
+ }
++ len = (u16_t)LWIP_MIN(copy_len, len_calc);
+ MEMCPY((u8_t *)p_to->payload + offset_to, (u8_t *)p_from->payload +
offset_from, len);
+ offset_to += len;
+ offset_from += len;
++ copy_len -= len;
+ LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
+ LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
+ if (offset_from >= p_from->len) {
+ /* on to next p_from (if any) */
+ offset_from = 0;
+ p_from = p_from->next;
++ LWIP_ERROR("p_from != NULL", (p_from != NULL) || (copy_len == 0),
return ERR_ARG;);
+ }
+ if (offset_to == p_to->len) {
+ /* on to next p_to (if any) */
+ offset_to = 0;
+ p_to = p_to->next;
+- LWIP_ERROR("p_to != NULL", (p_to != NULL) || (p_from == NULL),
return
ERR_ARG;);
++ LWIP_ERROR("p_to != NULL", (p_to != NULL) || (copy_len == 0), return
ERR_ARG;);
+ }
+
+ if ((p_from != NULL) && (p_from->len == p_from->tot_len)) {
+ /* don't copy more than one packet! */
+- LWIP_ERROR("pbuf_copy() does not allow packet queues!",
++ LWIP_ERROR("pbuf_copy_partial_pbuf() does not allow packet queues!",
+ (p_from->next == NULL), return ERR_VAL;);
+ }
+ if ((p_to != NULL) && (p_to->len == p_to->tot_len)) {
+ /* don't copy more than one packet! */
+- LWIP_ERROR("pbuf_copy() does not allow packet queues!",
++ LWIP_ERROR("pbuf_copy_partial_pbuf() does not allow packet queues!",
+ (p_to->next == NULL), return ERR_VAL;);
+ }
+- } while (p_from);
+- LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain
reached.\n"));
++ } while (copy_len);
++ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy_partial_pbuf: copy
complete.\n"));
+ return ERR_OK;
+ }
+
+--- a/src/include/lwip/opt.h
++++ b/src/include/lwip/opt.h
+@@ -2502,10 +2502,12 @@
+
+ /**
+ * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in
+- * ICMPv6 error messages.
++ * ICMPv6 error messages (0 = default of IP6_MIN_MTU_LENGTH)
++ * ATTENTION: RFC4443 section 2.4 says IP6_MIN_MTU_LENGTH is a MUST,
++ * so override this only if you absolutely have to!
+ */
+ #if !defined LWIP_ICMP6_DATASIZE || defined __DOXYGEN__
+-#define LWIP_ICMP6_DATASIZE 8
++#define LWIP_ICMP6_DATASIZE 0
+ #endif
+
+ /**
+--- a/src/include/lwip/pbuf.h
++++ b/src/include/lwip/pbuf.h
+@@ -293,6 +293,7 @@
+ void pbuf_chain(struct pbuf *head, struct pbuf *tail);
+ struct pbuf *pbuf_dechain(struct pbuf *p);
+ err_t pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from);
++err_t pbuf_copy_partial_pbuf(struct pbuf *p_to, const struct pbuf *p_from,
u16_t copy_len, u16_t offset);
+ u16_t pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t
len, u16_t
offset);
+ void *pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t
bufsize,
u16_t len, u16_t offset);
+ err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
+--- a/src/include/lwip/prot/icmp6.h
++++ b/src/include/lwip/prot/icmp6.h
+@@ -146,6 +146,8 @@
+ # include "arch/epstruct.h"
+ #endif
+
++#define ICMP6_HLEN 8
++
+ /** This is the ICMP6 header adapted for echo req/resp. */
+ #ifdef PACK_STRUCT_USE_INCLUDES
+ # include "arch/bpstruct.h"
+--- a/src/include/lwip/prot/ip6.h
++++ b/src/include/lwip/prot/ip6.h
+@@ -44,6 +44,8 @@
+ extern "C" {
+ #endif
+
++#define IP6_MIN_MTU_LENGTH 1280
++
+ /** This is the packed version of ip6_addr_t,
+ used in network headers that are itself packed */
+ #ifdef PACK_STRUCT_USE_INCLUDES
+--- a/src/netif/lowpan6.c
++++ b/src/netif/lowpan6.c
+@@ -881,7 +881,7 @@
+ MIB2_INIT_NETIF(netif, snmp_ifType_other, 0);
+
+ /* maximum transfer unit */
+- netif->mtu = 1280;
++ netif->mtu = IP6_MIN_MTU_LENGTH;
+
+ /* broadcast capability */
+ netif->flags = NETIF_FLAG_BROADCAST /* | NETIF_FLAG_LOWPAN6 */;
+--- a/src/netif/lowpan6_ble.c
++++ b/src/netif/lowpan6_ble.c
+@@ -417,7 +417,7 @@
+ MIB2_INIT_NETIF(netif, snmp_ifType_other, 0);
+
+ /* maximum transfer unit, set according to RFC7668 ch2.4 */
+- netif->mtu = 1280;
++ netif->mtu = IP6_MIN_MTU_LENGTH;
+
+ /* no flags set (no broadcast, ethernet,...)*/
+ netif->flags = 0;
+--- a/src/netif/zepif.c
++++ b/src/netif/zepif.c
+@@ -201,7 +201,7 @@
+ state->seqno++;
+ zep->len = (u8_t)p->tot_len;
+
+- err = pbuf_take_at(q, p->payload, p->tot_len, sizeof(struct zep_hdr));
++ err = pbuf_copy_partial_pbuf(q, p, p->tot_len, sizeof(struct zep_hdr));
+ if (err == ERR_OK) {
+ #if ZEPIF_LOOPBACK
+ zepif_udp_recv(netif, state->pcb, pbuf_clone(PBUF_RAW, PBUF_RAM, q),
NULL, 0);
diff -Nru lwip-2.1.2+dfsg1/debian/patches/series
lwip-2.1.2+dfsg1/debian/patches/series
--- lwip-2.1.2+dfsg1/debian/patches/series 2020-08-09
09:55:09.000000000
+0200
+++ lwip-2.1.2+dfsg1/debian/patches/series 2022-07-06
10:48:50.000000000
+0200
@@ -1,6 +1,7 @@
patch9350
patch9807
CVE-2020-8597
+CVE-2020-22283_22284
port
Reply to: