changeset 4501:be15f5b1966c draft

BPF: Fix ARP BPF filter to actually filter unwanted ARP message types While here, clarify the BPF instruction space needed for ARP as it could overflow in the very unlikely event we ARP for three addresses at the same time.
author Roy Marples <roy@marples.name>
date Fri, 03 May 2019 14:50:28 +0100
parents 94b77a3ab52f
children 5d361d74621c
files src/bpf.c
diffstat 1 files changed, 14 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/bpf.c	Fri May 03 14:44:06 2019 +0100
+++ b/src/bpf.c	Fri May 03 14:50:28 2019 +0100
@@ -301,6 +301,7 @@
 /* Normally this is needed by bootp.
  * Once that uses this again, the ARP guard here can be removed. */
 #ifdef ARP
+#define BPF_CMP_HWADDR_LEN	((((HWADDR_LEN / 4) + 2) * 2) + 1)
 static unsigned int
 bpf_cmp_hwaddr(struct bpf_insn *bpf, size_t bpf_len, size_t off,
     bool equal, uint8_t *hwaddr, size_t hwaddr_len)
@@ -414,7 +415,7 @@
 	         sizeof(((struct ether_arp *)0)->arp_sha), 1, 0),
 	BPF_STMT(BPF_RET + BPF_K, 0),
 };
-#define bpf_arp_ether_len	__arraycount(bpf_arp_ether)
+#define BPF_ARP_ETHER_LEN	__arraycount(bpf_arp_ether)
 
 static const struct bpf_insn bpf_arp_filter [] = {
 	/* Make sure this is for IP. */
@@ -425,21 +426,25 @@
 	BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct arphdr, ar_op)),
 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0),
 	/* or ARP REPLY. */
-	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 1),
+	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0),
 	BPF_STMT(BPF_RET + BPF_K, 0),
 	/* Make sure the protocol length matches. */
 	BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(struct arphdr, ar_pln)),
 	BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(in_addr_t), 1, 0),
 	BPF_STMT(BPF_RET + BPF_K, 0),
 };
-#define bpf_arp_filter_len	__arraycount(bpf_arp_filter)
-#define bpf_arp_extra		((((ARP_ADDRS_MAX + 1) * 2) * 2) + 2)
-#define bpf_arp_hw		((((HWADDR_LEN / 4) + 2) * 2) + 1)
+#define BPF_ARP_FILTER_LEN	__arraycount(bpf_arp_filter)
+
+#define BPF_ARP_ADDRS_LEN	1 + (ARP_ADDRS_MAX * 2) + 3 + \
+				(ARP_ADDRS_MAX * 2) + 1
+
+#define BPF_ARP_LEN		BPF_ARP_ETHER_LEN + BPF_ARP_FILTER_LEN + \
+				BPF_CMP_HWADDR_LEN + BPF_ARP_ADDRS_LEN
 
 int
 bpf_arp(struct interface *ifp, int fd)
 {
-	struct bpf_insn bpf[3+ bpf_arp_filter_len + bpf_arp_hw + bpf_arp_extra];
+	struct bpf_insn bpf[BPF_ARP_LEN];
 	struct bpf_insn *bp;
 	struct iarp_state *state;
 	uint16_t arp_len;
@@ -452,7 +457,7 @@
 	switch(ifp->family) {
 	case ARPHRD_ETHER:
 		memcpy(bp, bpf_arp_ether, sizeof(bpf_arp_ether));
-		bp += bpf_arp_ether_len;
+		bp += BPF_ARP_ETHER_LEN;
 		arp_len = sizeof(struct ether_header)+sizeof(struct ether_arp);
 		break;
 	default:
@@ -462,10 +467,10 @@
 
 	/* Copy in the main filter. */
 	memcpy(bp, bpf_arp_filter, sizeof(bpf_arp_filter));
-	bp += bpf_arp_filter_len;
+	bp += BPF_ARP_FILTER_LEN;
 
 	/* Ensure it's not from us. */
-	bp += bpf_cmp_hwaddr(bp, bpf_arp_hw, sizeof(struct arphdr),
+	bp += bpf_cmp_hwaddr(bp, BPF_CMP_HWADDR_LEN, sizeof(struct arphdr),
 	                     false, ifp->hwaddr, ifp->hwlen);
 
 	state = ARP_STATE(ifp);