lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <f19d6b009da1f198a2afa51a271afcb535c5cf8b.1770241104.git.marcdevel@gmail.com>
Date: Wed,  4 Feb 2026 23:11:59 +0100
From: Marc Suñé <marcdevel@...il.com>
To: kuba@...nel.org,
	willemdebruijn.kernel@...il.com,
	pabeni@...hat.com
Cc: netdev@...r.kernel.org,
	dborkman@...nel.org,
	vadim.fedorenko@...ux.dev,
	Marc Suñé <marcdevel@...il.com>
Subject: [PATCH net-next v3 2/4] selftests/net: add no ARP b/mcast,null poison test

Add a selftest to test that ARP bcast/mcast/null poisioning checks
are never bypassed.

Signed-off-by: Marc Suñé <marcdevel@...il.com>
---
 tools/testing/selftests/net/Makefile          |   1 +
 .../net/arp_no_invalid_sha_poision.sh         | 173 ++++++++++++++++++
 2 files changed, 174 insertions(+)
 create mode 100755 tools/testing/selftests/net/arp_no_invalid_sha_poision.sh

diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 45c4ea381bc3..64bfbb29a427 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -11,6 +11,7 @@ TEST_PROGS := \
 	amt.sh \
 	arp_ndisc_evict_nocarrier.sh \
 	arp_ndisc_untracked_subnets.sh \
+	arp_no_invalid_sha_poision.sh \
 	bareudp.sh \
 	big_tcp.sh \
 	bind_bhash.sh \
diff --git a/tools/testing/selftests/net/arp_no_invalid_sha_poision.sh b/tools/testing/selftests/net/arp_no_invalid_sha_poision.sh
new file mode 100755
index 000000000000..755dd31212c8
--- /dev/null
+++ b/tools/testing/selftests/net/arp_no_invalid_sha_poision.sh
@@ -0,0 +1,173 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Tests that ARP announcements with Broadcast, Multicast or NULL mac are never
+# accepted
+#
+
+source lib.sh
+
+readonly V4_ADDR0="10.0.10.1"
+readonly V4_ADDR1="10.0.10.2"
+readonly BCAST_MAC="ff:ff:ff:ff:ff:ff"
+readonly MCAST_MAC="01:00:5e:00:00:00"
+readonly NULL_MAC="00:00:00:00:00:00"
+readonly VALID_MAC="02:01:02:03:04:05"
+readonly ARP_REQ="request"
+readonly ARP_REPLY="reply"
+ret=0
+veth1_mac=
+
+setup() {
+	setup_ns PEER_NS
+
+	ip link add name veth0 type veth peer name veth1
+	ip link set dev veth0 up
+	ip link set dev veth1 netns "${PEER_NS}"
+	ip netns exec "${PEER_NS}" ip link set dev veth1 up
+	ip addr add "${V4_ADDR0}"/24 dev veth0
+	ip netns exec "${PEER_NS}" ip addr add "${V4_ADDR1}"/24 dev veth1
+	ip netns exec "${PEER_NS}" ip route add default via "${V4_ADDR0}" dev veth1
+
+	# Raise ARP timers to avoid flakes due to refreshes
+	sysctl -w net.ipv4.neigh.veth0.base_reachable_time=3600 \
+		>/dev/null 2>&1
+	ip netns exec "${PEER_NS}" \
+		sysctl -w net.ipv4.neigh.veth1.gc_stale_time=3600 \
+		>/dev/null 2>&1
+	ip netns exec "${PEER_NS}" \
+		sysctl -w net.ipv4.neigh.veth1.base_reachable_time=3600 \
+		>/dev/null 2>&1
+
+	veth1_mac="$(ip netns exec "${PEER_NS}" ip -j link show veth1 | \
+		jq -r '.[0].address' )"
+}
+
+cleanup() {
+	ip neigh flush dev veth0
+	ip link del veth0
+	cleanup_ns "${PEER_NS}"
+}
+
+# Make sure ARP announcement with invalid MAC is never learnt
+run_no_arp_poisoning() {
+	local l2_dmac="${1}"
+	local tmac="${2}"
+	local op="${3}"
+
+	ret=0
+
+	ip netns exec "${PEER_NS}" ip neigh flush dev veth1 >/dev/null 2>&1
+	ip netns exec "${PEER_NS}" ping -c 1 "${V4_ADDR0}" >/dev/null 2>&1
+
+	# Poison with a valid MAC to ensure injection is working
+	mausezahn "veth0" -q -a "${VALID_MAC}" -b "${BCAST_MAC}" -t arp \
+		  "${op}, sip=${V4_ADDR0}, tip=${V4_ADDR0}, smac=${VALID_MAC}, tmac=${VALID_MAC}"
+
+	neigh=$(ip netns exec "${PEER_NS}" ip neigh show "${V4_ADDR0}" | \
+		grep "${VALID_MAC}")
+	if [ "${neigh}" == "" ]; then
+		echo "ERROR: unable to ARP poision with a valid MAC ${VALID_MAC}"
+		ip netns exec "${PEER_NS}" ip neigh show "${V4_ADDR0}"
+		ret=1
+		return
+	fi
+
+	# Poison with tmac
+	mausezahn "veth0" -q -a "${VALID_MAC}" -b "${l2_dmac}" -t arp \
+		  "${op}, sip=${V4_ADDR0}, tip=${V4_ADDR0}, smac=${tmac}, tmac=${tmac}"
+
+	neigh=$(ip netns exec "${PEER_NS}" ip neigh show "${V4_ADDR0}" | \
+		grep "${tmac}")
+	if [ "${neigh}" != "" ]; then
+		echo "ERROR: ARP entry learnt for ${tmac} announcement."
+		ip netns exec "${PEER_NS}" ip neigh show "${V4_ADDR0}"
+		ret=1
+		return
+	fi
+}
+
+print_test_result() {
+	local msg="${1}"
+	local rc="${2}"
+
+	if [ "${rc}" == 0 ]; then
+		printf "TEST: %-60s  [ OK ]" "${msg}"
+	else
+		printf "TEST: %-60s  [ FAIL ]" "${msg}"
+	fi
+}
+
+run_all_tests() {
+	local results
+
+	setup
+
+	## ARP
+	# Broadcast gARPs
+	msg="1.1  ARP no poisoning dmac=bcast reply sha=bcast"
+	run_no_arp_poisoning "${BCAST_MAC}" "${BCAST_MAC}" "${ARP_REPLY}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	msg="1.2  ARP no poisoning dmac=bcast reply sha=null"
+	run_no_arp_poisoning "${BCAST_MAC}" "${NULL_MAC}" "${ARP_REPLY}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	msg="1.3  ARP no poisoning dmac=bcast req   sha=bcast"
+	run_no_arp_poisoning "${BCAST_MAC}" "${BCAST_MAC}" "${ARP_REQ}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	msg="1.4  ARP no poisoning dmac=bcast req   sha=null"
+	run_no_arp_poisoning "${BCAST_MAC}" "${NULL_MAC}" "${ARP_REQ}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	msg="1.5  ARP no poisoning dmac=bcast req   sha=mcast"
+	run_no_arp_poisoning "${BCAST_MAC}" "${MCAST_MAC}" "${ARP_REQ}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	msg="1.6  ARP no poisoning dmac=bcast reply sha=mcast"
+	run_no_arp_poisoning "${BCAST_MAC}" "${MCAST_MAC}" "${ARP_REPLY}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	# Targeted gARPs
+	msg="1.7  ARP no poisoning dmac=veth0 reply sha=bcast"
+	run_no_arp_poisoning "${veth1_mac}" "${BCAST_MAC}" "${ARP_REPLY}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	msg="1.8  ARP no poisoning dmac=veth0 reply sha=null"
+	run_no_arp_poisoning "${veth1_mac}" "${NULL_MAC}" "${ARP_REPLY}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	msg="1.9  ARP no poisoning dmac=veth0 req   sha=bcast"
+	run_no_arp_poisoning "${veth1_mac}" "${BCAST_MAC}" "${ARP_REQ}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	msg="1.10 ARP no poisoning dmac=veth0 req   sha=null"
+	run_no_arp_poisoning "${veth1_mac}" "${NULL_MAC}" "${ARP_REQ}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	msg="1.11 ARP no poisoning dmac=veth0 req   sha=mcast"
+	run_no_arp_poisoning "${veth1_mac}" "${MCAST_MAC}" "${ARP_REQ}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	msg="1.12 ARP no poisoning dmac=veth0 reply sha=mcast"
+	run_no_arp_poisoning "${veth1_mac}" "${MCAST_MAC}" "${ARP_REPLY}"
+	results+="$(print_test_result "${msg}" "${ret}")\n"
+
+	cleanup
+
+	printf '%b' "${results}"
+}
+
+if [ "$(id -u)" -ne 0 ];then
+	echo "SKIP: Need root privileges"
+	exit "${ksft_skip}"
+fi
+
+if [ ! -x "$(command -v ip)" ]; then
+	echo "SKIP: Could not run test without ip tool"
+	exit "${ksft_skip}"
+fi
+
+run_all_tests
+exit "${ret}"
-- 
2.47.3


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ