The branch stable/14 has been updated by kp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=7a96c75098afe071e49755f1beccaaf08f9ae13f

commit 7a96c75098afe071e49755f1beccaaf08f9ae13f
Author:     Kristof Provost <k...@freebsd.org>
AuthorDate: 2025-06-21 09:13:22 +0000
Commit:     Kristof Provost <k...@freebsd.org>
CommitDate: 2025-07-09 08:08:50 +0000

    pf: limit extra SCTP states
    
    For SCTP we create states for all combinations of endpoints, to allow 
multihoming to work.
    Malicious users could abuse this to fill our state table more easily
    than they otherwise could, because we create states between all
    combinations of endpoints. Limit this to no more than 8 extra endpoints
    for each side of the connection.
    
    MFC after:      2 weeks
    Sponsored by:   Orange Business Services
    
    (cherry picked from commit cd0169c9379c400ec75b77e87ca770e37f964276)
---
 sys/netpfil/pf/pf.c          | 11 +++++++++++
 tests/sys/netpfil/pf/sctp.py | 28 ++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 2ba2f2213fb7..f067c2b6bdf4 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -191,6 +191,8 @@ VNET_DEFINE(size_t, pf_allrulecount);
 VNET_DEFINE(struct pf_krule *, pf_rulemarker);
 #endif
 
+#define PF_SCTP_MAX_ENDPOINTS          8
+
 struct pf_sctp_endpoint;
 RB_HEAD(pf_sctp_endpoints, pf_sctp_endpoint);
 struct pf_sctp_source {
@@ -6374,6 +6376,7 @@ pf_sctp_multihome_add_addr(struct pf_pdesc *pd, struct 
pf_addr *a, uint32_t v_ta
        };
        struct pf_sctp_source *i;
        struct pf_sctp_endpoint *ep;
+       int count;
 
        PF_SCTP_ENDPOINTS_LOCK();
 
@@ -6392,13 +6395,21 @@ pf_sctp_multihome_add_addr(struct pf_pdesc *pd, struct 
pf_addr *a, uint32_t v_ta
        }
 
        /* Avoid inserting duplicates. */
+       count = 0;
        TAILQ_FOREACH(i, &ep->sources, entry) {
+               count++;
                if (pf_addr_cmp(&i->addr, a, pd->af) == 0) {
                        PF_SCTP_ENDPOINTS_UNLOCK();
                        return;
                }
        }
 
+       /* Limit the number of addresses per endpoint. */
+       if (count >= PF_SCTP_MAX_ENDPOINTS) {
+               PF_SCTP_ENDPOINTS_UNLOCK();
+               return;
+       }
+
        i = malloc(sizeof(*i), M_PFTEMP, M_NOWAIT);
        if (i == NULL) {
                PF_SCTP_ENDPOINTS_UNLOCK();
diff --git a/tests/sys/netpfil/pf/sctp.py b/tests/sys/netpfil/pf/sctp.py
index 230dbae0d327..da42ce527195 100644
--- a/tests/sys/netpfil/pf/sctp.py
+++ b/tests/sys/netpfil/pf/sctp.py
@@ -426,6 +426,34 @@ class TestSCTP(VnetTestTemplate):
         assert re.search(r"all sctp 192.0.2.4:.*192.0.2.3:1234", states)
         assert re.search(r"all sctp 192.0.2.4:.*192.0.2.2:1234", states)
 
+    @pytest.mark.require_user("root")
+    def test_limit_addresses(self):
+        srv_vnet = self.vnet_map["vnet2"]
+
+        ifname = self.vnet_map["vnet1"].iface_alias_map["if1"].name
+        for i in range(0, 16):
+            ToolsHelper.print_output("/sbin/ifconfig %s inet alias 
192.0.2.%d/24" % (ifname, 4 + i))
+
+        ToolsHelper.print_output("/sbin/pfctl -e")
+        ToolsHelper.pf_rules([
+            "block proto sctp",
+            "pass on lo",
+            "pass inet proto sctp to 192.0.2.0/24"])
+
+        # Set up a connection, which will try to create states for all 
addresses
+        # we have assigned
+        client = SCTPClient("192.0.2.3", 1234)
+        client.send(b"hello", 0)
+        rcvd = self.wait_object(srv_vnet.pipe)
+        print(rcvd)
+        assert rcvd['ppid'] == 0
+        assert rcvd['data'] == "hello"
+
+        # But the number should be limited to 9 (original + 8 extra)
+        states = ToolsHelper.get_output("/sbin/pfctl -ss | grep 192.0.2.2")
+        print(states)
+        assert(states.count('\n') <= 9)
+
     @pytest.mark.require_user("root")
     def test_disallow_related(self):
         srv_vnet = self.vnet_map["vnet2"]

Reply via email to