Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 18 Feb 2025 17:43:16 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 5ff91b71bb67 - stable/14 - pf tests: add more fragmentation test cases
Message-ID:  <202502181743.51IHhGNS021418@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/14 has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=5ff91b71bb67f4408a2541a13cd270b7370c6766

commit 5ff91b71bb67f4408a2541a13cd270b7370c6766
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2025-02-04 13:06:33 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2025-02-18 17:40:26 +0000

    pf tests: add more fragmentation test cases
    
    Add more test cases for pf fragment hole counter.  Also look into
    final fragment of echo reply and check total length of IP packet.
    
    MFC after:      1 week
    Obtained from:  OpenBSD, bluhm <bluhm@openbsd.org>, 640736615b
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    
    (cherry picked from commit db100bd93036855c7688dc088b811dc7b660f51d)
---
 tests/sys/netpfil/pf/Makefile              |  4 ++
 tests/sys/netpfil/pf/frag-adjhole.py       | 58 +++++++++++++++++++++
 tests/sys/netpfil/pf/frag-overhole.py      | 83 ++++++++++++++++++++++++++++++
 tests/sys/netpfil/pf/fragmentation_pass.sh | 38 ++++++++++++++
 4 files changed, 183 insertions(+)

diff --git a/tests/sys/netpfil/pf/Makefile b/tests/sys/netpfil/pf/Makefile
index dc77fd67b2c6..f2ccd5aa6ec2 100644
--- a/tests/sys/netpfil/pf/Makefile
+++ b/tests/sys/netpfil/pf/Makefile
@@ -62,6 +62,8 @@ ${PACKAGE}FILES+=	CVE-2019-5597.py \
 			frag-overindex.py \
 			frag-overlimit.py \
 			frag-overreplace.py \
+			frag-overhole.py \
+			frag-adjhole.py \
 			pfsync_defer.py \
 			pft_ether.py \
 			rdr-srcport.py \
@@ -73,6 +75,8 @@ ${PACKAGE}FILESMODE_fragcommon.py=	0555
 ${PACKAGE}FILESMODE_frag-overindex.py=	0555
 ${PACKAGE}FILESMODE_frag-overlimit.py=	0555
 ${PACKAGE}FILESMODE_frag-overreplace.py=	0555
+${PACKAGE}FILESMODE_frag-overhole.py=	0555
+${PACKAGE}FILESMODE_frag-adjhole.py=	0555
 ${PACKAGE}FILESMODE_pfsync_defer.py=	0555
 ${PACKAGE}FILESMODE_pft_ether.py=	0555
 
diff --git a/tests/sys/netpfil/pf/frag-adjhole.py b/tests/sys/netpfil/pf/frag-adjhole.py
new file mode 100644
index 000000000000..99caf66617dd
--- /dev/null
+++ b/tests/sys/netpfil/pf/frag-adjhole.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2025 Alexander Bluhm <bluhm@openbsd.org>
+
+from fragcommon import *
+
+# |--------|
+#          |--------|
+#      |-------|
+#                   |----|
+
+def send(src, dst, send_if, recv_if):
+	pid = os.getpid()
+	eid = pid & 0xffff
+	payload = b"ABCDEFGHIJKLMNOP" * 2
+	packet = sp.IP(src=src, dst=dst)/ \
+	    sp.ICMP(type='echo-request', id=eid) / payload
+	frag = []
+	fid = pid & 0xffff
+	frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
+	    flags='MF') / bytes(packet)[20:36])
+	frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
+	    frag=2, flags='MF') / bytes(packet)[36:52])
+	frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
+	    frag=1, flags='MF') / bytes(packet)[28:44])
+	frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
+	    frag=4) / bytes(packet)[52:60])
+	eth=[]
+	for f in frag:
+		eth.append(sp.Ether()/f)
+	if os.fork() == 0:
+		time.sleep(1)
+		sp.sendp(eth, iface=send_if)
+		os._exit(0)
+
+	ans = sp.sniff(iface=recv_if, timeout=3, filter=
+	    "ip and src " + dst + " and dst " + src + " and icmp")
+	for a in ans:
+		if a and a.type == sp.ETH_P_IP and \
+		    a.payload.proto == 1 and \
+		    a.payload.frag == 0 and a.payload.flags == 0 and \
+		    sp.icmptypes[a.payload.payload.type] == 'echo-reply':
+			id = a.payload.payload.id
+			print("id=%#x" % (id))
+			if id != eid:
+				print("WRONG ECHO REPLY ID")
+				exit(2)
+			data = a.payload.payload.payload.load
+			print("payload=%s" % (data))
+			if data == payload:
+				exit(0)
+			print("PAYLOAD!=%s" % (payload))
+			exit(1)
+	print("NO ECHO REPLY")
+	exit(2)
+
+if __name__ == '__main__':
+	main(send)
diff --git a/tests/sys/netpfil/pf/frag-overhole.py b/tests/sys/netpfil/pf/frag-overhole.py
new file mode 100644
index 000000000000..91697b6b83c6
--- /dev/null
+++ b/tests/sys/netpfil/pf/frag-overhole.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2025 Alexander Bluhm <bluhm@openbsd.org>
+
+from fragcommon import *
+
+#                               index boundary 4096 |
+# |--------------|
+#                 ....
+#                     |--------------|
+#                                    |----------|
+#                                               |XXXX----------|
+#                                          |XXXX----|
+#                                                               |---|
+
+# this should trigger "frag tail overlap %d" and "frag head overlap %d"
+def send(src, dst, send_if, recv_if):
+	pid = os.getpid()
+	eid = pid & 0xffff
+	payload = b"ABCDEFGHIJKLMNOP"
+	dummy = b"01234567"
+	fragsize = 1024
+	boundary = 4096
+	fragnum = int(boundary / fragsize)
+	packet = sp.IP(src=src, dst=dst)/ \
+	    sp.ICMP(type='echo-request', id=eid)/ \
+	    ((int((boundary + fragsize) / len(payload)) + 1) * payload)
+	packet_length = len(packet)
+	frag = []
+	fid = pid & 0xffff
+	for i in range(fragnum-1):
+		frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
+		    frag=(i * fragsize)>>3, flags='MF')/
+		    bytes(packet)[20 + i * fragsize:20 + (i + 1) * fragsize])
+	frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
+	    frag=(boundary - fragsize) >> 3, flags='MF')/
+	    bytes(packet)[20 + boundary - fragsize:20 + boundary - len(dummy)])
+	frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
+	    frag=(boundary - len(dummy)) >> 3, flags='MF')/
+	    (dummy+bytes(packet)[20 + boundary:20 + boundary + fragsize]))
+	frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
+	    frag=(boundary - 8 - len(dummy)) >> 3, flags='MF')/
+	    (dummy+bytes(packet)[20 + boundary - 8:20 + boundary]))
+	frag.append(sp.IP(src=src, dst=dst, proto=1, id=fid,
+	    frag=(boundary + fragsize) >> 3)/bytes(packet)[20 + boundary + fragsize:])
+	eth=[]
+	for f in frag:
+		eth.append(sp.Ether() / f)
+
+	if os.fork() == 0:
+		time.sleep(1)
+		for e in eth:
+			sp.sendp(e, iface=send_if)
+			time.sleep(0.001)
+		os._exit(0)
+
+	ans = sp.sniff(iface=recv_if, timeout=3, filter=
+	    "ip and src " + dst + " and dst " + src + " and icmp")
+	for a in ans:
+		if a and a.type == sp.ETH_P_IP and \
+		    a.payload.proto == 1 and \
+		    a.payload.frag == 0 and \
+		    sp.icmptypes[a.payload.payload.type] == 'echo-reply':
+			id = a.payload.payload.id
+			print("id=%#x" % (id))
+			if id != eid:
+				print("WRONG ECHO REPLY ID")
+				exit(2)
+		if a and a.type == sp.ETH_P_IP and \
+		    a.payload.proto == 1 and \
+		    a.payload.frag > 0 and \
+		    a.payload.flags == '':
+			length = (a.payload.frag << 3) + a.payload.len
+			print("len=%d" % (length))
+			if length != packet_length:
+				print("WRONG ECHO REPLY LENGTH")
+				exit(1)
+			exit(0)
+	print("NO ECHO REPLY")
+	exit(1)
+
+if __name__ == '__main__':
+	main(send)
diff --git a/tests/sys/netpfil/pf/fragmentation_pass.sh b/tests/sys/netpfil/pf/fragmentation_pass.sh
index 5e92bb2d9a97..66fe336dff34 100644
--- a/tests/sys/netpfil/pf/fragmentation_pass.sh
+++ b/tests/sys/netpfil/pf/fragmentation_pass.sh
@@ -285,6 +285,42 @@ overlimit_cleanup()
 	pft_cleanup
 }
 
+atf_test_case "overhole" "cleanup"
+overhole_head()
+{
+	atf_set descr 'ping fragment at index boundary which modifies pf hole counter'
+	atf_set require.user root
+	atf_set require.progs scapy
+}
+
+overhole_body()
+{
+	frag_common overhole
+}
+
+overhole_cleanup()
+{
+	pft_cleanup
+}
+
+atf_test_case "adjhole" "cleanup"
+adjhole_head()
+{
+	atf_set descr 'overlapping ping fragments which modifies pf hole counter'
+	atf_set require.user root
+	atf_set require.progs scapy
+}
+
+adjhole_body()
+{
+	frag_common adjhole
+}
+
+adjhole_cleanup()
+{
+	pft_cleanup
+}
+
 atf_test_case "reassemble" "cleanup"
 reassemble_head()
 {
@@ -476,6 +512,8 @@ atf_init_test_cases()
 	atf_add_test_case "overreplace"
 	atf_add_test_case "overindex"
 	atf_add_test_case "overlimit"
+	atf_add_test_case "overhole"
+	atf_add_test_case "adjhole"
 	atf_add_test_case "reassemble"
 	atf_add_test_case "no_df"
 	atf_add_test_case "reassemble_slowpath"



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502181743.51IHhGNS021418>