The raw packet socket is created with ETH_P_ALL as protocol, which
registers the ethernet packet hook immediately. Frames from every interface
start queuing the moment the socket exists. The BPF filter that restricts
the socket to batman-adv ICMP packets with our uid is only attached after
bind(). Frames received in the window between socket() and SO_ATTACH_FILTER
are therefore queued unfiltered.

Delay the start of the capture by:

* create the socket with protocol 0 (no capture)
* attach the filter while the queue is guaranteed empty
* then bind() with sll_protocol = htons(ETH_P_ALL)

Only after the bind, packets will be captured.

Fixes: 4bd751eed4dc ("batctl: Implement non-routing batadv_icmp in userspace")
Signed-off-by: Sven Eckelmann <[email protected]>
---
 icmp_helper.c | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/icmp_helper.c b/icmp_helper.c
index 52ac22d..570f0b3 100644
--- a/icmp_helper.c
+++ b/icmp_helper.c
@@ -176,7 +176,12 @@ static int icmp_interface_add(const char *ifname, const 
uint8_t mac[ETH_ALEN])
        strncpy(iface->name, ifname, IFNAMSIZ);
        iface->name[sizeof(iface->name) - 1] = '\0';
 
-       iface->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+       /* create the socket with protocol 0 so the kernel does not start
+        * capturing yet - otherwise frames would queue unfiltered between
+        * socket() and SO_ATTACH_FILTER. Delivery only starts at bind() below,
+        * by which time the filter is already installed.
+        */
+       iface->sock = socket(PF_PACKET, SOCK_RAW, 0);
        if (iface->sock < 0) {
                perror("Error - can't create raw socket");
                ret = -errno;
@@ -194,6 +199,12 @@ static int icmp_interface_add(const char *ifname, const 
uint8_t mac[ETH_ALEN])
                goto close_sock;
        }
 
+       ret = icmp_interface_filter(iface->sock, uid);
+       if (ret < 0) {
+               fprintf(stderr, "Error - can't add filter to raw socket: %s\n", 
strerror(-ret));
+               goto close_sock;
+       }
+
        memset(&sll, 0, sizeof(sll));
        sll.sll_family = AF_PACKET;
        sll.sll_protocol = htons(ETH_P_ALL);
@@ -207,12 +218,6 @@ static int icmp_interface_add(const char *ifname, const 
uint8_t mac[ETH_ALEN])
                goto close_sock;
        }
 
-       ret = icmp_interface_filter(iface->sock, uid);
-       if (ret < 0) {
-               fprintf(stderr, "Error - can't add filter to raw socket: %s\n", 
strerror(-ret));
-               goto close_sock;
-       }
-
        list_add(&iface->list, &interface_list);
 
        return 0;

-- 
2.47.3

Reply via email to