[PATCH net v5] arp: Fix Hole-196 vulnerability by dropping unicast ARP replies in L2 BMC
flat view
From: Star Chang <hidden>
Date: 2026-10-30 03:11:39
Also in:
lkml
Subsystem:
documentation, networking [general], networking [ipv4/ipv6], the rest · Maintainers:
Jonathan Corbet, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds
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 <redacted> --- 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