git: 51a78dd2764b - main - pf: improve SCTP state validation
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 07 Sep 2023 17:05:31 UTC
The branch main has been updated by kp:
URL: https://cgit.FreeBSD.org/src/commit/?id=51a78dd2764beabfd19a58b8a8b04387a547f02e
commit 51a78dd2764beabfd19a58b8a8b04387a547f02e
Author: Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2023-09-01 11:33:56 +0000
Commit: Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-09-07 17:05:01 +0000
pf: improve SCTP state validation
Only create new states for INIT chunks, or when we're creating a
secondary state for a multihomed association.
Store and verify verification tag.
MFC after: 3 weeks
Sponsored by: Orange Business Services
---
sys/net/pfvar.h | 8 +++++++-
sys/netpfil/pf/pf.c | 32 ++++++++++++++++++++++----------
sys/netpfil/pf/pf_norm.c | 17 +++++++++++++++++
3 files changed, 46 insertions(+), 11 deletions(-)
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index a131ba925013..d63a7bb1afb2 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -900,7 +900,10 @@ struct pf_state_scrub {
#define PFSS_DATA_NOTS 0x0080 /* no timestamp on data packets */
u_int8_t pfss_ttl; /* stashed TTL */
u_int8_t pad;
- u_int32_t pfss_ts_mod; /* timestamp modulation */
+ union {
+ u_int32_t pfss_ts_mod; /* timestamp modulation */
+ u_int32_t pfss_v_tag; /* SCTP verification tag */
+ };
};
struct pf_state_host {
@@ -1583,6 +1586,7 @@ struct pf_pdesc {
#define PFDESC_SCTP_DATA 0x0040
#define PFDESC_SCTP_ASCONF 0x0080
#define PFDESC_SCTP_OTHER 0x0100
+#define PFDESC_SCTP_ADD_IP 0x0200
u_int16_t sctp_flags;
u_int32_t sctp_initiate_tag;
@@ -2297,6 +2301,8 @@ int pf_normalize_tcp_init(struct mbuf *, int, struct pf_pdesc *,
int pf_normalize_tcp_stateful(struct mbuf *, int, struct pf_pdesc *,
u_short *, struct tcphdr *, struct pf_kstate *,
struct pf_state_peer *, struct pf_state_peer *, int *);
+int pf_normalize_sctp_init(struct mbuf *, int, struct pf_pdesc *,
+ struct pf_state_peer *, struct pf_state_peer *);
int pf_normalize_sctp(int, struct pfi_kkif *, struct mbuf *, int,
int, void *, struct pf_pdesc *);
u_int32_t
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index a324a31d6d84..c24d4dfce742 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -4909,11 +4909,7 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a,
if (s->state_flags & PFSTATE_SCRUB_TCP &&
pf_normalize_tcp_init(m, off, pd, th, &s->src, &s->dst)) {
REASON_SET(&reason, PFRES_MEMORY);
- pf_src_tree_remove_state(s);
- s->timeout = PFTM_UNLINKED;
- STATE_DEC_COUNTERS(s);
- pf_free_state(s);
- return (PF_DROP);
+ goto drop;
}
if (s->state_flags & PFSTATE_SCRUB_TCP && s->src.scrub &&
pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
@@ -4922,12 +4918,13 @@ pf_create_state(struct pf_krule *r, struct pf_krule *nr, struct pf_krule *a,
DPFPRINTF(PF_DEBUG_URGENT,
("pf_normalize_tcp_stateful failed on first "
"pkt\n"));
- pf_src_tree_remove_state(s);
- s->timeout = PFTM_UNLINKED;
- STATE_DEC_COUNTERS(s);
- pf_free_state(s);
- return (PF_DROP);
+ goto drop;
}
+ } else if (pd->proto == IPPROTO_SCTP) {
+ if (pf_normalize_sctp_init(m, off, pd, &s->src, &s->dst))
+ goto drop;
+ if (! (pd->sctp_flags & (PFDESC_SCTP_INIT | PFDESC_SCTP_ADD_IP)))
+ goto drop;
}
s->direction = pd->dir;
@@ -5024,6 +5021,13 @@ csfailed:
}
return (PF_DROP);
+
+drop:
+ pf_src_tree_remove_state(s);
+ s->timeout = PFTM_UNLINKED;
+ STATE_DEC_COUNTERS(s);
+ pf_free_state(s);
+ return (PF_DROP);
}
static int
@@ -5891,6 +5895,13 @@ pf_test_state_sctp(struct pf_kstate **state, struct pfi_kkif *kif,
}
}
+ if (src->scrub != NULL) {
+ if (src->scrub->pfss_v_tag == 0) {
+ src->scrub->pfss_v_tag = pd->hdr.sctp.v_tag;
+ } else if (src->scrub->pfss_v_tag != pd->hdr.sctp.v_tag)
+ return (PF_DROP);
+ }
+
(*state)->expire = time_uptime;
/* translate source/destination address, if necessary */
@@ -5931,6 +5942,7 @@ pf_sctp_multihome_delayed(struct pf_pdesc *pd, int off, struct pfi_kkif *kif,
TAILQ_FOREACH_SAFE(j, &pd->sctp_multihome_jobs, next, tmp) {
PF_RULES_RLOCK();
+ j->pd.sctp_flags |= PFDESC_SCTP_ADD_IP;
action = pf_test_rule(&r, &sm, kif,
j->m, off, &j->pd, &ra, &rs, NULL);
PF_RULES_RUNLOCK();
diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index 83b94db87a19..d63cf0ebe54e 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -1565,11 +1565,28 @@ pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd,
void
pf_normalize_tcp_cleanup(struct pf_kstate *state)
{
+ /* XXX Note: this also cleans up SCTP. */
uma_zfree(V_pf_state_scrub_z, state->src.scrub);
uma_zfree(V_pf_state_scrub_z, state->dst.scrub);
/* Someday... flush the TCP segment reassembly descriptors. */
}
+int
+pf_normalize_sctp_init(struct mbuf *m, int off, struct pf_pdesc *pd,
+ struct pf_state_peer *src, struct pf_state_peer *dst)
+{
+ src->scrub = uma_zalloc(V_pf_state_scrub_z, M_ZERO | M_NOWAIT);
+ if (src->scrub == NULL)
+ return (1);
+
+ dst->scrub = uma_zalloc(V_pf_state_scrub_z, M_ZERO | M_NOWAIT);
+ if (dst->scrub == NULL) {
+ uma_zfree(V_pf_state_scrub_z, src);
+ return (1);
+ }
+
+ return (0);
+}
int
pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd,