Netdev List
 help / color / mirror / Atom feed
* [PATCH net v5] arp: Fix Hole-196 vulnerability by dropping unicast ARP replies in L2 BMC
@ 2026-10-30  3:11 Star Chang
  0 siblings, 0 replies; only message in thread
From: Star Chang @ 2026-10-30  3:11 UTC (permalink / raw)
  To: netdev
  Cc: ja, dsahern, idosch, davem, edumazet, kuba, pabeni, horms,
	johannes, johannes.berg, linux-kernel, wangroger, starchang

Wi-Fi 802.11 to 802.3 frame translation allows attackers to inject
frames inside GTK-encrypted L2 broadcast/multicast (BMC) frames (the
"Hole-196" vulnerability).

While the `drop_unicast_in_l2_multicast` sysctl drops unicast
IPv4/IPv6 packets received over L2 BMC, it did not check ARP replies in
`net/ipv4/arp.c`. In laboratory testing on shared-key Wi-Fi networks,
an attacker can inject an unsolicited unicast ARP reply (e.g. sip =
gateway IP, sha = attacker MAC, tip = victim IP) over L2 broadcast. If
the victim already has a neighbor entry for the gateway (such as after
normal network traffic), `neigh_update()` is invoked after the
1-second locktime window, overwriting the gateway's cached MAC address
with the attacker's MAC.

Under standard networking behavior, a non-GARP ARP reply is strictly
meant to be delivered as an L2 unicast frame (PACKET_HOST) to the
requester. The only legitimate reason an ARP reply is sent over L2
broadcast is for Gratuitous ARP (sip == tip) or address announcement.

Enhance `drop_unicast_in_l2_multicast` sysctl enforcement:
- Drop ARP replies received over L2 BMC frames unless they are
  Gratuitous ARP (sip == tip), recording
  SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST.
- Preserve legitimate GARP announcements (sip == tip) so they continue
  to defer to the `drop_gratuitous_arp` sysctl, preserving VRRP/HSRP
  router failover.
- Leave ARP requests untouched per RFC 826.
- Update Documentation/networking/ip-sysctl.rst to describe the ARP
  behavior.

Fixes: 12b74dfadb5a ("ipv4: add option to drop unicast encapsulated in L2 multicast")
Signed-off-by: Star Chang <starchang@google.com>
---
v4 -> v5:
  - Drop all IP and IPv6 changes to avoid UAF risks and adhere to RFC 1122.
  - Simplify ARP logic to strictly drop non-GARP ARP replies (ar_op == ARPOP_REPLY && sip != tip) over L2 BMC.
  - Do not inspect or gate on target hardware address (tha), leaving ARP requests untouched per RFC 826.
  - Update Documentation/networking/ip-sysctl.rst to accurately reflect ARP behavior.
  - Record SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST on drop.
  - Retain only Fixes: 12b74dfadb5a.

v3 -> v4:
  - Addressed review feedback on ratelimit logging and drop counters.

v2 -> v3:
  - Added THA validation and gratuitous ARP handling.

v1 -> v2:
  - Initial expansion to ARP.

 Documentation/networking/ip-sysctl.rst |  4 ++--
 net/ipv4/arp.c                         | 20 ++++++++++++++++++++
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
index 208f46967ee5..0e4f151fac48 100644
--- a/Documentation/networking/ip-sysctl.rst
+++ b/Documentation/networking/ip-sysctl.rst
@@ -2297,8 +2297,8 @@ promote_secondaries - BOOLEAN
 	Default: 0 (disabled)
 
 drop_unicast_in_l2_multicast - BOOLEAN
-	Drop any unicast IP packets that are received in link-layer
-	multicast (or broadcast) frames.
+	Drop any unicast IP packets and non-GARP ARP replies that are
+	received in link-layer multicast (or broadcast) frames.
 
 	This behavior (for multicast) is actually a SHOULD in RFC
 	1122, but is disabled by default for compatibility reasons.
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index d409f606aec0..d6a01d05aa75 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -791,6 +791,26 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
 	    (!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip)))
 		goto out_free_skb;
 
+/*
+ * Hole-196 defense for ARP:
+ * If drop_unicast_in_l2_multicast is enabled, drop ARP Replies received
+ * in L2 BMC frames unless they are Gratuitous ARP (sip == tip).
+ *
+ * Standard ARP Replies are strictly unicast (PACKET_HOST). An ARP Reply
+ * in an L2 broadcast frame with (sip != tip) is an injected unicast packet.
+ * Legitimate GARP (sip == tip) is preserved and defers to DROP_GRATUITOUS_ARP.
+ * ARP Requests are left untouched per RFC 826.
+ */
+	if ((skb->pkt_type == PACKET_BROADCAST ||
+	     skb->pkt_type == PACKET_MULTICAST) &&
+	    IN_DEV_ORCONF(in_dev, DROP_UNICAST_IN_L2_MULTICAST)) {
+		if (arp->ar_op == htons(ARPOP_REPLY) && sip != tip) {
+			kfree_skb_reason(skb,
+					 SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST);
+			return NET_RX_DROP;
+		}
+	}
+
  /*
   *	For some 802.11 wireless deployments (and possibly other networks),
   *	there will be an ARP proxy and gratuitous ARP frames are attacks
-- 
2.56.0.317.g454f8302e1-goog

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-30  3:11 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-30  3:11 [PATCH net v5] arp: Fix Hole-196 vulnerability by dropping unicast ARP replies in L2 BMC Star Chang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox