aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2023-02-14 06:11:38 +0000
committerKristof Provost <kp@FreeBSD.org>2023-03-02 16:21:59 +0000
commit3dec62eded04eaf431bf0948f4e6412deede87d5 (patch)
treee40d01490fb34cbacf9e55fdd0239aec2eb6709d
parent65d7644bdb167b549aa0d1480424cc4e186649f2 (diff)
pfsync: support deferring IPv6 packets
When we send out a deferred packet we must make sure to call ip6_output() for IPv6 packets. If not we might end up attempting to ip_fragment() an IPv6 packet, which could lead to us reading outside of the mbuf. PR: 268246 Reviewed by: melifaro, zlei MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D38586 (cherry picked from commit 9a1cab6d79b7286e5f650f57ed95625e6ddb8e4b)
-rw-r--r--sys/netpfil/pf/if_pfsync.c71
1 files changed, 56 insertions, 15 deletions
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index f6c7bd9b566d..6c25ddb7f6b3 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -102,12 +102,16 @@ __FBSDID("$FreeBSD$");
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+
#define PFSYNC_MINPKT ( \
sizeof(struct ip) + \
sizeof(struct pfsync_header) + \
sizeof(struct pfsync_subheader) )
struct pfsync_bucket;
+struct pfsync_softc;
struct pfsync_pkt {
struct ip *ip;
@@ -170,6 +174,7 @@ static void pfsync_q_ins(struct pf_kstate *, int, bool);
static void pfsync_q_del(struct pf_kstate *, bool, struct pfsync_bucket *);
static void pfsync_update_state(struct pf_kstate *);
+static void pfsync_tx(struct pfsync_softc *, struct mbuf *);
struct pfsync_upd_req_item {
TAILQ_ENTRY(pfsync_upd_req_item) ur_entry;
@@ -186,8 +191,6 @@ struct pfsync_deferral {
struct mbuf *pd_m;
};
-struct pfsync_sofct;
-
struct pfsync_bucket
{
int b_id;
@@ -1839,7 +1842,7 @@ pfsync_defer_tmo(void *arg)
free(pd, M_PFSYNC);
PFSYNC_BUCKET_UNLOCK(b);
- ip_output(m, NULL, NULL, 0, NULL, NULL);
+ pfsync_tx(sc, m);
pf_release_state(st);
@@ -2323,6 +2326,55 @@ pfsync_push_all(struct pfsync_softc *sc)
}
static void
+pfsync_tx(struct pfsync_softc *sc, struct mbuf *m)
+{
+ struct ip *ip;
+ int error, af;
+
+ ip = mtod(m, struct ip *);
+ MPASS(ip->ip_v == IPVERSION || ip->ip_v == (IPV6_VERSION >> 4));
+
+ af = ip->ip_v == IPVERSION ? AF_INET : AF_INET6;
+
+ /*
+ * We distinguish between a deferral packet and our
+ * own pfsync packet based on M_SKIP_FIREWALL
+ * flag. This is XXX.
+ */
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ if (m->m_flags & M_SKIP_FIREWALL) {
+ error = ip_output(m, NULL, NULL, 0,
+ NULL, NULL);
+ } else {
+ error = ip_output(m, NULL, NULL,
+ IP_RAWOUTPUT, &sc->sc_imo, NULL);
+ }
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ if (m->m_flags & M_SKIP_FIREWALL) {
+ error = ip6_output(m, NULL, NULL, 0,
+ NULL, NULL, NULL);
+ } else {
+ MPASS(false);
+ /* We don't support pfsync over IPv6. */
+ /*error = ip6_output(m, NULL, NULL,
+ IP_RAWOUTPUT, &sc->sc_imo6, NULL);*/
+ }
+ break;
+#endif
+ }
+
+ if (error == 0)
+ V_pfsyncstats.pfsyncs_opackets++;
+ else
+ V_pfsyncstats.pfsyncs_oerrors++;
+}
+
+static void
pfsyncintr(void *arg)
{
struct epoch_tracker et;
@@ -2349,18 +2401,7 @@ pfsyncintr(void *arg)
n = m->m_nextpkt;
m->m_nextpkt = NULL;
- /*
- * We distinguish between a deferral packet and our
- * own pfsync packet based on M_SKIP_FIREWALL
- * flag. This is XXX.
- */
- if (m->m_flags & M_SKIP_FIREWALL)
- ip_output(m, NULL, NULL, 0, NULL, NULL);
- else if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo,
- NULL) == 0)
- V_pfsyncstats.pfsyncs_opackets++;
- else
- V_pfsyncstats.pfsyncs_oerrors++;
+ pfsync_tx(sc, m);
}
}
CURVNET_RESTORE();