pf: improve SCTP validation
As per RFC5061 "4.2. New Parameter Types" the add/delete IP address parameters (0xc001, 0xc002) may not be present in an INIT or INIT-ACK chunk. They are only allowed to be present in an ASCONF chunk. This also prevents unbounded recursion while parsing an SCTP packet. Approved by: so Security: FreeBSD-SA-26:14.pf Security: CVE-2026-7164 PR: 294799 Reported by: Igor Gabriel Sousa e Souza Sponsored by: Orange Business Services
This commit is contained in:
committed by
Mark Johnston
parent
5d8e32aad2
commit
6f9ddb329b
+11
-5
@@ -8353,7 +8353,7 @@ pf_sctp_multihome_delayed(struct pf_pdesc *pd, struct pfi_kkif *kif,
|
||||
}
|
||||
|
||||
static int
|
||||
pf_multihome_scan(int start, int len, struct pf_pdesc *pd, int op)
|
||||
pf_multihome_scan(int start, int len, struct pf_pdesc *pd, int op, bool asconf)
|
||||
{
|
||||
int off = 0;
|
||||
struct pf_sctp_multihome_job *job;
|
||||
@@ -8458,6 +8458,9 @@ pf_multihome_scan(int start, int len, struct pf_pdesc *pd, int op)
|
||||
int ret;
|
||||
struct sctp_asconf_paramhdr ah;
|
||||
|
||||
if (asconf)
|
||||
return (PF_DROP);
|
||||
|
||||
if (!pf_pull_hdr(pd->m, start + off, &ah, sizeof(ah),
|
||||
NULL, pd->af))
|
||||
return (PF_DROP);
|
||||
@@ -8467,7 +8470,7 @@ pf_multihome_scan(int start, int len, struct pf_pdesc *pd, int op)
|
||||
|
||||
ret = pf_multihome_scan(start + off + sizeof(ah),
|
||||
ntohs(ah.ph.param_length) - sizeof(ah), pd,
|
||||
SCTP_ADD_IP_ADDRESS);
|
||||
SCTP_ADD_IP_ADDRESS, true);
|
||||
if (ret != PF_PASS)
|
||||
return (ret);
|
||||
break;
|
||||
@@ -8476,6 +8479,9 @@ pf_multihome_scan(int start, int len, struct pf_pdesc *pd, int op)
|
||||
int ret;
|
||||
struct sctp_asconf_paramhdr ah;
|
||||
|
||||
if (asconf)
|
||||
return (PF_DROP);
|
||||
|
||||
if (!pf_pull_hdr(pd->m, start + off, &ah, sizeof(ah),
|
||||
NULL, pd->af))
|
||||
return (PF_DROP);
|
||||
@@ -8485,7 +8491,7 @@ pf_multihome_scan(int start, int len, struct pf_pdesc *pd, int op)
|
||||
|
||||
ret = pf_multihome_scan(start + off + sizeof(ah),
|
||||
ntohs(ah.ph.param_length) - sizeof(ah), pd,
|
||||
SCTP_DEL_IP_ADDRESS);
|
||||
SCTP_DEL_IP_ADDRESS, true);
|
||||
if (ret != PF_PASS)
|
||||
return (ret);
|
||||
break;
|
||||
@@ -8506,7 +8512,7 @@ pf_multihome_scan_init(int start, int len, struct pf_pdesc *pd)
|
||||
start += sizeof(struct sctp_init_chunk);
|
||||
len -= sizeof(struct sctp_init_chunk);
|
||||
|
||||
return (pf_multihome_scan(start, len, pd, SCTP_ADD_IP_ADDRESS));
|
||||
return (pf_multihome_scan(start, len, pd, SCTP_ADD_IP_ADDRESS, false));
|
||||
}
|
||||
|
||||
int
|
||||
@@ -8515,7 +8521,7 @@ pf_multihome_scan_asconf(int start, int len, struct pf_pdesc *pd)
|
||||
start += sizeof(struct sctp_asconf_chunk);
|
||||
len -= sizeof(struct sctp_asconf_chunk);
|
||||
|
||||
return (pf_multihome_scan(start, len, pd, SCTP_ADD_IP_ADDRESS));
|
||||
return (pf_multihome_scan(start, len, pd, SCTP_ADD_IP_ADDRESS, false));
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -618,6 +618,29 @@ def test_initiate_tag_check(self):
|
||||
assert r.getlayer(sp.SCTPChunkInitAck)
|
||||
assert r.getlayer(sp.SCTP).tag == 42
|
||||
|
||||
@pytest.mark.require_user("root")
|
||||
@pytest.mark.require_progs(["scapy"])
|
||||
def test_too_many_add_ip(self):
|
||||
import scapy.all as sp
|
||||
DEPTH=90
|
||||
params=[]
|
||||
for i in range(0, DEPTH):
|
||||
ch = sp.SCTPChunkParamAddIPAddr(len=(DEPTH - i) * 8)
|
||||
params.append(ch)
|
||||
packet = sp.IP(src="192.0.2.1", dst="192.0.2.2") \
|
||||
/ sp.SCTP(sport=4321, dport=1234) \
|
||||
/ sp.SCTPChunkInit(init_tag=1, n_in_streams=1, n_out_streams=1, a_rwnd=1500,
|
||||
params=params)
|
||||
packet.show()
|
||||
sp.hexdump(packet)
|
||||
print("len %d" % len(packet))
|
||||
|
||||
r = sp.sr1(packet, timeout=3)
|
||||
# We should not get a reply to this
|
||||
if r:
|
||||
r.show()
|
||||
assert not r
|
||||
|
||||
class TestSCTPv6(VnetTestTemplate):
|
||||
REQUIRED_MODULES = ["sctp", "pf"]
|
||||
TOPOLOGY = {
|
||||
|
||||
Reference in New Issue
Block a user