summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2024-08-06 02:47:22 +0000
committerCoprDistGit <infra@openeuler.org>2024-08-06 02:47:22 +0000
commitcf9ea042d268873a47b1adb344510276d321922b (patch)
tree2e51c1f557c545f3300bbefcea6624f35ad440de
parent2dad4dda28a4890d0385e4146ef440e7cb2823f3 (diff)
automatic import of libslirpopeneuler24.03_LTS
-rw-r--r--.gitignore1
-rw-r--r--0001-Add-mtod_check.patch54
-rw-r--r--0001-Fix-DHCP-broken-in-libslirp-v4.6.0.patch30
-rw-r--r--0001-New-utility-slirp_ether_ntoa.patch186
-rw-r--r--0001-ip-Enforce-strict-aliasing.patch412
-rw-r--r--0002-Replace-inet_ntoa-with-safer-inet_ntop.patch173
-rw-r--r--0002-bootp-limit-vendor-specific-area-to-input-packet-mem.patch161
-rw-r--r--0003-bootp-check-bootp_input-buffer-size.patch36
-rw-r--r--0004-upd6-check-udp6_input-buffer-size.patch36
-rw-r--r--0005-tftp-check-tftp_input-buffer-size.patch37
-rw-r--r--0006-tftp-introduce-a-header-structure.patch249
-rw-r--r--0007-udp-check-upd_input-buffer-size.patch36
-rw-r--r--libslirp.spec129
-rw-r--r--sources1
14 files changed, 1541 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..24fc108 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/libslirp-4.4.0.tar.xz
diff --git a/0001-Add-mtod_check.patch b/0001-Add-mtod_check.patch
new file mode 100644
index 0000000..fbdead1
--- /dev/null
+++ b/0001-Add-mtod_check.patch
@@ -0,0 +1,54 @@
+From 87f5d0c70bdb46d467d32e3c3a8d7a472c97e148 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 15:58:25 +0400
+Subject: [PATCH 1/7] 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>
+(cherry picked from commit 93e645e72a056ec0b2c16e0299fc5c6b94e4ca17)
+---
+ src/mbuf.c | 11 +++++++++++
+ src/mbuf.h | 1 +
+ 2 files changed, 12 insertions(+)
+
+diff --git a/src/mbuf.c b/src/mbuf.c
+index 54ec721..cb2e971 100644
+--- 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
+index 546e785..2015e32 100644
+--- 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.29.0
+
diff --git a/0001-Fix-DHCP-broken-in-libslirp-v4.6.0.patch b/0001-Fix-DHCP-broken-in-libslirp-v4.6.0.patch
new file mode 100644
index 0000000..bd4e685
--- /dev/null
+++ b/0001-Fix-DHCP-broken-in-libslirp-v4.6.0.patch
@@ -0,0 +1,30 @@
+From c9f314f6e315a5518432761fea864196a290f799 Mon Sep 17 00:00:00 2001
+From: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
+Date: Thu, 17 Jun 2021 18:01:32 +0900
+Subject: [PATCH] Fix "DHCP broken in libslirp v4.6.0"
+
+Fix issue 48
+
+Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
+---
+ src/bootp.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/bootp.c b/src/bootp.c
+index cafa1eb..0a35873 100644
+--- a/src/bootp.c
++++ b/src/bootp.c
+@@ -359,7 +359,9 @@ static void bootp_reply(Slirp *slirp,
+
+ daddr.sin_addr.s_addr = 0xffffffffu;
+
+- m->m_len = sizeof(struct bootp_t) - sizeof(struct ip) - sizeof(struct udphdr);
++ assert ((q - rbp->bp_vend + 1) <= DHCP_OPT_LEN);
++
++ m->m_len = sizeof(struct bootp_t) + (q - rbp->bp_vend + 1) - sizeof(struct ip) - sizeof(struct udphdr);
+ udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+ }
+
+--
+2.29.0
+
diff --git a/0001-New-utility-slirp_ether_ntoa.patch b/0001-New-utility-slirp_ether_ntoa.patch
new file mode 100644
index 0000000..823785b
--- /dev/null
+++ b/0001-New-utility-slirp_ether_ntoa.patch
@@ -0,0 +1,186 @@
+From c6fcedf4f53e070dfcb7a6910624705cdcc0a027 Mon Sep 17 00:00:00 2001
+From: Doug Evans <dje@google.com>
+Date: Tue, 23 Feb 2021 15:23:19 -0800
+Subject: [PATCH 1/2] New utility slirp_ether_ntoa
+
+... and call it everywhere a macaddr is pretty-printed.
+
+Signed-off-by: Doug Evans <dje@google.com>
+(cherry picked from commit ac00ba460e101bbce0a167b4f0517378a0fbe6b8)
+---
+ src/arp_table.c | 12 +++++++-----
+ src/ndp_table.c | 18 ++++++++++--------
+ src/slirp.c | 11 +++++------
+ src/util.c | 11 +++++++++++
+ src/util.h | 8 ++++++++
+ 5 files changed, 41 insertions(+), 19 deletions(-)
+
+diff --git a/src/arp_table.c b/src/arp_table.c
+index 959e5b9ec0af..ba8c8a4eee88 100644
+--- a/src/arp_table.c
++++ b/src/arp_table.c
+@@ -34,11 +34,12 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr,
+ ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
+ ArpTable *arptbl = &slirp->arp_table;
+ int i;
++ char ethaddr_str[ETH_ADDRSTRLEN];
+
+ DEBUG_CALL("arp_table_add");
+ DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr }));
+- DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x", ethaddr[0], ethaddr[1],
+- ethaddr[2], ethaddr[3], ethaddr[4], ethaddr[5]);
++ DEBUG_ARG("hw addr = %s", slirp_ether_ntoa(ethaddr, ethaddr_str,
++ sizeof(ethaddr_str)));
+
+ if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+ /* Do not register broadcast addresses */
+@@ -67,6 +68,7 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
+ ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
+ ArpTable *arptbl = &slirp->arp_table;
+ int i;
++ char ethaddr_str[ETH_ADDRSTRLEN];
+
+ DEBUG_CALL("arp_table_search");
+ DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr }));
+@@ -81,9 +83,9 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
+ for (i = 0; i < ARP_TABLE_SIZE; i++) {
+ if (arptbl->table[i].ar_sip == ip_addr) {
+ memcpy(out_ethaddr, arptbl->table[i].ar_sha, ETH_ALEN);
+- DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
+- out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+- out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
++ DEBUG_ARG("found hw addr = %s",
++ slirp_ether_ntoa(out_ethaddr, ethaddr_str,
++ sizeof(ethaddr_str)));
+ return 1;
+ }
+ }
+diff --git a/src/ndp_table.c b/src/ndp_table.c
+index 110d6ea0e43f..61ae8e0468fc 100644
+--- a/src/ndp_table.c
++++ b/src/ndp_table.c
+@@ -12,13 +12,14 @@ void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
+ char addrstr[INET6_ADDRSTRLEN];
+ NdpTable *ndp_table = &slirp->ndp_table;
+ int i;
++ char ethaddr_str[ETH_ADDRSTRLEN];
+
+ inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
+
+ DEBUG_CALL("ndp_table_add");
+ DEBUG_ARG("ip = %s", addrstr);
+- DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x", ethaddr[0], ethaddr[1],
+- ethaddr[2], ethaddr[3], ethaddr[4], ethaddr[5]);
++ DEBUG_ARG("hw addr = %s", slirp_ether_ntoa(ethaddr, ethaddr_str,
++ sizeof(ethaddr_str)));
+
+ if (IN6_IS_ADDR_MULTICAST(&ip_addr) || in6_zero(&ip_addr)) {
+ /* Do not register multicast or unspecified addresses */
+@@ -50,6 +51,7 @@ bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
+ char addrstr[INET6_ADDRSTRLEN];
+ NdpTable *ndp_table = &slirp->ndp_table;
+ int i;
++ char ethaddr_str[ETH_ADDRSTRLEN];
+
+ inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
+
+@@ -66,18 +68,18 @@ bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
+ out_ethaddr[3] = ip_addr.s6_addr[13];
+ out_ethaddr[4] = ip_addr.s6_addr[14];
+ out_ethaddr[5] = ip_addr.s6_addr[15];
+- DEBUG_ARG("multicast addr = %02x:%02x:%02x:%02x:%02x:%02x",
+- out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+- out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
++ DEBUG_ARG("multicast addr = %s",
++ slirp_ether_ntoa(out_ethaddr, ethaddr_str,
++ sizeof(ethaddr_str)));
+ return 1;
+ }
+
+ for (i = 0; i < NDP_TABLE_SIZE; i++) {
+ if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
+ memcpy(out_ethaddr, ndp_table->table[i].eth_addr, ETH_ALEN);
+- DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
+- out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+- out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
++ DEBUG_ARG("found hw addr = %s",
++ slirp_ether_ntoa(out_ethaddr, ethaddr_str,
++ sizeof(ethaddr_str)));
+ return 1;
+ }
+ }
+diff --git a/src/slirp.c b/src/slirp.c
+index abb6f9a966d8..1f2513a9e1a4 100644
+--- a/src/slirp.c
++++ b/src/slirp.c
+@@ -1054,6 +1054,7 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
+ uint8_t ethaddr[ETH_ALEN];
+ const struct ip *iph = (const struct ip *)ifm->m_data;
+ int ret;
++ char ethaddr_str[ETH_ADDRSTRLEN];
+
+ if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
+ return 1;
+@@ -1079,12 +1080,10 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
+ }
+
+ memcpy(eh->h_dest, ethaddr, ETH_ALEN);
+- DEBUG_ARG("src = %02x:%02x:%02x:%02x:%02x:%02x", eh->h_source[0],
+- eh->h_source[1], eh->h_source[2], eh->h_source[3],
+- eh->h_source[4], eh->h_source[5]);
+- DEBUG_ARG("dst = %02x:%02x:%02x:%02x:%02x:%02x", eh->h_dest[0],
+- eh->h_dest[1], eh->h_dest[2], eh->h_dest[3], eh->h_dest[4],
+- eh->h_dest[5]);
++ DEBUG_ARG("src = %s", slirp_ether_ntoa(eh->h_source, ethaddr_str,
++ sizeof(ethaddr_str)));
++ DEBUG_ARG("dst = %s", slirp_ether_ntoa(eh->h_dest, ethaddr_str,
++ sizeof(ethaddr_str)));
+ memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
+ slirp_send_packet_all(slirp, buf, ifm->m_len + ETH_HLEN);
+ return 1;
+diff --git a/src/util.c b/src/util.c
+index 2d8fb9642e76..67ef66786f54 100644
+--- a/src/util.c
++++ b/src/util.c
+@@ -427,3 +427,14 @@ int slirp_fmt0(char *str, size_t size, const char *format, ...)
+
+ return rv;
+ }
++
++const char *slirp_ether_ntoa(const uint8_t *addr, char *out_str,
++ size_t out_str_size)
++{
++ assert(out_str_size >= ETH_ADDRSTRLEN);
++
++ slirp_fmt0(out_str, out_str_size, "%02x:%02x:%02x:%02x:%02x:%02x",
++ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
++
++ return out_str;
++}
+diff --git a/src/util.h b/src/util.h
+index d67b3d0de9aa..8134db961779 100644
+--- a/src/util.h
++++ b/src/util.h
+@@ -84,6 +84,7 @@ struct iovec {
+ #define SCALE_MS 1000000
+
+ #define ETH_ALEN 6
++#define ETH_ADDRSTRLEN 18 /* "xx:xx:xx:xx:xx:xx", with trailing NUL */
+ #define ETH_HLEN 14
+ #define ETH_P_IP (0x0800) /* Internet Protocol packet */
+ #define ETH_P_ARP (0x0806) /* Address Resolution packet */
+@@ -186,4 +187,11 @@ void slirp_pstrcpy(char *buf, int buf_size, const char *str);
+ int slirp_fmt(char *str, size_t size, const char *format, ...) G_GNUC_PRINTF(3, 4);
+ int slirp_fmt0(char *str, size_t size, const char *format, ...) G_GNUC_PRINTF(3, 4);
+
++/*
++ * Pretty print a MAC address into out_str.
++ * As a convenience returns out_str.
++ */
++const char *slirp_ether_ntoa(const uint8_t *addr, char *out_str,
++ size_t out_str_len);
++
+ #endif
+--
+2.34.1.428.gdcc0cd074f0c
+
diff --git a/0001-ip-Enforce-strict-aliasing.patch b/0001-ip-Enforce-strict-aliasing.patch
new file mode 100644
index 0000000..3080bd0
--- /dev/null
+++ b/0001-ip-Enforce-strict-aliasing.patch
@@ -0,0 +1,412 @@
+From 5f19b8960548bd0704ae7054dce599ec1abcf258 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
+Date: Mon, 4 Mar 2024 22:49:39 +0400
+Subject: [PATCH] ip: Enforce strict aliasing
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+JIRA: RHEL-27868
+
+Sometimes ipq were casted to ipasfrag, and the original and casted
+pointer were used simultaneously in ip_reass(). GCC 12.1.0 assumes
+these pointers are not aliases, and therefore incorrectly the pointed
+data will not be modified when it is actually modified with another
+pointer.
+
+To fix this problem, introduce a new type "ipas", which is a universal
+type denoting an entry in the assembly queue and contains union for
+specialization as queue head (frequently referred as "q" or "ipq" in
+the source code) or IP fragment ("f" or "ipf").
+
+This bug was found by Alexander Bulekov when fuzzing QEMU:
+https://patchew.org/QEMU/20230129053316.1071513-1-alxndr@bu.edu/
+
+The fixed test case is:
+fuzz/crash_449dd4ad72212627fe3245c875f79a7033cc5382
+
+Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
+Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+
+(cherry picked from commit 26be815b86e8d49add8c9a8b320239b9594ff03d)
+[ Marc-André - various backport conflicts in ip_input.c ]
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+---
+ src/ip.h | 21 ++----
+ src/ip_input.c | 170 ++++++++++++++++++++++++-------------------------
+ 2 files changed, 91 insertions(+), 100 deletions(-)
+
+diff --git a/src/ip.h b/src/ip.h
+index e5d4aa8..ab1144d 100644
+--- a/src/ip.h
++++ b/src/ip.h
+@@ -209,10 +209,8 @@ struct ipovly {
+ * being reassembled is attached to one of these structures.
+ * They are timed out after ipq_ttl drops to 0, and may also
+ * be reclaimed if memory becomes tight.
+- * size 28 bytes
+ */
+ struct ipq {
+- struct qlink frag_link; /* to ip headers of fragments */
+ struct qlink ip_link; /* to other reass headers */
+ uint8_t ipq_ttl; /* time for reass q to live */
+ uint8_t ipq_p; /* protocol of this fragment */
+@@ -220,23 +218,16 @@ struct ipq {
+ struct in_addr ipq_src, ipq_dst;
+ };
+
+-/*
+- * Ip header, when holding a fragment.
+- *
+- * Note: ipf_link must be at same offset as frag_link above
+- */
+-struct ipasfrag {
+- struct qlink ipf_link;
+- struct ip ipf_ip;
++struct ipas {
++ struct qlink link;
++ union {
++ struct ipq ipq;
++ struct ip ipf_ip;
++ };
+ };
+
+-G_STATIC_ASSERT(offsetof(struct ipq, frag_link) ==
+- offsetof(struct ipasfrag, ipf_link));
+-
+ #define ipf_off ipf_ip.ip_off
+ #define ipf_tos ipf_ip.ip_tos
+ #define ipf_len ipf_ip.ip_len
+-#define ipf_next ipf_link.next
+-#define ipf_prev ipf_link.prev
+
+ #endif
+diff --git a/src/ip_input.c b/src/ip_input.c
+index 7f017a2..aac56a9 100644
+--- a/src/ip_input.c
++++ b/src/ip_input.c
+@@ -41,8 +41,8 @@
+
+ static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp);
+ static void ip_freef(Slirp *slirp, struct ipq *fp);
+-static void ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev);
+-static void ip_deq(register struct ipasfrag *p);
++static void ip_enq(register struct ipas *p, register struct ipas *prev);
++static void ip_deq(register struct ipas *p);
+
+ /*
+ * IP initialization: fill in IP protocol switch table.
+@@ -144,7 +144,7 @@ void ip_input(struct mbuf *m)
+ * XXX This should fail, don't fragment yet
+ */
+ if (ip->ip_off & ~IP_DF) {
+- register struct ipq *fp;
++ register struct ipq *q;
+ struct qlink *l;
+ /*
+ * Look for queue of fragments
+@@ -152,14 +152,14 @@ void ip_input(struct mbuf *m)
+ */
+ for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link;
+ l = l->next) {
+- fp = container_of(l, struct ipq, ip_link);
+- if (ip->ip_id == fp->ipq_id &&
+- ip->ip_src.s_addr == fp->ipq_src.s_addr &&
+- ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
+- ip->ip_p == fp->ipq_p)
++ q = container_of(l, struct ipq, ip_link);
++ if (ip->ip_id == q->ipq_id &&
++ ip->ip_src.s_addr == q->ipq_src.s_addr &&
++ ip->ip_dst.s_addr == q->ipq_dst.s_addr &&
++ ip->ip_p == q->ipq_p)
+ goto found;
+ }
+- fp = NULL;
++ q = NULL;
+ found:
+
+ /*
+@@ -181,12 +181,12 @@ void ip_input(struct mbuf *m)
+ * attempt reassembly; if it succeeds, proceed.
+ */
+ if (ip->ip_tos & 1 || ip->ip_off) {
+- ip = ip_reass(slirp, ip, fp);
++ ip = ip_reass(slirp, ip, q);
+ if (ip == NULL)
+ return;
+ m = dtom(slirp, ip);
+- } else if (fp)
+- ip_freef(slirp, fp);
++ } else if (q)
++ ip_freef(slirp, q);
+
+ } else
+ ip->ip_len -= hlen;
+@@ -212,24 +212,25 @@ bad:
+ m_free(m);
+ }
+
+-#define iptofrag(P) ((struct ipasfrag *)(((char *)(P)) - sizeof(struct qlink)))
+-#define fragtoip(P) ((struct ip *)(((char *)(P)) + sizeof(struct qlink)))
++#define iptoas(P) container_of((P), struct ipas, ipf_ip)
++#define astoip(P) (&(P)->ipf_ip)
+ /*
+ * Take incoming datagram fragment and try to
+ * reassemble it into whole datagram. If a chain for
+ * reassembly of this datagram already exists, then it
+- * is given as fp; otherwise have to make a chain.
++ * is given as q; otherwise have to make a chain.
+ */
+-static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
++static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *q)
+ {
+ register struct mbuf *m = dtom(slirp, ip);
+- register struct ipasfrag *q;
++ struct ipas *first = container_of(q, struct ipas, ipq);
++ register struct ipas *cursor;
+ int hlen = ip->ip_hl << 2;
+ int i, next;
+
+ DEBUG_CALL("ip_reass");
+ DEBUG_ARG("ip = %p", ip);
+- DEBUG_ARG("fp = %p", fp);
++ DEBUG_ARG("q = %p", q);
+ DEBUG_ARG("m = %p", m);
+
+ /*
+@@ -243,30 +244,30 @@ static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
+ /*
+ * If first fragment to arrive, create a reassembly queue.
+ */
+- if (fp == NULL) {
++ if (q == NULL) {
+ struct mbuf *t = m_get(slirp);
+
+ if (t == NULL) {
+ goto dropfrag;
+ }
+- fp = mtod(t, struct ipq *);
+- insque(&fp->ip_link, &slirp->ipq.ip_link);
+- fp->ipq_ttl = IPFRAGTTL;
+- fp->ipq_p = ip->ip_p;
+- fp->ipq_id = ip->ip_id;
+- fp->frag_link.next = fp->frag_link.prev = &fp->frag_link;
+- fp->ipq_src = ip->ip_src;
+- fp->ipq_dst = ip->ip_dst;
+- q = (struct ipasfrag *)fp;
++ first = mtod(t, struct ipas *);
++ q = &first->ipq;
++ slirp_insque(&q->ip_link, &slirp->ipq.ip_link);
++ q->ipq_ttl = IPFRAGTTL;
++ q->ipq_p = ip->ip_p;
++ q->ipq_id = ip->ip_id;
++ first->link.next = first->link.prev = first;
++ q->ipq_src = ip->ip_src;
++ q->ipq_dst = ip->ip_dst;
++ cursor = first;
+ goto insert;
+ }
+
+ /*
+ * Find a segment which begins after this one does.
+ */
+- for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
+- q = q->ipf_next)
+- if (q->ipf_off > ip->ip_off)
++ for (cursor = first->link.next; cursor != first; cursor = cursor->link.next)
++ if (cursor->ipf_off > ip->ip_off)
+ break;
+
+ /*
+@@ -274,8 +275,8 @@ static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
+ * our data already. If so, drop the data from the incoming
+ * segment. If it provides all of our data, drop us.
+ */
+- if (q->ipf_prev != &fp->frag_link) {
+- struct ipasfrag *pq = q->ipf_prev;
++ if (cursor->link.prev != first) {
++ struct ipas *pq = cursor->link.prev;
+ i = pq->ipf_off + pq->ipf_len - ip->ip_off;
+ if (i > 0) {
+ if (i >= ip->ip_len)
+@@ -290,18 +291,17 @@ static struct ip *ip_reass(Slirp *slirp, struct ip *ip, struct ipq *fp)
+ * While we overlap succeeding segments trim them or,
+ * if they are completely covered, dequeue them.
+ */
+- while (q != (struct ipasfrag *)&fp->frag_link &&
+- ip->ip_off + ip->ip_len > q->ipf_off) {
+- struct ipasfrag *prev;
+- i = (ip->ip_off + ip->ip_len) - q->ipf_off;
+- if (i < q->ipf_len) {
+- q->ipf_len -= i;
+- q->ipf_off += i;
+- m_adj(dtom(slirp, q), i);
++ while (cursor != first && ip->ip_off + ip->ip_len > cursor->ipf_off) {
++ struct ipas *prev;
++ i = (ip->ip_off + ip->ip_len) - cursor->ipf_off;
++ if (i < cursor->ipf_len) {
++ cursor->ipf_len -= i;
++ cursor->ipf_off += i;
++ m_adj(dtom(slirp, cursor), i);
+ break;
+ }
+- prev = q;
+- q = q->ipf_next;
++ prev = cursor;
++ cursor = cursor->link.next;
+ ip_deq(prev);
+ m_free(dtom(slirp, prev));
+ }
+@@ -311,28 +311,27 @@ insert:
+ * Stick new segment in its place;
+ * check for complete reassembly.
+ */
+- ip_enq(iptofrag(ip), q->ipf_prev);
++ ip_enq(iptoas(ip), cursor->link.prev);
+ next = 0;
+- for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
+- q = q->ipf_next) {
+- if (q->ipf_off != next)
++ for (cursor = first->link.next; cursor != first; cursor = cursor->link.next) {
++ if (cursor->ipf_off != next)
+ return NULL;
+- next += q->ipf_len;
++ next += cursor->ipf_len;
+ }
+- if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1)
++ if (((struct ipas *)(cursor->link.prev))->ipf_tos & 1)
+ return NULL;
+
+ /*
+ * Reassembly is complete; concatenate fragments.
+ */
+- q = fp->frag_link.next;
+- m = dtom(slirp, q);
+- int delta = (char *)q - (m->m_flags & M_EXT ? m->m_ext : m->m_dat);
+-
+- q = (struct ipasfrag *)q->ipf_next;
+- while (q != (struct ipasfrag *)&fp->frag_link) {
+- struct mbuf *t = dtom(slirp, q);
+- q = (struct ipasfrag *)q->ipf_next;
++ cursor = first->link.next;
++ m = dtom(slirp, cursor);
++ int delta = (char *)cursor - (m->m_flags & M_EXT ? m->m_ext : m->m_dat);
++
++ cursor = cursor->link.next;
++ while (cursor != first) {
++ struct mbuf *t = dtom(slirp, cursor);
++ cursor = cursor->link.next;
+ m_cat(m, t);
+ }
+
+@@ -342,25 +341,25 @@ insert:
+ * dequeue and discard fragment reassembly header.
+ * Make header visible.
+ */
+- q = fp->frag_link.next;
++ cursor = first->link.next;
+
+ /*
+ * If the fragments concatenated to an mbuf that's bigger than the total
+ * size of the fragment and the mbuf was not already using an m_ext buffer,
+- * then an m_ext buffer was alloced. But fp->ipq_next points to the old
++ * then an m_ext buffer was alloced. But q->ipq_next points to the old
+ * buffer (in the mbuf), so we must point ip into the new buffer.
+ */
+ if (m->m_flags & M_EXT) {
+- q = (struct ipasfrag *)(m->m_ext + delta);
++ cursor = (struct ipas *)(m->m_ext + delta);
+ }
+
+- ip = fragtoip(q);
++ ip = astoip(cursor);
+ ip->ip_len = next;
+ ip->ip_tos &= ~1;
+- ip->ip_src = fp->ipq_src;
+- ip->ip_dst = fp->ipq_dst;
+- remque(&fp->ip_link);
+- (void)m_free(dtom(slirp, fp));
++ ip->ip_src = q->ipq_src;
++ ip->ip_dst = q->ipq_dst;
++ slirp_remque(&q->ip_link);
++ m_free(dtom(slirp, q));
+ m->m_len += (ip->ip_hl << 2);
+ m->m_data -= (ip->ip_hl << 2);
+
+@@ -375,41 +374,42 @@ dropfrag:
+ * Free a fragment reassembly header and all
+ * associated datagrams.
+ */
+-static void ip_freef(Slirp *slirp, struct ipq *fp)
++static void ip_freef(Slirp *slirp, struct ipq *q)
+ {
+- register struct ipasfrag *q, *p;
++ struct ipas *first = container_of(q, struct ipas, ipq);
++ register struct ipas *cursor, *next;
+
+- for (q = fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link;
+- q = p) {
+- p = q->ipf_next;
+- ip_deq(q);
+- m_free(dtom(slirp, q));
++ for (cursor = first->link.next; cursor != first; cursor = next) {
++ next = cursor->link.next;
++ ip_deq(cursor);
++ m_free(dtom(slirp, cursor));
+ }
+- remque(&fp->ip_link);
+- (void)m_free(dtom(slirp, fp));
++
++ slirp_remque(&q->ip_link);
++ m_free(dtom(slirp, q));
+ }
+
+ /*
+ * Put an ip fragment on a reassembly chain.
+ * Like insque, but pointers in middle of structure.
+ */
+-static void ip_enq(register struct ipasfrag *p, register struct ipasfrag *prev)
++static void ip_enq(register struct ipas *p, register struct ipas *prev)
+ {
+ DEBUG_CALL("ip_enq");
+ DEBUG_ARG("prev = %p", prev);
+- p->ipf_prev = prev;
+- p->ipf_next = prev->ipf_next;
+- ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p;
+- prev->ipf_next = p;
++ p->link.prev = prev;
++ p->link.next = prev->link.next;
++ ((struct ipas *)(prev->link.next))->link.prev = p;
++ prev->link.next = p;
+ }
+
+ /*
+ * To ip_enq as remque is to insque.
+ */
+-static void ip_deq(register struct ipasfrag *p)
++static void ip_deq(register struct ipas *p)
+ {
+- ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next;
+- ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev;
++ ((struct ipas *)(p->link.prev))->link.next = p->link.next;
++ ((struct ipas *)(p->link.next))->link.prev = p->link.prev;
+ }
+
+ /*
+@@ -429,10 +429,10 @@ void ip_slowtimo(Slirp *slirp)
+ return;
+
+ while (l != &slirp->ipq.ip_link) {
+- struct ipq *fp = container_of(l, struct ipq, ip_link);
++ struct ipq *q = container_of(l, struct ipq, ip_link);
+ l = l->next;
+- if (--fp->ipq_ttl == 0) {
+- ip_freef(slirp, fp);
++ if (--q->ipq_ttl == 0) {
++ ip_freef(slirp, q);
+ }
+ }
+ }
+--
+2.44.0
+
diff --git a/0002-Replace-inet_ntoa-with-safer-inet_ntop.patch b/0002-Replace-inet_ntoa-with-safer-inet_ntop.patch
new file mode 100644
index 0000000..908b144
--- /dev/null
+++ b/0002-Replace-inet_ntoa-with-safer-inet_ntop.patch
@@ -0,0 +1,173 @@
+From 849c972aa16a85c860f67d7e7f1fbe58e45187d2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
+Date: Wed, 9 Feb 2022 22:15:08 +0400
+Subject: [PATCH 2/2] Replace inet_ntoa() with safer inet_ntop()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+inet_ntoa() returns a static pointer which is subject to safety issues.
+Use the recommended alternative.
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+---
+ src/arp_table.c | 8 ++++++--
+ src/ip_icmp.c | 10 ++++++----
+ src/misc.c | 22 +++++++++++++---------
+ src/socket.c | 5 +++--
+ src/udp.c | 5 +++--
+ 5 files changed, 31 insertions(+), 19 deletions(-)
+
+diff --git a/src/arp_table.c b/src/arp_table.c
+index ba8c8a4eee88..3cf2ecc238bc 100644
+--- a/src/arp_table.c
++++ b/src/arp_table.c
+@@ -35,9 +35,11 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr,
+ ArpTable *arptbl = &slirp->arp_table;
+ int i;
+ char ethaddr_str[ETH_ADDRSTRLEN];
++ char addr[INET_ADDRSTRLEN];
+
+ DEBUG_CALL("arp_table_add");
+- DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr }));
++ DEBUG_ARG("ip = %s", inet_ntop(AF_INET, &(struct in_addr){ .s_addr = ip_addr },
++ addr, sizeof(addr)));
+ DEBUG_ARG("hw addr = %s", slirp_ether_ntoa(ethaddr, ethaddr_str,
+ sizeof(ethaddr_str)));
+
+@@ -69,9 +71,11 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
+ ArpTable *arptbl = &slirp->arp_table;
+ int i;
+ char ethaddr_str[ETH_ADDRSTRLEN];
++ char addr[INET_ADDRSTRLEN];
+
+ DEBUG_CALL("arp_table_search");
+- DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){ .s_addr = ip_addr }));
++ DEBUG_ARG("ip = %s", inet_ntop(AF_INET, &(struct in_addr){ .s_addr = ip_addr },
++ addr, sizeof(addr)));
+
+ /* If broadcast address */
+ if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+diff --git a/src/ip_icmp.c b/src/ip_icmp.c
+index f4d686b0222d..26e44a3fd49c 100644
+--- a/src/ip_icmp.c
++++ b/src/ip_icmp.c
+@@ -291,10 +291,12 @@ void icmp_forward_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsi
+ goto end_error;
+ ip = mtod(msrc, struct ip *);
+ if (slirp_debug & DBG_MISC) {
+- char bufa[20], bufb[20];
+- slirp_pstrcpy(bufa, sizeof(bufa), inet_ntoa(ip->ip_src));
+- slirp_pstrcpy(bufb, sizeof(bufb), inet_ntoa(ip->ip_dst));
+- DEBUG_MISC(" %.16s to %.16s", bufa, bufb);
++ char addr_src[INET_ADDRSTRLEN];
++ char addr_dst[INET_ADDRSTRLEN];
++
++ inet_ntop(AF_INET, &ip->ip_src, addr_src, sizeof(addr_src));
++ inet_ntop(AF_INET, &ip->ip_dst, addr_dst, sizeof(addr_dst));
++ DEBUG_MISC(" %.16s to %.16s", addr_src, addr_dst);
+ }
+ if (ip->ip_off & IP_OFFMASK)
+ goto end_error; /* Only reply to fragment 0 */
+diff --git a/src/misc.c b/src/misc.c
+index e6bc0a207d0b..1306f68eb539 100644
+--- a/src/misc.c
++++ b/src/misc.c
+@@ -293,6 +293,7 @@ char *slirp_connection_info(Slirp *slirp)
+ uint16_t dst_port;
+ struct socket *so;
+ const char *state;
++ char addr[INET_ADDRSTRLEN];
+ char buf[20];
+
+ g_string_append_printf(str,
+@@ -322,10 +323,11 @@ char *slirp_connection_info(Slirp *slirp)
+ }
+ slirp_fmt0(buf, sizeof(buf), " TCP[%s]", state);
+ g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
+- src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) :
+- "*",
++ src.sin_addr.s_addr ?
++ inet_ntop(AF_INET, &src.sin_addr, addr, sizeof(addr)) : "*",
+ ntohs(src.sin_port));
+- g_string_append_printf(str, "%15s %5d %5d %5d\n", inet_ntoa(dst_addr),
++ g_string_append_printf(str, "%15s %5d %5d %5d\n",
++ inet_ntop(AF_INET, &dst_addr, addr, sizeof(addr)),
+ ntohs(dst_port), so->so_rcv.sb_cc,
+ so->so_snd.sb_cc);
+ }
+@@ -346,10 +348,11 @@ char *slirp_connection_info(Slirp *slirp)
+ dst_port = so->so_fport;
+ }
+ g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
+- src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) :
+- "*",
++ src.sin_addr.s_addr ?
++ inet_ntop(AF_INET, &src.sin_addr, addr, sizeof(addr)) : "*",
+ ntohs(src.sin_port));
+- g_string_append_printf(str, "%15s %5d %5d %5d\n", inet_ntoa(dst_addr),
++ g_string_append_printf(str, "%15s %5d %5d %5d\n",
++ inet_ntop(AF_INET, &dst_addr, addr, sizeof(addr)),
+ ntohs(dst_port), so->so_rcv.sb_cc,
+ so->so_snd.sb_cc);
+ }
+@@ -360,9 +363,10 @@ char *slirp_connection_info(Slirp *slirp)
+ src.sin_addr = so->so_laddr;
+ dst_addr = so->so_faddr;
+ g_string_append_printf(str, "%-19s %3d %15s - ", buf, so->s,
+- src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) :
+- "*");
+- g_string_append_printf(str, "%15s - %5d %5d\n", inet_ntoa(dst_addr),
++ src.sin_addr.s_addr ?
++ inet_ntop(AF_INET, &src.sin_addr, addr, sizeof(addr)) : "*");
++ g_string_append_printf(str, "%15s - %5d %5d\n",
++ inet_ntop(AF_INET, &dst_addr, addr, sizeof(addr)),
+ so->so_rcv.sb_cc, so->so_snd.sb_cc);
+ }
+
+diff --git a/src/socket.c b/src/socket.c
+index c0b02ad131f3..6607e319ad6c 100644
+--- a/src/socket.c
++++ b/src/socket.c
+@@ -743,13 +743,14 @@ struct socket *tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
+ struct sockaddr_in addr;
+ struct socket *so;
+ int s, opt = 1;
++ char inet_addr[INET_ADDRSTRLEN];
+ socklen_t addrlen = sizeof(addr);
+ memset(&addr, 0, addrlen);
+
+ DEBUG_CALL("tcp_listen");
+- DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){ .s_addr = haddr }));
++ DEBUG_ARG("haddr = %s", inet_ntop(AF_INET, &(struct in_addr){ .s_addr = haddr }, inet_addr, sizeof(inet_addr)));
+ DEBUG_ARG("hport = %d", ntohs(hport));
+- DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){ .s_addr = laddr }));
++ DEBUG_ARG("laddr = %s", inet_ntop(AF_INET, &(struct in_addr){ .s_addr = laddr }, inet_addr, sizeof(inet_addr)));
+ DEBUG_ARG("lport = %d", ntohs(lport));
+ DEBUG_ARG("flags = %x", flags);
+
+diff --git a/src/udp.c b/src/udp.c
+index e4578aa94ed5..0547cd6fc5c3 100644
+--- a/src/udp.c
++++ b/src/udp.c
+@@ -248,14 +248,15 @@ bad:
+ int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr,
+ struct sockaddr_in *daddr, int iptos)
+ {
++ char addr[INET_ADDRSTRLEN];
+ register struct udpiphdr *ui;
+ int error = 0;
+
+ DEBUG_CALL("udp_output");
+ DEBUG_ARG("so = %p", so);
+ DEBUG_ARG("m = %p", m);
+- DEBUG_ARG("saddr = %s", inet_ntoa(saddr->sin_addr));
+- DEBUG_ARG("daddr = %s", inet_ntoa(daddr->sin_addr));
++ DEBUG_ARG("saddr = %s", inet_ntop(AF_INET, &saddr->sin_addr, addr, sizeof(addr)));
++ DEBUG_ARG("daddr = %s", inet_ntop(AF_INET, &daddr->sin_addr, addr, sizeof(addr)));
+
+ /*
+ * Adjust for header
+--
+2.34.1.428.gdcc0cd074f0c
+
diff --git a/0002-bootp-limit-vendor-specific-area-to-input-packet-mem.patch b/0002-bootp-limit-vendor-specific-area-to-input-packet-mem.patch
new file mode 100644
index 0000000..88e5ba0
--- /dev/null
+++ b/0002-bootp-limit-vendor-specific-area-to-input-packet-mem.patch
@@ -0,0 +1,161 @@
+From f0d4faae8258385338bc1ec252250454346b7ef7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 19:25:28 +0400
+Subject: [PATCH 2/7] 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
+
+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>
+(cherry picked from commit f13cad45b25d92760bb0ad67bec0300a4d7d5275)
+---
+ 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 cb2e971..0c1a530 100644
+--- a/src/mbuf.c
++++ b/src/mbuf.c
+@@ -233,3 +233,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 2015e32..a9752a3 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.29.0
+
diff --git a/0003-bootp-check-bootp_input-buffer-size.patch b/0003-bootp-check-bootp_input-buffer-size.patch
new file mode 100644
index 0000000..c97cb12
--- /dev/null
+++ b/0003-bootp-check-bootp_input-buffer-size.patch
@@ -0,0 +1,36 @@
+From 0f017f39a390d8fa4ae817f45fbf71a0c8332860 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 16:15:14 +0400
+Subject: [PATCH 3/7] bootp: check bootp_input buffer size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fixes: CVE-2021-3592
+Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/44
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+(cherry picked from commit 2eca0838eee1da96204545e22cdaed860d9d7c6c)
+---
+ 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.29.0
+
diff --git a/0004-upd6-check-udp6_input-buffer-size.patch b/0004-upd6-check-udp6_input-buffer-size.patch
new file mode 100644
index 0000000..a832f6b
--- /dev/null
+++ b/0004-upd6-check-udp6_input-buffer-size.patch
@@ -0,0 +1,36 @@
+From 30feadb676a0792036a0f64309235c5767e2ee76 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 16:32:55 +0400
+Subject: [PATCH 4/7] upd6: check udp6_input buffer size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fixes: CVE-2021-3593
+Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/45
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+(cherry picked from commit de71c15de66ba9350bf62c45b05f8fbff166517b)
+---
+ src/udp6.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/udp6.c b/src/udp6.c
+index fdd8089..236b962 100644
+--- a/src/udp6.c
++++ b/src/udp6.c
+@@ -29,7 +29,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.29.0
+
diff --git a/0005-tftp-check-tftp_input-buffer-size.patch b/0005-tftp-check-tftp_input-buffer-size.patch
new file mode 100644
index 0000000..1d879cc
--- /dev/null
+++ b/0005-tftp-check-tftp_input-buffer-size.patch
@@ -0,0 +1,37 @@
+From 31aaf902aa6ba31ab8f41543b2d4da8c01f3b861 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 16:34:30 +0400
+Subject: [PATCH 5/7] tftp: check tftp_input buffer size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fixes: CVE-2021-3595
+Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/46
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+(cherry picked from commit 3f17948137155f025f7809fdc38576d5d2451c3d)
+---
+ 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.29.0
+
diff --git a/0006-tftp-introduce-a-header-structure.patch b/0006-tftp-introduce-a-header-structure.patch
new file mode 100644
index 0000000..f163137
--- /dev/null
+++ b/0006-tftp-introduce-a-header-structure.patch
@@ -0,0 +1,249 @@
+From c8665ebbdadb72f7c2cb74b9704f68704c13653b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 20:01:20 +0400
+Subject: [PATCH 6/7] tftp: introduce a header structure
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+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>
+(cherry picked from commit 990163cf3ac86b7875559f49602c4d76f46f6f30)
+---
+ 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.29.0
+
diff --git a/0007-udp-check-upd_input-buffer-size.patch b/0007-udp-check-upd_input-buffer-size.patch
new file mode 100644
index 0000000..7fc155d
--- /dev/null
+++ b/0007-udp-check-upd_input-buffer-size.patch
@@ -0,0 +1,36 @@
+From ca41f7eaa58d3f63a3df58d812b3cec32343ab6a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
+Date: Fri, 4 Jun 2021 16:40:23 +0400
+Subject: [PATCH 7/7] udp: check upd_input buffer size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Fixes: CVE-2021-3594
+Fixes: https://gitlab.freedesktop.org/slirp/libslirp/-/issues/47
+
+Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
+(cherry picked from commit 74572be49247c8c5feae7c6e0b50c4f569ca9824)
+---
+ src/udp.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/udp.c b/src/udp.c
+index 050cee4..e4578aa 100644
+--- a/src/udp.c
++++ b/src/udp.c
+@@ -94,7 +94,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.29.0
+
diff --git a/libslirp.spec b/libslirp.spec
new file mode 100644
index 0000000..83986a1
--- /dev/null
+++ b/libslirp.spec
@@ -0,0 +1,129 @@
+Name: libslirp
+Version: 4.4.0
+Release: 8%{?dist}
+Summary: A general purpose TCP-IP emulator
+
+# check the SPDX tags in source files for details
+License: BSD and MIT
+URL: https://gitlab.freedesktop.org/slirp/%{name}
+Source0: %{url}/-/archive/v%{version}/%{name}-%{version}.tar.xz
+Patch0001: 0001-Add-mtod_check.patch
+Patch0002: 0002-bootp-limit-vendor-specific-area-to-input-packet-mem.patch
+Patch0003: 0003-bootp-check-bootp_input-buffer-size.patch
+Patch0004: 0004-upd6-check-udp6_input-buffer-size.patch
+Patch0005: 0005-tftp-check-tftp_input-buffer-size.patch
+Patch0006: 0006-tftp-introduce-a-header-structure.patch
+Patch0007: 0007-udp-check-upd_input-buffer-size.patch
+Patch0008: 0001-Fix-DHCP-broken-in-libslirp-v4.6.0.patch
+Patch0009: 0001-New-utility-slirp_ether_ntoa.patch
+Patch0010: 0002-Replace-inet_ntoa-with-safer-inet_ntop.patch
+Patch0011: 0001-ip-Enforce-strict-aliasing.patch
+
+
+BuildRequires: git-core
+BuildRequires: meson
+BuildRequires: gcc
+BuildRequires: glib2-devel
+
+%description
+A general purpose TCP-IP emulator used by virtual machine hypervisors
+to provide virtual networking services.
+
+
+%package devel
+Summary: Development files for %{name}
+Requires: %{name}%{?_isa} = %{version}-%{release}
+
+%description devel
+The %{name}-devel package contains libraries and header files for
+developing applications that use %{name}.
+
+
+%prep
+%autosetup -S git_am
+
+%build
+%meson
+%meson_build
+
+
+%install
+%meson_install
+
+
+%files
+%license COPYRIGHT
+%doc README.md CHANGELOG.md
+%{_libdir}/%{name}.so.0*
+
+%files devel
+%dir %{_includedir}/slirp/
+%{_includedir}/slirp/*
+%{_libdir}/%{name}.so
+%{_libdir}/pkgconfig/slirp.pc
+
+
+%changelog
+* Mon Jun 03 2024 Marc-André Lureau <marcandre.lureau@redhat.com> - 4.4.0-8
+- Backport upstream commit b09dbd9557 ("ip: Enforce strict aliasing")
+ Fixes JIRA RHEL-27868
+
+* Fri Feb 11 2022 Jindrich Novy <jnovy@redhat.com> - 4.4.0-7
+- fix also socket.c, thanks to Marc-André Lureau
+- Related: #2000051
+
+* Fri Feb 11 2022 Jindrich Novy <jnovy@redhat.com> - 4.4.0-6
+- add patches fixing gating tests from Marc-André Lureau
+- Related: #2000051
+
+* Wed Feb 09 2022 Jindrich Novy <jnovy@redhat.com> - 4.4.0-5
+- add gating.yaml
+- Related: #2000051
+
+* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 4.4.0-4
+- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
+ Related: rhbz#1991688
+
+* Fri Jun 18 2021 Marc-André Lureau <marcandre.lureau@redhat.com> - 4.4.0-3
+- Fix CVE-2021-3592 CVE-2021-3593 CVE-2021-3594 CVE-2021-3595 out-of-bounds access
+ Resolves: rhbz#1970826 rhbz#1970839 rhbz#1970857 rhbz#1970847
+
+* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 4.4.0-2
+- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
+
+* Wed Dec 2 18:19:30 +04 2020 Marc-André Lureau <marcandre.lureau@redhat.com> - 4.4.0-1
+- new version
+
+* Fri Nov 27 20:10:28 +04 2020 Marc-André Lureau <marcandre.lureau@redhat.com> - 4.3.1-3
+- Fix CVE-2020-29129 CVE-2020-29130 out-of-bounds access while processing ARP/NCSI packets
+ rhbz#1902232
+
+* Tue Jul 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 4.3.1-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
+
+* Wed Jul 08 2020 Marc-André Lureau <marcandre.lureau@redhat.com> - 4.3.1-1
+- New v4.3.1 release
+
+* Thu Apr 23 2020 Marc-André Lureau <marcandre.lureau@redhat.com> - 4.3.0-1
+- New v4.3.0 release
+
+* Mon Apr 20 2020 Marc-André Lureau <marcandre.lureau@redhat.com> - 4.2.0-2
+- CVE-2020-1983 fix
+
+* Tue Mar 17 2020 Marc-André Lureau <marcandre.lureau@redhat.com> - 4.2.0-1
+- New v4.2.0 release
+
+* Wed Jan 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 4.1.0-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
+
+* Tue Dec 03 2019 Marc-André Lureau <marcandre.lureau@redhat.com> - 4.1.0-1
+- New v4.1.0 release
+
+* Fri Aug 2 2019 Marc-André Lureau <marcandre.lureau@redhat.com> - 4.0.0-3
+- Fix CVE-2019-14378, rhbz#1735654
+
+* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 4.0.0-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
+
+* Wed May 22 2019 Marc-André Lureau <marcandre.lureau@redhat.com> - 4.0.0-1
+- Initial package, rhbz#1712980
diff --git a/sources b/sources
new file mode 100644
index 0000000..ff63742
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+602c9b982d30ec641ff0f08cc0bf6822 libslirp-4.4.0.tar.xz