[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#995439: bullseye-pu: package libslirp/4.4.0-1+deb11u1



Package: release.debian.org
Severity: normal
Tags: buster
User: release.debian.org@packages.debian.org
Usertags: pu

There are a few security bugs found in libslirp, a user-level
networking library used in qemu and other places, in version
in bullseye.  These bugs has already been fixed in -testing
by a new upstream version of the library, but these CVEs are
still listed for it in bullseye.

The impact of these bugs are relatively low, - this is why
the security team decided to not release a DSA for them.
However they're security issues still, and I'd be really
glad to clear the list of security issues for this package.
I asked the security team about pushing this to bullseye-security
and the answer was to go the bullseye-proposed-updates route.

The way how libslirp is used in qemu makes every bug in libslirp
to be basically non-essential, since user-level networking is
only good for some quick testing, it is not supposed to be used
in production.  However I don't know how this library is used
in other places.

[ Tests ]
There's no automated tests tried for this library. Neither do
I have reproducers for all the issues involved. However I tested
the user-mode networking of qemu with this proposed version of
libslirp and gave it as much stress testing as I can, especially
trying to hit the areas changed. Run a bunch of various stress
testing and manually did stuff including various UDP protocols,
tftp transfers, and BOOTP debugging. So far everything seems to
work correctly.

The same changes were made upstream (these *are* changes taken
from upstream, with very minor editing of context so eg function
declarations will find their way in the header file which, in
a later version, contained more declarations than in the version
in bullseye), - and these upstream changes has been tested by
numerous people including debian testing. I hadn't need to backport
the changes, the code is the same (if not counting the context
in header file).

[ Risks ]
Again, due to the nature of this package which is mostly aimed
for testing and not real production, the risk of breaking it is
rather small. It can affect quite some people ofcourse. Having
in mind this is the same set of changes already used by many
people in a more recent version, I don't expect a big issue there.

[ Checklist ]
  [X] *all* changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in (old)stable
  [X] the issue is verified as fixed in unstable

[ Changes ]
Here are the changelog entry for the new release:

libslirp (4.4.0-1+deb11u1) bullseye; urgency=medium

  * import a few patches from upstream to fix 4 security issues:
   - add-mtod_check.patch (preparational)
   - bootp-limit-vendor-area-to-input-packet-CVE-2021-3592.patch,
     bootp-check-bootp_input-buffer-size-CVE-2021-3592.patch
     Closes: #989993, CVE-2021-3592: invalid pointer init in bootp_init()
   - tftp-check-tftp_input-buffer-size-CVE-2021-3595.patch,
     tftp-introduce-a-header-structure-CVE-2021-3595.patch
     Closes: #989996, CVE-2021-3595: invalid pointer init in tftp_input()
   - udp-check-upd_input-buffer-size-CVE-2021-3594.patch
     Closes: #989995, CVE-2021-3594: invalid pointer init in udp_input()
   - upd6-check-udp6_input-buffer-size-CVE-2021-3593.patch
     Closes: #989994, CVE-2021-3593: invalid pointer init in udp6_input()

 -- Michael Tokarev <mjt@tls.msk.ru>  Thu, 30 Sep 2021 21:08:51 +0300

[ Other info ]
And here's the debdiff.

Thanks!

/mjt
----
diff -Nru libslirp-4.4.0/debian/changelog libslirp-4.4.0/debian/changelog
--- libslirp-4.4.0/debian/changelog	2020-12-19 18:36:33.000000000 +0300
+++ libslirp-4.4.0/debian/changelog	2021-09-30 21:08:51.000000000 +0300
@@ -1,3 +1,20 @@
+libslirp (4.4.0-1+deb11u1) bullseye; urgency=medium
+
+  * import a few patches from upstream to fix 4 security issues:
+   - add-mtod_check.patch (preparational)
+   - bootp-limit-vendor-area-to-input-packet-CVE-2021-3592.patch,
+     bootp-check-bootp_input-buffer-size-CVE-2021-3592.patch
+     Closes: #989993, CVE-2021-3592: invalid pointer init in bootp_init()
+   - tftp-check-tftp_input-buffer-size-CVE-2021-3595.patch,
+     tftp-introduce-a-header-structure-CVE-2021-3595.patch
+     Closes: #989996, CVE-2021-3595: invalid pointer init in tftp_input()
+   - udp-check-upd_input-buffer-size-CVE-2021-3594.patch
+     Closes: #989995, CVE-2021-3594: invalid pointer init in udp_input()
+   - upd6-check-udp6_input-buffer-size-CVE-2021-3593.patch
+     Closes: #989994, CVE-2021-3593: invalid pointer init in udp6_input()
+
+ -- Michael Tokarev <mjt@tls.msk.ru>  Thu, 30 Sep 2021 21:08:51 +0300
+
 libslirp (4.4.0-1) unstable; urgency=medium
 
   * new upstream release
diff -Nru libslirp-4.4.0/debian/patches/add-mtod_check.patch libslirp-4.4.0/debian/patches/add-mtod_check.patch
--- libslirp-4.4.0/debian/patches/add-mtod_check.patch	1970-01-01 03:00:00.000000000 +0300
+++ libslirp-4.4.0/debian/patches/add-mtod_check.patch	2021-09-30 20:50:51.000000000 +0300
@@ -0,0 +1,51 @@
+Commit-Id: 93e645e72a056ec0b2c16e0299fc5c6b94e4ca17
+From: Marc-André Lureau <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 15:58:25 +0400
+Subject: Add mtod_check()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Recent security issues demonstrate the lack of safety care when casting
+a mbuf to a particular structure type. At least, it should check that
+the buffer is large enough. The following patches will make use of this
+function.
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+---
+ src/mbuf.c | 11 +++++++++++
+ src/mbuf.h |  1 +
+ 2 files changed, 12 insertions(+)
+
+diff --git a/src/mbuf.c b/src/mbuf.c
+--- a/src/mbuf.c
++++ b/src/mbuf.c
+@@ -222,3 +222,14 @@ struct mbuf *dtom(Slirp *slirp, void *dat)
+ 
+     return (struct mbuf *)0;
+ }
++
++void *mtod_check(struct mbuf *m, size_t len)
++{
++    if (m->m_len >= len) {
++        return m->m_data;
++    }
++
++    DEBUG_ERROR("mtod failed");
++
++    return NULL;
++}
+diff --git a/src/mbuf.h b/src/mbuf.h
+--- a/src/mbuf.h
++++ b/src/mbuf.h
+@@ -118,6 +118,7 @@ void m_inc(struct mbuf *, int);
+ void m_adj(struct mbuf *, int);
+ int m_copy(struct mbuf *, struct mbuf *, int, int);
+ struct mbuf *dtom(Slirp *, void *);
++void *mtod_check(struct mbuf *, size_t len);
+ 
+ static inline void ifs_init(struct mbuf *ifm)
+ {
+-- 
+2.30.2
+
diff -Nru libslirp-4.4.0/debian/patches/bootp-check-bootp_input-buffer-size-CVE-2021-3592.patch libslirp-4.4.0/debian/patches/bootp-check-bootp_input-buffer-size-CVE-2021-3592.patch
--- libslirp-4.4.0/debian/patches/bootp-check-bootp_input-buffer-size-CVE-2021-3592.patch	1970-01-01 03:00:00.000000000 +0300
+++ libslirp-4.4.0/debian/patches/bootp-check-bootp_input-buffer-size-CVE-2021-3592.patch	2021-09-30 21:04:33.000000000 +0300
@@ -0,0 +1,36 @@
+Commit-Id: 2eca0838eee1da96204545e22cdaed860d9d7c6c
+From: Marc-André Lureau <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 16:15:14 +0400
+Subject: bootp: check bootp_input buffer size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+Bug-Debian: https://bugs.debian.org/989993
+
+Fixes: CVE-2021-3592
+Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/44
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+---
+ src/bootp.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/bootp.c b/src/bootp.c
+index e0db8d1..cafa1eb 100644
+--- a/src/bootp.c
++++ b/src/bootp.c
+@@ -365,9 +365,9 @@ static void bootp_reply(Slirp *slirp,
+ 
+ void bootp_input(struct mbuf *m)
+ {
+-    struct bootp_t *bp = mtod(m, struct bootp_t *);
++    struct bootp_t *bp = mtod_check(m, sizeof(struct bootp_t));
+ 
+-    if (bp->bp_op == BOOTP_REQUEST) {
++    if (bp && bp->bp_op == BOOTP_REQUEST) {
+         bootp_reply(m->slirp, bp, m_end(m));
+     }
+ }
+-- 
+2.30.2
+
diff -Nru libslirp-4.4.0/debian/patches/bootp-limit-vendor-area-to-input-packet-CVE-2021-3592.patch libslirp-4.4.0/debian/patches/bootp-limit-vendor-area-to-input-packet-CVE-2021-3592.patch
--- libslirp-4.4.0/debian/patches/bootp-limit-vendor-area-to-input-packet-CVE-2021-3592.patch	1970-01-01 03:00:00.000000000 +0300
+++ libslirp-4.4.0/debian/patches/bootp-limit-vendor-area-to-input-packet-CVE-2021-3592.patch	2021-09-30 21:04:33.000000000 +0300
@@ -0,0 +1,160 @@
+Commit-Id: f13cad45b25d92760bb0ad67bec0300a4d7d5275
+From: Marc-André Lureau <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 19:25:28 +0400
+Subject: bootp: limit vendor-specific area to input packet memory buffer
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+Bug-Debian: https://bugs.debian.org/989993
+
+sizeof(bootp_t) currently holds DHCP_OPT_LEN. Remove this optional field
+from the structure, to help with the following patch checking for
+minimal header size. Modify the bootp_reply() function to take the
+buffer boundaries and avoiding potential buffer overflow.
+
+Related to CVE-2021-3592.
+
+https://gitlab.freedesktop.org/slirp/libslirp/-/issues/44
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+---
+ src/bootp.c | 26 +++++++++++++++-----------
+ src/bootp.h |  2 +-
+ src/mbuf.c  |  5 +++++
+ src/mbuf.h  |  1 +
+ 4 files changed, 22 insertions(+), 12 deletions(-)
+
+diff --git a/src/bootp.c b/src/bootp.c
+index 46e9681..e0db8d1 100644
+--- a/src/bootp.c
++++ b/src/bootp.c
+@@ -92,21 +92,22 @@ found:
+     return bc;
+ }
+ 
+-static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
++static void dhcp_decode(const struct bootp_t *bp,
++                        const uint8_t *bp_end,
++                        int *pmsg_type,
+                         struct in_addr *preq_addr)
+ {
+-    const uint8_t *p, *p_end;
++    const uint8_t *p;
+     int len, tag;
+ 
+     *pmsg_type = 0;
+     preq_addr->s_addr = htonl(0L);
+ 
+     p = bp->bp_vend;
+-    p_end = p + DHCP_OPT_LEN;
+     if (memcmp(p, rfc1533_cookie, 4) != 0)
+         return;
+     p += 4;
+-    while (p < p_end) {
++    while (p < bp_end) {
+         tag = p[0];
+         if (tag == RFC1533_PAD) {
+             p++;
+@@ -114,10 +115,10 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
+             break;
+         } else {
+             p++;
+-            if (p >= p_end)
++            if (p >= bp_end)
+                 break;
+             len = *p++;
+-            if (p + len > p_end) {
++            if (p + len > bp_end) {
+                 break;
+             }
+             DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
+@@ -144,7 +145,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
+     }
+ }
+ 
+-static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
++static void bootp_reply(Slirp *slirp,
++                        const struct bootp_t *bp,
++                        const uint8_t *bp_end)
+ {
+     BOOTPClient *bc = NULL;
+     struct mbuf *m;
+@@ -157,7 +160,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
+     uint8_t client_ethaddr[ETH_ALEN];
+ 
+     /* extract exact DHCP msg type */
+-    dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
++    dhcp_decode(bp, bp_end, &dhcp_msg_type, &preq_addr);
+     DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
+     if (preq_addr.s_addr != htonl(0L))
+         DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
+@@ -179,9 +182,10 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
+         return;
+     }
+     m->m_data += IF_MAXLINKHDR;
++    m_inc(m, sizeof(struct bootp_t) + DHCP_OPT_LEN);
+     rbp = (struct bootp_t *)m->m_data;
+     m->m_data += sizeof(struct udpiphdr);
+-    memset(rbp, 0, sizeof(struct bootp_t));
++    memset(rbp, 0, sizeof(struct bootp_t) + DHCP_OPT_LEN);
+ 
+     if (dhcp_msg_type == DHCPDISCOVER) {
+         if (preq_addr.s_addr != htonl(0L)) {
+@@ -235,7 +239,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
+     rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
+ 
+     q = rbp->bp_vend;
+-    end = (uint8_t *)&rbp[1];
++    end = rbp->bp_vend + DHCP_OPT_LEN;
+     memcpy(q, rfc1533_cookie, 4);
+     q += 4;
+ 
+@@ -364,6 +368,6 @@ void bootp_input(struct mbuf *m)
+     struct bootp_t *bp = mtod(m, struct bootp_t *);
+ 
+     if (bp->bp_op == BOOTP_REQUEST) {
+-        bootp_reply(m->slirp, bp);
++        bootp_reply(m->slirp, bp, m_end(m));
+     }
+ }
+diff --git a/src/bootp.h b/src/bootp.h
+index a57fa51..31ce5fd 100644
+--- a/src/bootp.h
++++ b/src/bootp.h
+@@ -114,7 +114,7 @@ struct bootp_t {
+     uint8_t bp_hwaddr[16];
+     uint8_t bp_sname[64];
+     char bp_file[128];
+-    uint8_t bp_vend[DHCP_OPT_LEN];
++    uint8_t bp_vend[];
+ };
+ 
+ typedef struct {
+diff --git a/src/mbuf.c b/src/mbuf.c
+index b4152c3..36864a4 100644
+--- a/src/mbuf.c
++++ b/src/mbuf.c
+@@ -274,3 +274,8 @@ void *mtod_check(struct mbuf *m, size_t len)
+ 
+     return NULL;
+ }
++
++void *m_end(struct mbuf *m)
++{
++    return m->m_data + m->m_len;
++}
+diff --git a/src/mbuf.h b/src/mbuf.h
+index 23c5458..34e697a 100644
+--- a/src/mbuf.h
++++ b/src/mbuf.h
+@@ -119,6 +119,7 @@ void m_adj(struct mbuf *, int);
+ int m_copy(struct mbuf *, struct mbuf *, int, int);
+ struct mbuf *dtom(Slirp *, void *);
+ void *mtod_check(struct mbuf *, size_t len);
++void *m_end(struct mbuf *);
+ 
+ static inline void ifs_init(struct mbuf *ifm)
+ {
+-- 
+2.30.2
+
diff -Nru libslirp-4.4.0/debian/patches/series libslirp-4.4.0/debian/patches/series
--- libslirp-4.4.0/debian/patches/series	2020-07-03 18:47:56.000000000 +0300
+++ libslirp-4.4.0/debian/patches/series	2021-09-30 21:07:24.000000000 +0300
@@ -0,0 +1,7 @@
+add-mtod_check.patch
+bootp-limit-vendor-area-to-input-packet-CVE-2021-3592.patch
+bootp-check-bootp_input-buffer-size-CVE-2021-3592.patch
+tftp-check-tftp_input-buffer-size-CVE-2021-3595.patch
+tftp-introduce-a-header-structure-CVE-2021-3595.patch
+udp-check-upd_input-buffer-size-CVE-2021-3594.patch
+upd6-check-udp6_input-buffer-size-CVE-2021-3593.patch
diff -Nru libslirp-4.4.0/debian/patches/tftp-check-tftp_input-buffer-size-CVE-2021-3595.patch libslirp-4.4.0/debian/patches/tftp-check-tftp_input-buffer-size-CVE-2021-3595.patch
--- libslirp-4.4.0/debian/patches/tftp-check-tftp_input-buffer-size-CVE-2021-3595.patch	1970-01-01 03:00:00.000000000 +0300
+++ libslirp-4.4.0/debian/patches/tftp-check-tftp_input-buffer-size-CVE-2021-3595.patch	2021-09-30 21:04:37.000000000 +0300
@@ -0,0 +1,37 @@
+Commit-Id: 3f17948137155f025f7809fdc38576d5d2451c3d
+From: Marc-André Lureau <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 16:34:30 +0400
+Subject: tftp: check tftp_input buffer size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+Bug-Debian: https://bugs.debian.org/989996
+
+Fixes: CVE-2021-3595
+Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/46
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+---
+ src/tftp.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/tftp.c b/src/tftp.c
+index c6950ee..e06911d 100644
+--- a/src/tftp.c
++++ b/src/tftp.c
+@@ -446,7 +446,11 @@ static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
+ 
+ void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m)
+ {
+-    struct tftp_t *tp = (struct tftp_t *)m->m_data;
++    struct tftp_t *tp = mtod_check(m, offsetof(struct tftp_t, x.tp_buf));
++
++    if (tp == NULL) {
++        return;
++    }
+ 
+     switch (ntohs(tp->tp_op)) {
+     case TFTP_RRQ:
+-- 
+2.30.2
+
diff -Nru libslirp-4.4.0/debian/patches/tftp-introduce-a-header-structure-CVE-2021-3595.patch libslirp-4.4.0/debian/patches/tftp-introduce-a-header-structure-CVE-2021-3595.patch
--- libslirp-4.4.0/debian/patches/tftp-introduce-a-header-structure-CVE-2021-3595.patch	1970-01-01 03:00:00.000000000 +0300
+++ libslirp-4.4.0/debian/patches/tftp-introduce-a-header-structure-CVE-2021-3595.patch	2021-09-30 21:04:37.000000000 +0300
@@ -0,0 +1,249 @@
+Commit-Id: 990163cf3ac86b7875559f49602c4d76f46f6f30
+From: Marc-André Lureau <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 20:01:20 +0400
+Subject: tftp: introduce a header structure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+Bug-Debian: https://bugs.debian.org/989996
+
+Instead of using a composed structure and potentially reading past the
+incoming buffer, use a different structure for the header.
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+---
+ src/tftp.c | 60 ++++++++++++++++++++++++++++--------------------------
+ src/tftp.h |  6 +++++-
+ 2 files changed, 36 insertions(+), 30 deletions(-)
+
+diff --git a/src/tftp.c b/src/tftp.c
+index e06911d..a19c889 100644
+--- a/src/tftp.c
++++ b/src/tftp.c
+@@ -50,7 +50,7 @@ static void tftp_session_terminate(struct tftp_session *spt)
+ }
+ 
+ static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas,
+-                                 struct tftp_t *tp)
++                                 struct tftphdr *hdr)
+ {
+     struct tftp_session *spt;
+     int k;
+@@ -75,7 +75,7 @@ found:
+     memcpy(&spt->client_addr, srcsas, sockaddr_size(srcsas));
+     spt->fd = -1;
+     spt->block_size = 512;
+-    spt->client_port = tp->udp.uh_sport;
++    spt->client_port = hdr->udp.uh_sport;
+     spt->slirp = slirp;
+ 
+     tftp_session_update(spt);
+@@ -84,7 +84,7 @@ found:
+ }
+ 
+ static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas,
+-                             struct tftp_t *tp)
++                             struct tftphdr *hdr)
+ {
+     struct tftp_session *spt;
+     int k;
+@@ -94,7 +94,7 @@ static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas,
+ 
+         if (tftp_session_in_use(spt)) {
+             if (sockaddr_equal(&spt->client_addr, srcsas)) {
+-                if (spt->client_port == tp->udp.uh_sport) {
++                if (spt->client_port == hdr->udp.uh_sport) {
+                     return k;
+                 }
+             }
+@@ -148,13 +148,13 @@ static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt,
+ }
+ 
+ static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
+-                            struct tftp_t *recv_tp)
++                            struct tftphdr *hdr)
+ {
+     if (spt->client_addr.ss_family == AF_INET6) {
+         struct sockaddr_in6 sa6, da6;
+ 
+         sa6.sin6_addr = spt->slirp->vhost_addr6;
+-        sa6.sin6_port = recv_tp->udp.uh_dport;
++        sa6.sin6_port = hdr->udp.uh_dport;
+         da6.sin6_addr = ((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr;
+         da6.sin6_port = spt->client_port;
+ 
+@@ -163,7 +163,7 @@ static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
+         struct sockaddr_in sa4, da4;
+ 
+         sa4.sin_addr = spt->slirp->vhost_addr;
+-        sa4.sin_port = recv_tp->udp.uh_dport;
++        sa4.sin_port = hdr->udp.uh_dport;
+         da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr;
+         da4.sin_port = spt->client_port;
+ 
+@@ -185,14 +185,14 @@ static int tftp_send_oack(struct tftp_session *spt, const char *keys[],
+ 
+     tp = tftp_prep_mbuf_data(spt, m);
+ 
+-    tp->tp_op = htons(TFTP_OACK);
++    tp->hdr.tp_op = htons(TFTP_OACK);
+     for (i = 0; i < nb; i++) {
+         n += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", keys[i]);
+         n += slirp_fmt0(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u", values[i]);
+     }
+ 
+-    m->m_len = G_SIZEOF_MEMBER(struct tftp_t, tp_op) + n;
+-    tftp_udp_output(spt, m, recv_tp);
++    m->m_len = G_SIZEOF_MEMBER(struct tftp_t, hdr.tp_op) + n;
++    tftp_udp_output(spt, m, &recv_tp->hdr);
+ 
+     return 0;
+ }
+@@ -213,21 +213,21 @@ static void tftp_send_error(struct tftp_session *spt, uint16_t errorcode,
+ 
+     tp = tftp_prep_mbuf_data(spt, m);
+ 
+-    tp->tp_op = htons(TFTP_ERROR);
++    tp->hdr.tp_op = htons(TFTP_ERROR);
+     tp->x.tp_error.tp_error_code = htons(errorcode);
+     slirp_pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg),
+                   msg);
+ 
+     m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + 3 +
+                strlen(msg) - sizeof(struct udphdr);
+-    tftp_udp_output(spt, m, recv_tp);
++    tftp_udp_output(spt, m, &recv_tp->hdr);
+ 
+ out:
+     tftp_session_terminate(spt);
+ }
+ 
+ static void tftp_send_next_block(struct tftp_session *spt,
+-                                 struct tftp_t *recv_tp)
++                                 struct tftphdr *hdr)
+ {
+     struct mbuf *m;
+     struct tftp_t *tp;
+@@ -241,7 +241,7 @@ static void tftp_send_next_block(struct tftp_session *spt,
+ 
+     tp = tftp_prep_mbuf_data(spt, m);
+ 
+-    tp->tp_op = htons(TFTP_DATA);
++    tp->hdr.tp_op = htons(TFTP_DATA);
+     tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
+ 
+     nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf,
+@@ -259,7 +259,7 @@ static void tftp_send_next_block(struct tftp_session *spt,
+ 
+     m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX - nobytes) -
+                sizeof(struct udphdr);
+-    tftp_udp_output(spt, m, recv_tp);
++    tftp_udp_output(spt, m, hdr);
+ 
+     if (nobytes == spt->block_size) {
+         tftp_session_update(spt);
+@@ -282,12 +282,12 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
+     int nb_options = 0;
+ 
+     /* check if a session already exists and if so terminate it */
+-    s = tftp_session_find(slirp, srcsas, tp);
++    s = tftp_session_find(slirp, srcsas, &tp->hdr);
+     if (s >= 0) {
+         tftp_session_terminate(&slirp->tftp_sessions[s]);
+     }
+ 
+-    s = tftp_session_allocate(slirp, srcsas, tp);
++    s = tftp_session_allocate(slirp, srcsas, &tp->hdr);
+ 
+     if (s < 0) {
+         return;
+@@ -413,29 +413,29 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
+     }
+ 
+     spt->block_nr = 0;
+-    tftp_send_next_block(spt, tp);
++    tftp_send_next_block(spt, &tp->hdr);
+ }
+ 
+ static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas,
+-                            struct tftp_t *tp, int pktlen)
++                            struct tftphdr *hdr)
+ {
+     int s;
+ 
+-    s = tftp_session_find(slirp, srcsas, tp);
++    s = tftp_session_find(slirp, srcsas, hdr);
+ 
+     if (s < 0) {
+         return;
+     }
+ 
+-    tftp_send_next_block(&slirp->tftp_sessions[s], tp);
++    tftp_send_next_block(&slirp->tftp_sessions[s], hdr);
+ }
+ 
+ static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
+-                              struct tftp_t *tp, int pktlen)
++                              struct tftphdr *hdr)
+ {
+     int s;
+ 
+-    s = tftp_session_find(slirp, srcsas, tp);
++    s = tftp_session_find(slirp, srcsas, hdr);
+ 
+     if (s < 0) {
+         return;
+@@ -446,23 +446,25 @@ static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
+ 
+ void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m)
+ {
+-    struct tftp_t *tp = mtod_check(m, offsetof(struct tftp_t, x.tp_buf));
++    struct tftphdr *hdr = mtod_check(m, sizeof(struct tftphdr));
+ 
+-    if (tp == NULL) {
++    if (hdr == NULL) {
+         return;
+     }
+ 
+-    switch (ntohs(tp->tp_op)) {
++    switch (ntohs(hdr->tp_op)) {
+     case TFTP_RRQ:
+-        tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len);
++        tftp_handle_rrq(m->slirp, srcsas,
++                        mtod(m, struct tftp_t *),
++                        m->m_len);
+         break;
+ 
+     case TFTP_ACK:
+-        tftp_handle_ack(m->slirp, srcsas, tp, m->m_len);
++        tftp_handle_ack(m->slirp, srcsas, hdr);
+         break;
+ 
+     case TFTP_ERROR:
+-        tftp_handle_error(m->slirp, srcsas, tp, m->m_len);
++        tftp_handle_error(m->slirp, srcsas, hdr);
+         break;
+     }
+ }
+diff --git a/src/tftp.h b/src/tftp.h
+index 6d75478..cafab03 100644
+--- a/src/tftp.h
++++ b/src/tftp.h
+@@ -20,9 +20,13 @@
+ #define TFTP_FILENAME_MAX 512
+ #define TFTP_BLOCKSIZE_MAX 1428
+ 
+-struct tftp_t {
++struct tftphdr {
+     struct udphdr udp;
+     uint16_t tp_op;
++} SLIRP_PACKED;
++
++struct tftp_t {
++    struct tftphdr hdr;
+     union {
+         struct {
+             uint16_t tp_block_nr;
+-- 
+2.30.2
+
diff -Nru libslirp-4.4.0/debian/patches/udp-check-upd_input-buffer-size-CVE-2021-3594.patch libslirp-4.4.0/debian/patches/udp-check-upd_input-buffer-size-CVE-2021-3594.patch
--- libslirp-4.4.0/debian/patches/udp-check-upd_input-buffer-size-CVE-2021-3594.patch	1970-01-01 03:00:00.000000000 +0300
+++ libslirp-4.4.0/debian/patches/udp-check-upd_input-buffer-size-CVE-2021-3594.patch	2021-09-30 21:04:37.000000000 +0300
@@ -0,0 +1,36 @@
+Commit-Id: 74572be49247c8c5feae7c6e0b50c4f569ca9824
+From: Marc-André Lureau <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 16:40:23 +0400
+Subject: udp: check upd_input buffer size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+Bug-Debian: https://bugs.debian.org/989995
+
+Fixes: CVE-2021-3594
+Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/47
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+---
+ src/udp.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/udp.c b/src/udp.c
+index 767ca85..06b7b7d 100644
+--- a/src/udp.c
++++ b/src/udp.c
+@@ -96,7 +96,10 @@ void udp_input(register struct mbuf *m, int iphlen)
+     /*
+      * Get IP and UDP header together in first mbuf.
+      */
+-    ip = mtod(m, struct ip *);
++    ip = mtod_check(m, iphlen + sizeof(struct udphdr));
++    if (ip == NULL) {
++        goto bad;
++    }
+     uh = (struct udphdr *)((char *)ip + iphlen);
+ 
+     /*
+-- 
+2.30.2
+
diff -Nru libslirp-4.4.0/debian/patches/upd6-check-udp6_input-buffer-size-CVE-2021-3593.patch libslirp-4.4.0/debian/patches/upd6-check-udp6_input-buffer-size-CVE-2021-3593.patch
--- libslirp-4.4.0/debian/patches/upd6-check-udp6_input-buffer-size-CVE-2021-3593.patch	1970-01-01 03:00:00.000000000 +0300
+++ libslirp-4.4.0/debian/patches/upd6-check-udp6_input-buffer-size-CVE-2021-3593.patch	2021-09-30 21:07:24.000000000 +0300
@@ -0,0 +1,36 @@
+Commit-Id: de71c15de66ba9350bf62c45b05f8fbff166517b
+From: Marc-André Lureau <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 16:32:55 +0400
+Subject: upd6: check udp6_input buffer size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+Bug-Debian: https://bugs.debian.org/989994
+
+Fixes: CVE-2021-3593
+Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/45
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+---
+ src/udp6.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/udp6.c b/src/udp6.c
+index 18ce998..efeac5c 100644
+--- a/src/udp6.c
++++ b/src/udp6.c
+@@ -31,7 +31,10 @@ void udp6_input(struct mbuf *m)
+     ip = mtod(m, struct ip6 *);
+     m->m_len -= iphlen;
+     m->m_data += iphlen;
+-    uh = mtod(m, struct udphdr *);
++    uh = mtod_check(m, sizeof(struct udphdr));
++    if (uh == NULL) {
++        goto bad;
++    }
+     m->m_len += iphlen;
+     m->m_data -= iphlen;
+ 
+-- 
+2.30.2
+

Reply to: