Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144544724
D19622.1775343804.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D19622.1775343804.diff
View Options
Index: head/sys/netinet/ip_reass.c
===================================================================
--- head/sys/netinet/ip_reass.c
+++ head/sys/netinet/ip_reass.c
@@ -47,7 +47,10 @@
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_var.h>
#include <net/rss_config.h>
#include <net/netisr.h>
#include <net/vnet.h>
@@ -181,6 +184,7 @@
struct ip *ip;
struct mbuf *p, *q, *nq, *t;
struct ipq *fp;
+ struct ifnet *srcifp;
struct ipqhead *head;
int i, hlen, next, tmpmax;
u_int8_t ecn, ecn0;
@@ -241,6 +245,11 @@
}
/*
+ * Store receive network interface pointer for later.
+ */
+ srcifp = m->m_pkthdr.rcvif;
+
+ /*
* Attempt reassembly; if it succeeds, proceed.
* ip_reass() will return a different mbuf.
*/
@@ -490,8 +499,11 @@
m->m_len += (ip->ip_hl << 2);
m->m_data -= (ip->ip_hl << 2);
/* some debugging cruft by sklower, below, will go away soon */
- if (m->m_flags & M_PKTHDR) /* XXX this should be done elsewhere */
+ if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */
m_fixhdr(m);
+ /* set valid receive interface pointer */
+ m->m_pkthdr.rcvif = srcifp;
+ }
IPSTAT_INC(ips_reassembled);
IPQ_UNLOCK(hash);
@@ -607,6 +619,43 @@
}
}
+/*
+ * Drain off all datagram fragments belonging to
+ * the given network interface.
+ */
+static void
+ipreass_cleanup(void *arg __unused, struct ifnet *ifp)
+{
+ struct ipq *fp, *temp;
+ struct mbuf *m;
+ int i;
+
+ KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__));
+
+ /*
+ * Skip processing if IPv4 reassembly is not initialised or
+ * torn down by ipreass_destroy().
+ */
+ if (V_ipq_zone == NULL)
+ return;
+
+ CURVNET_SET_QUIET(ifp->if_vnet);
+ for (i = 0; i < IPREASS_NHASH; i++) {
+ IPQ_LOCK(i);
+ /* Scan fragment list. */
+ TAILQ_FOREACH_SAFE(fp, &V_ipq[i].head, ipq_list, temp) {
+ for (m = fp->ipq_frags; m != NULL; m = m->m_nextpkt) {
+ /* clear no longer valid rcvif pointer */
+ if (m->m_pkthdr.rcvif == ifp)
+ m->m_pkthdr.rcvif = NULL;
+ }
+ }
+ IPQ_UNLOCK(i);
+ }
+ CURVNET_RESTORE();
+}
+EVENTHANDLER_DEFINE(ifnet_departure_event, ipreass_cleanup, NULL, 0);
+
#ifdef VIMAGE
/*
* Destroy IP reassembly structures.
@@ -617,6 +666,7 @@
ipreass_drain();
uma_zdestroy(V_ipq_zone);
+ V_ipq_zone = NULL;
for (int i = 0; i < IPREASS_NHASH; i++)
mtx_destroy(&V_ipq[i].lock);
}
Index: head/sys/netinet6/frag6.c
===================================================================
--- head/sys/netinet6/frag6.c
+++ head/sys/netinet6/frag6.c
@@ -246,7 +246,7 @@
* Return ICMP time exceeded error for the 1st fragment.
* Just free other fragments.
*/
- if (af6->ip6af_off == 0) {
+ if (af6->ip6af_off == 0 && m->m_pkthdr.rcvif != NULL) {
/* Adjust pointer. */
ip6 = mtod(m, struct ip6_hdr *);
@@ -272,6 +272,43 @@
}
/*
+ * Drain off all datagram fragments belonging to
+ * the given network interface.
+ */
+static void
+frag6_cleanup(void *arg __unused, struct ifnet *ifp)
+{
+ struct ip6q *q6, *q6n, *head;
+ struct ip6asfrag *af6;
+ struct mbuf *m;
+ int i;
+
+ KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__));
+
+ CURVNET_SET_QUIET(ifp->if_vnet);
+ for (i = 0; i < IP6REASS_NHASH; i++) {
+ IP6QB_LOCK(i);
+ head = IP6QB_HEAD(i);
+ /* Scan fragment list. */
+ for (q6 = head->ip6q_next; q6 != head; q6 = q6n) {
+ q6n = q6->ip6q_next;
+
+ for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
+ af6 = af6->ip6af_down) {
+ m = IP6_REASS_MBUF(af6);
+
+ /* clear no longer valid rcvif pointer */
+ if (m->m_pkthdr.rcvif == ifp)
+ m->m_pkthdr.rcvif = NULL;
+ }
+ }
+ IP6QB_UNLOCK(i);
+ }
+ CURVNET_RESTORE();
+}
+EVENTHANDLER_DEFINE(ifnet_departure_event, frag6_cleanup, NULL, 0);
+
+/*
* Like in RFC2460, in RFC8200, fragment and reassembly rules do not agree with
* each other, in terms of next header field handling in fragment header.
* While the sender will use the same value for all of the fragmented packets,
@@ -307,6 +344,7 @@
frag6_input(struct mbuf **mp, int *offp, int proto)
{
struct ifnet *dstifp;
+ struct ifnet *srcifp;
struct in6_ifaddr *ia6;
struct ip6_hdr *ip6;
struct ip6_frag *ip6f;
@@ -338,6 +376,11 @@
return (IPPROTO_DONE);
#endif
+ /*
+ * Store receive network interface pointer for later.
+ */
+ srcifp = m->m_pkthdr.rcvif;
+
dstifp = NULL;
/* Find the destination interface of the packet. */
ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
@@ -534,6 +577,9 @@
frag6_deq(af6, bucket);
free(af6, M_FRAG6);
+ /* Set a valid receive interface pointer. */
+ merr->m_pkthdr.rcvif = srcifp;
+
/* Adjust pointer. */
ip6err = mtod(merr, struct ip6_hdr *);
@@ -720,6 +766,8 @@
for (t = m; t; t = t->m_next)
plen += t->m_len;
m->m_pkthdr.len = plen;
+ /* Set a valid receive interface pointer. */
+ m->m_pkthdr.rcvif = srcifp;
}
#ifdef RSS
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 4, 11:03 PM (13 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28261802
Default Alt Text
D19622.1775343804.diff (4 KB)
Attached To
Mode
D19622: Fix panic in network stack due memory use after free in relation to fragmented packets
Attached
Detach File
Event Timeline
Log In to Comment