wpa_supplicant: don't reply to EAPOL if pkt_type is PACKET_OTHERHOST

Message ID bed5b01d5240b36959947cf0f9e5119291f496b6.1513699065.git.davide.caratti@gmail.com
State Superseded
Headers show
Series
  • wpa_supplicant: don't reply to EAPOL if pkt_type is PACKET_OTHERHOST
Related show

Commit Message

Davide Caratti Dec. 19, 2017, 4:04 p.m.
When wpa_supplicant is running on a Linux interface that is configured in
promiscuous mode, and it is not a member of a bridge, incoming EAPOL
packets are processed regardless of the Destination Address in the frame.
As a consequence, there are situations where wpa_supplicant replies to
EAPOL packets that are not destined for it.

This behavior seems undesired (see IEEE Std 802.1X-2010, 11.4.a), and can
be avoided by attaching a BPF filter that lets the kernel discard packets
having pkt_type equal to PACKET_OTHERHOST.

Signed-off-by: Davide Caratti <davide.caratti@gmail.com>
---
 src/l2_packet/l2_packet.h       |  1 +
 src/l2_packet/l2_packet_linux.c | 22 ++++++++++++++++++++++
 wpa_supplicant/wpa_supplicant.c |  5 +++++
 3 files changed, 28 insertions(+)

Patch

diff --git a/src/l2_packet/l2_packet.h b/src/l2_packet/l2_packet.h
index 2a4524582..53871774b 100644
--- a/src/l2_packet/l2_packet.h
+++ b/src/l2_packet/l2_packet.h
@@ -42,6 +42,7 @@  struct l2_ethhdr {
 enum l2_packet_filter_type {
 	L2_PACKET_FILTER_DHCP,
 	L2_PACKET_FILTER_NDISC,
+	L2_PACKET_FILTER_PKTTYPE,
 };
 
 /**
diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c
index 65b490679..b155bd673 100644
--- a/src/l2_packet/l2_packet_linux.c
+++ b/src/l2_packet/l2_packet_linux.c
@@ -84,6 +84,25 @@  static const struct sock_fprog ndisc_sock_filter = {
 	.filter = ndisc_sock_filter_insns,
 };
 
+/* drop packet if skb->pkt_type is PACKET_OTHERHOST (0x03). Generated by:
+ * $ bpfc - << -EOF
+ * > ldb #type
+ * > jeq #0x03, drop
+ * > pass: ret #-1
+ * > drop: ret #0
+ * > -EOF
+ */
+static struct sock_filter pkt_type_filter_insns[] = {
+	{ 0x30, 0, 0, 0xfffff004 },
+	{ 0x15, 1, 0, 0x00000003 },
+	{ 0x6, 0, 0, 0xffffffff },
+	{ 0x6, 0, 0, 0x00000000 },
+};
+
+static const struct sock_fprog pkt_type_sock_filter = {
+	.len = ARRAY_SIZE(pkt_type_filter_insns),
+	.filter = pkt_type_filter_insns,
+};
 
 int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
 {
@@ -471,6 +490,9 @@  int l2_packet_set_packet_filter(struct l2_packet_data *l2,
 	case L2_PACKET_FILTER_NDISC:
 		sock_filter = &ndisc_sock_filter;
 		break;
+	case L2_PACKET_FILTER_PKTTYPE:
+		sock_filter = &pkt_type_sock_filter;
+		break;
 	default:
 		return -1;
 	}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 984fe02f7..74b4c56d5 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -3962,6 +3962,11 @@  int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
 					   wpa_supplicant_rx_eapol, wpa_s, 0);
 		if (wpa_s->l2 == NULL)
 			return -1;
+
+		if (l2_packet_set_packet_filter(wpa_s->l2,
+						L2_PACKET_FILTER_PKTTYPE))
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"Failed to attach pkt_type filter");
 	} else {
 		const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
 		if (addr)