mirror of
https://github.com/openwrt/routing.git
synced 2026-10-14 17:26:30 +04:00
batman-adv: merge bugfixes from 2026.3
* ensure minimal ethernet header on TX * fix VLAN priority offset * tt: avoid request storms during pending request * frag: fix primary_if leak on failed linearization * frag: free unfragmentable packet * mcast: avoid OOB read of num_dests header * tt: prevent TVLV OOB check overflow * clean untagged VLAN on netdev registration failure * dat: fix tie-break for candidate selection * bla: avoid CRC corruption due to parallel claim add * bla: prevent CRC corruptions after claim flush * dat: avoid unaligned fault in IP extraction * dat: atomically update mac addresses * fix TX priority extraction for BATADV_FORW_MCAST * mcast: ensure unshared skb for multicast packets * mcast: linearize skbuff for packet generation * fix stale receive device on merged fragments * tvlv: handle negative tvlv processing return codes * bla: fix freeing of claims on meshif deletion * reject unrepresentable multicast TVLV offsets Signed-off-by: Sven Eckelmann <sven@narfation.org>
This commit is contained in:
22 files changed
+1159
-1
No files matched your search
+1
-1
@@ -4,7 +4,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=batman-adv
|
||||
PKG_VERSION:=2025.4
|
||||
PKG_RELEASE:=6
|
||||
PKG_RELEASE:=7
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://downloads.open-mesh.org/batman/releases/batman-adv-$(PKG_VERSION)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Thu, 2 Jul 2026 11:34:54 +0200
|
||||
Subject: batman-adv: ensure minimal ethernet header on TX
|
||||
|
||||
As documented in commit 8bd67ebb50c0 ("net: bridge: xmit: make sure we have
|
||||
at least eth header len bytes"), it is possible by for a local user with
|
||||
eBPF TC hook access to attach a tc filter which truncates the packet and
|
||||
redirects to an batadv interface. But the code assumes that at least
|
||||
ETH_HLEN bytes are available and thus might read outside of the available
|
||||
buffer.
|
||||
|
||||
The batadv_interface_tx() must therefore always check itself if enough data
|
||||
is available for the ethernet header and don't rely on min_header_len.
|
||||
|
||||
Fixes: 094a751463a9 ("route outgoing traffic")
|
||||
Reported-by: Sashiko <sashiko-bot@kernel.org>
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=c54eb3034180f1e5230da89cdb6885849d93c397
|
||||
|
||||
--- a/net/batman-adv/mesh-interface.c
|
||||
+++ b/net/batman-adv/mesh-interface.c
|
||||
@@ -193,6 +193,9 @@ static netdev_tx_t batadv_interface_tx(s
|
||||
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
|
||||
goto dropped;
|
||||
|
||||
+ if (!pskb_may_pull(skb, ETH_HLEN))
|
||||
+ goto dropped;
|
||||
+
|
||||
/* reset control block to avoid left overs from previous users */
|
||||
memset(skb->cb, 0, sizeof(struct batadv_skb_cb));
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Thu, 2 Jul 2026 20:41:13 +0200
|
||||
Subject: batman-adv: fix VLAN priority offset
|
||||
|
||||
The batadv_skb_set_priority() receives an SKB with the inner ethernet
|
||||
header at position "offset". When it tries to extract the IPv4 and IPv6
|
||||
header, it needs to skip the ethernet header to get access to the IP
|
||||
header.
|
||||
|
||||
But for VLAN header, it performs the access with the struct vlan_ethhdr.
|
||||
This struct contains both both the ethernet header and the VLAN header. It
|
||||
is therefore incorrect to skip over the whole vlan_ethhdr size to get
|
||||
access to the vlan_ethhdr.
|
||||
|
||||
Fixes: eb7643628a60 ("batman-adv: set skb priority according to content")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=23b07325f689f8b88db714b1388d8dee136bc9d9
|
||||
|
||||
--- a/net/batman-adv/main.c
|
||||
+++ b/net/batman-adv/main.c
|
||||
@@ -354,7 +354,7 @@ void batadv_skb_set_priority(struct sk_b
|
||||
|
||||
switch (ethhdr->h_proto) {
|
||||
case htons(ETH_P_8021Q):
|
||||
- vhdr = skb_header_pointer(skb, offset + sizeof(*vhdr),
|
||||
+ vhdr = skb_header_pointer(skb, offset,
|
||||
sizeof(*vhdr), &vhdr_tmp);
|
||||
if (!vhdr)
|
||||
return;
|
||||
@@ -0,0 +1,32 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Thu, 2 Jul 2026 20:56:14 +0200
|
||||
Subject: batman-adv: tt: avoid request storms during pending request
|
||||
|
||||
batadv_send_tt_request() allocates a tt_req_node when none exists for the
|
||||
destination originator node. This should prevent that a multiple TT
|
||||
requests are send at the same time to an originator.
|
||||
|
||||
But if allocation of the send buffer failed, this request must be cleaned
|
||||
up again. But indicator for such a failure is "ret == false". But the
|
||||
actual implementation is checking for "ret == true".
|
||||
|
||||
The check must be inverted to not loose the information about the TT
|
||||
request directly after it was attempted to be sent out. This should avoid
|
||||
potential request storms.
|
||||
|
||||
Fixes: 6228419df3a5 ("batman-adv: tvlv - convert tt query packet to use tvlv unicast packets")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=1315afbabaa985f87fa772616b70df025bbe3dcc
|
||||
|
||||
--- a/net/batman-adv/translation-table.c
|
||||
+++ b/net/batman-adv/translation-table.c
|
||||
@@ -3003,7 +3003,7 @@ static bool batadv_send_tt_request(struc
|
||||
out:
|
||||
batadv_hardif_put(primary_if);
|
||||
|
||||
- if (ret && tt_req_node) {
|
||||
+ if (!ret && tt_req_node) {
|
||||
spin_lock_bh(&bat_priv->tt.req_list_lock);
|
||||
if (!hlist_unhashed(&tt_req_node->list)) {
|
||||
hlist_del_init(&tt_req_node->list);
|
||||
@@ -0,0 +1,25 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Fri, 3 Jul 2026 20:51:44 +0200
|
||||
Subject: batman-adv: frag: fix primary_if leak on failed linearization
|
||||
|
||||
If the skb has a frag_list, it must be linearized before it can be split
|
||||
using skb_split(). But when this step failed, it must not only free the skb
|
||||
but also take care of the reference to the already found primary_if.
|
||||
|
||||
Reported-by: Sashiko <sashiko-bot@kernel.org>
|
||||
Fixes: d467720acaf1 ("batman-adv: Don't skb_split skbuffs with frag_list")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=54ddb49d2d97e1667bd5f2b6a8ee291a668f37f2
|
||||
|
||||
--- a/net/batman-adv/fragmentation.c
|
||||
+++ b/net/batman-adv/fragmentation.c
|
||||
@@ -543,7 +543,7 @@ int batadv_frag_send_packet(struct sk_bu
|
||||
*/
|
||||
if (skb_has_frag_list(skb) && __skb_linearize(skb)) {
|
||||
ret = -ENOMEM;
|
||||
- goto free_skb;
|
||||
+ goto put_primary_if;
|
||||
}
|
||||
|
||||
/* Create one header to be copied to all fragments */
|
||||
@@ -0,0 +1,31 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Fri, 3 Jul 2026 20:21:16 +0200
|
||||
Subject: batman-adv: frag: free unfragmentable packet
|
||||
|
||||
The caller of batadv_frag_send_packet() assume that the skb provided to the
|
||||
function are always consumed. But the pre-check for an empty payload or the
|
||||
zero fragment size returned an error without any further actions.
|
||||
|
||||
A failed pre-check must use the same error handling code as the rest of the
|
||||
function.
|
||||
|
||||
Fixes: db56e4ecf5c2 ("batman-adv: Fragment and send skbs larger than mtu")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=2cc7404af2a7d18357134237a41a55b303eea700
|
||||
|
||||
--- a/net/batman-adv/fragmentation.c
|
||||
+++ b/net/batman-adv/fragmentation.c
|
||||
@@ -516,8 +516,10 @@ int batadv_frag_send_packet(struct sk_bu
|
||||
mtu = min_t(unsigned int, mtu, BATADV_FRAG_MAX_FRAG_SIZE);
|
||||
max_fragment_size = mtu - header_size;
|
||||
|
||||
- if (skb->len == 0 || max_fragment_size == 0)
|
||||
- return -EINVAL;
|
||||
+ if (skb->len == 0 || max_fragment_size == 0) {
|
||||
+ ret = -EINVAL;
|
||||
+ goto free_skb;
|
||||
+ }
|
||||
|
||||
num_fragments = (skb->len - 1) / max_fragment_size + 1;
|
||||
max_fragment_size = (skb->len - 1) / num_fragments + 1;
|
||||
@@ -0,0 +1,46 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Fri, 3 Jul 2026 20:33:20 +0200
|
||||
Subject: batman-adv: mcast: avoid OOB read of num_dests header
|
||||
|
||||
Before the access to struct batadv_tvlv_mcast_tracker's num_dests, it is
|
||||
attempted to check whether enough space is actually in the network header.
|
||||
But instead of using offsetofend() to check for the whole size (2) which
|
||||
must be accessible, offsetof() of is called. The latter is always returning
|
||||
0. The comparison with the network header length will always return that
|
||||
enough data is available - even when only 1 or 0 bytes are accessible.
|
||||
|
||||
Instead of using offsetofend(), use the more common check for the whole
|
||||
header.
|
||||
|
||||
Fixes: 8ed36122d709 ("batman-adv: mcast: implement multicast packet reception and forwarding")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=34d3097e0313f9a2b44c96fb99d941c1acb896fa
|
||||
|
||||
--- a/net/batman-adv/multicast_forw.c
|
||||
+++ b/net/batman-adv/multicast_forw.c
|
||||
@@ -927,11 +927,11 @@ static int batadv_mcast_forw_packet(stru
|
||||
{
|
||||
struct batadv_tvlv_mcast_tracker *mcast_tracker;
|
||||
struct batadv_neigh_node *neigh_node;
|
||||
- unsigned long offset, num_dests_off;
|
||||
struct sk_buff *nexthop_skb;
|
||||
unsigned char *skb_net_hdr;
|
||||
bool local_recv = false;
|
||||
unsigned int tvlv_len;
|
||||
+ unsigned long offset;
|
||||
bool xmitted = false;
|
||||
u8 *dest, *next_dest;
|
||||
u16 num_dests;
|
||||
@@ -940,9 +940,8 @@ static int batadv_mcast_forw_packet(stru
|
||||
/* (at least) TVLV part needs to be linearized */
|
||||
SKB_LINEAR_ASSERT(skb);
|
||||
|
||||
- /* check if num_dests is within skb length */
|
||||
- num_dests_off = offsetof(struct batadv_tvlv_mcast_tracker, num_dests);
|
||||
- if (num_dests_off > skb_network_header_len(skb))
|
||||
+ /* check if batadv_tvlv_mcast_tracker header is within skb length */
|
||||
+ if (sizeof(*mcast_tracker) > skb_network_header_len(skb))
|
||||
return -EINVAL;
|
||||
|
||||
skb_net_hdr = skb_network_header(skb);
|
||||
@@ -0,0 +1,30 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Fri, 3 Jul 2026 22:19:01 +0200
|
||||
Subject: batman-adv: tt: prevent TVLV OOB check overflow
|
||||
|
||||
A TT unicast TVLV contains the number of VLANs stored in it. This number is
|
||||
an u16 and gets multiplied by the size of the struct
|
||||
batadv_tvlv_tt_vlan_data (8 bytes). The size can therefore overflow the u16
|
||||
used to store the tt_vlan_len. All additional safety checks to prevent
|
||||
out-of-bounds access of the TVLV buffer are invalid due to this overflow.
|
||||
|
||||
Using size_t prevents this overflow and ensures that the safety checks
|
||||
compare against the actual buffer requirements.
|
||||
|
||||
Fixes: 21a57f6e7a3b ("batman-adv: make the TT CRC logic VLAN specific")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=f11771cdce654b3b5e17d0fc08fb32c0d6fa6a39
|
||||
|
||||
--- a/net/batman-adv/translation-table.c
|
||||
+++ b/net/batman-adv/translation-table.c
|
||||
@@ -4065,7 +4065,8 @@ static int batadv_tt_tvlv_unicast_handle
|
||||
u16 tvlv_value_len)
|
||||
{
|
||||
struct batadv_tvlv_tt_data *tt_data;
|
||||
- u16 tt_vlan_len, tt_num_entries;
|
||||
+ u16 tt_num_entries;
|
||||
+ size_t tt_vlan_len;
|
||||
char tt_flag;
|
||||
bool ret;
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Sat, 4 Jul 2026 09:19:00 +0200
|
||||
Subject: batman-adv: clean untagged VLAN on netdev registration failure
|
||||
|
||||
When an mesh interface is registered, it creates an untagged struct
|
||||
batadv_meshif_vlan on top of it via the NETDEV_REGISTER notifier. But in
|
||||
this process, another receiver of this notification can veto the
|
||||
registration. The netdev registration will be aborted because of this veto.
|
||||
|
||||
The register_netdevice() call will try to clean up the net_device using
|
||||
unregister_netdevice_queue() - which only uses the .priv_destructor to
|
||||
free private resources. In this situation, .dellink will not be called.
|
||||
|
||||
The cleanup of the untagged batadv_meshif_vlan must thefore be done in the
|
||||
destructor to avoid a leak of this object.
|
||||
|
||||
Fixes: 952cebb57518 ("batman-adv: add per VLAN interface attribute framework")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=ebb41e16afeea3cfc0fd0c2abfa05b78a3ecec32
|
||||
|
||||
--- a/net/batman-adv/main.c
|
||||
+++ b/net/batman-adv/main.c
|
||||
@@ -245,6 +245,7 @@ err_orig:
|
||||
void batadv_mesh_free(struct net_device *mesh_iface)
|
||||
{
|
||||
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
|
||||
+ struct batadv_meshif_vlan *vlan;
|
||||
|
||||
atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
|
||||
|
||||
@@ -259,6 +260,13 @@ void batadv_mesh_free(struct net_device
|
||||
|
||||
batadv_mcast_free(bat_priv);
|
||||
|
||||
+ /* destroy the "untagged" VLAN */
|
||||
+ vlan = batadv_meshif_vlan_get(bat_priv, BATADV_NO_FLAGS);
|
||||
+ if (vlan) {
|
||||
+ batadv_meshif_destroy_vlan(bat_priv, vlan);
|
||||
+ batadv_meshif_vlan_put(vlan);
|
||||
+ }
|
||||
+
|
||||
/* Free the TT and the originator tables only after having terminated
|
||||
* all the other depending components which may use these structures for
|
||||
* their purposes.
|
||||
--- a/net/batman-adv/mesh-interface.c
|
||||
+++ b/net/batman-adv/mesh-interface.c
|
||||
@@ -593,8 +593,8 @@ int batadv_meshif_create_vlan(struct bat
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @vlan: the object to remove
|
||||
*/
|
||||
-static void batadv_meshif_destroy_vlan(struct batadv_priv *bat_priv,
|
||||
- struct batadv_meshif_vlan *vlan)
|
||||
+void batadv_meshif_destroy_vlan(struct batadv_priv *bat_priv,
|
||||
+ struct batadv_meshif_vlan *vlan)
|
||||
{
|
||||
/* explicitly remove the associated TT local entry because it is marked
|
||||
* with the NOPURGE flag
|
||||
@@ -1103,22 +1103,13 @@ static int batadv_meshif_newlink(struct
|
||||
static void batadv_meshif_destroy_netlink(struct net_device *mesh_iface,
|
||||
struct list_head *head)
|
||||
{
|
||||
- struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
|
||||
struct batadv_hard_iface *hard_iface;
|
||||
- struct batadv_meshif_vlan *vlan;
|
||||
|
||||
while (!list_empty(&mesh_iface->adj_list.lower)) {
|
||||
hard_iface = netdev_adjacent_get_private(mesh_iface->adj_list.lower.next);
|
||||
batadv_hardif_disable_interface(hard_iface);
|
||||
}
|
||||
|
||||
- /* destroy the "untagged" VLAN */
|
||||
- vlan = batadv_meshif_vlan_get(bat_priv, BATADV_NO_FLAGS);
|
||||
- if (vlan) {
|
||||
- batadv_meshif_destroy_vlan(bat_priv, vlan);
|
||||
- batadv_meshif_vlan_put(vlan);
|
||||
- }
|
||||
-
|
||||
unregister_netdevice_queue(mesh_iface, head);
|
||||
}
|
||||
|
||||
--- a/net/batman-adv/mesh-interface.h
|
||||
+++ b/net/batman-adv/mesh-interface.h
|
||||
@@ -21,6 +21,8 @@ void batadv_interface_rx(struct net_devi
|
||||
bool batadv_meshif_is_valid(const struct net_device *net_dev);
|
||||
extern struct rtnl_link_ops batadv_link_ops;
|
||||
int batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid);
|
||||
+void batadv_meshif_destroy_vlan(struct batadv_priv *bat_priv,
|
||||
+ struct batadv_meshif_vlan *vlan);
|
||||
void batadv_meshif_vlan_release(struct kref *ref);
|
||||
struct batadv_meshif_vlan *batadv_meshif_vlan_get(struct batadv_priv *bat_priv,
|
||||
unsigned short vid);
|
||||
@@ -0,0 +1,34 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Thu, 2 Jul 2026 19:32:40 +0200
|
||||
Subject: batman-adv: dat: fix tie-break for candidate selection
|
||||
|
||||
The original version of the candidate selection for DAT attempted to
|
||||
compare both candidate and max_orig_node to identify which has the smaller
|
||||
MAC address. This comparison is required as tie-break when a hash collision
|
||||
happened.
|
||||
|
||||
But the used function returned 0 when the function was not equal and a
|
||||
non-zero value when it was equal. As result, the actually selected
|
||||
node was dependent on the order of entries in the orig_hash and not
|
||||
actually on the mac addresses. The last originator in the hash collision
|
||||
would always win.
|
||||
|
||||
To have a proper ordering, it must diff the actual MAC address bytes and
|
||||
reject the candidate when the diff is not smaller than 0.
|
||||
|
||||
Fixes: 34b3c3850e7d ("batman-adv: Distributed ARP Table - create DHT helper functions")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=b9185d1d5d7b5031f41d65913056532f78802d50
|
||||
|
||||
--- a/net/batman-adv/distributed-arp-table.c
|
||||
+++ b/net/batman-adv/distributed-arp-table.c
|
||||
@@ -545,7 +545,7 @@ static bool batadv_is_orig_node_eligible
|
||||
* the one with the lowest address
|
||||
*/
|
||||
if (tmp_max == max && max_orig_node &&
|
||||
- batadv_compare_eth(candidate->orig, max_orig_node->orig))
|
||||
+ memcmp(candidate->orig, max_orig_node->orig, ETH_ALEN) >= 0)
|
||||
goto out;
|
||||
|
||||
ret = true;
|
||||
@@ -0,0 +1,148 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Fri, 3 Jul 2026 00:30:53 +0200
|
||||
Subject: batman-adv: bla: avoid CRC corruption due to parallel claim add
|
||||
|
||||
batadv_bla_add_claim() is used to add claims and modify the backbone of
|
||||
claims for CLAIM frames from remote backbones and local packets. When it
|
||||
handles a claim, it needs to either
|
||||
|
||||
* add the new claim's CRC to the backbone CRC
|
||||
* remove the already existing claim's CRC from the old backbone and add it
|
||||
to the new backbone
|
||||
|
||||
But when the "new" claim code was running in parallel to the "change
|
||||
backbone" code, it can happen that the CRC was invalid because the
|
||||
backbone_gw of the claim was changed twice in the "new" claim code path:
|
||||
|
||||
* CPU0 creates the claim for gateway A and publishes it in the claim
|
||||
hash. The crc16 of the address has not yet been added to A's crc at
|
||||
this point.
|
||||
|
||||
* CPU1 processes a claim frame of gateway B for the same client, finds
|
||||
the just published claim, and performs the ownership change: it
|
||||
switches the pointer to B, removes the crc16 from A's crc - which
|
||||
never contained it - and adds it to B's crc.
|
||||
|
||||
* CPU0 continues behind the creation branch, unconditionally switches
|
||||
the pointer back to A without compensating B's crc (its remove_crc
|
||||
is false for the creation path), and finally adds the crc16 to A's
|
||||
crc
|
||||
|
||||
The CRC is then wrong for both:
|
||||
|
||||
* claim belongs to A: but CRC is not part of backbone A's CRC
|
||||
* claim doesn't belong to B: CRC is still part of backbone B's CRC
|
||||
|
||||
This wrong CRC is never recomputated from the stored claims. For local
|
||||
backbone claims, this can also not recovered using syncs.
|
||||
|
||||
To avoid this, split the functionality in clear separate parts:
|
||||
|
||||
* new claim which always adds claim CRC to the backbone CRC (but never
|
||||
changes the already set backbone_gw of the claim back)
|
||||
|
||||
* update of existing claim which automatically changes the backbone_gw
|
||||
entry and only updates both backbone CRCs when there was an actual change
|
||||
|
||||
Reported-by: Sashiko <sashiko-bot@kernel.org>
|
||||
Fixes: a9ce0dc43e2c ("batman-adv: add basic bridge loop avoidance code")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=d88d7ea0d0befbb759d142682a5413531feb05a6
|
||||
|
||||
--- a/net/batman-adv/bridge_loop_avoidance.c
|
||||
+++ b/net/batman-adv/bridge_loop_avoidance.c
|
||||
@@ -699,12 +699,14 @@ static void batadv_bla_add_claim(struct
|
||||
struct batadv_bla_backbone_gw *old_backbone_gw;
|
||||
struct batadv_bla_claim *claim;
|
||||
struct batadv_bla_claim search_claim;
|
||||
- bool remove_crc = false;
|
||||
int hash_added;
|
||||
+ u16 claim_crc;
|
||||
+ bool changed;
|
||||
|
||||
ether_addr_copy(search_claim.addr, mac);
|
||||
search_claim.vid = vid;
|
||||
claim = batadv_claim_hash_find(bat_priv, &search_claim);
|
||||
+ claim_crc = crc16(0, mac, ETH_ALEN);
|
||||
|
||||
/* create a new claim entry if it does not exist yet. */
|
||||
if (!claim) {
|
||||
@@ -736,43 +738,55 @@ static void batadv_bla_add_claim(struct
|
||||
kfree(claim);
|
||||
return;
|
||||
}
|
||||
+
|
||||
+ spin_lock_bh(&backbone_gw->crc_lock);
|
||||
+ backbone_gw->crc ^= claim_crc;
|
||||
+ spin_unlock_bh(&backbone_gw->crc_lock);
|
||||
+
|
||||
+ WRITE_ONCE(backbone_gw->lasttime, jiffies);
|
||||
+
|
||||
+ batadv_claim_put(claim);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ WRITE_ONCE(claim->lasttime, jiffies);
|
||||
+
|
||||
+ /* replace backbone_gw atomically and adjust reference counters */
|
||||
+ spin_lock_bh(&claim->backbone_lock);
|
||||
+ if (claim->backbone_gw != backbone_gw) {
|
||||
+ changed = true;
|
||||
+
|
||||
+ old_backbone_gw = claim->backbone_gw;
|
||||
+ kref_get(&backbone_gw->refcount);
|
||||
+ claim->backbone_gw = backbone_gw;
|
||||
} else {
|
||||
- WRITE_ONCE(claim->lasttime, jiffies);
|
||||
- if (claim->backbone_gw == backbone_gw)
|
||||
- /* no need to register a new backbone */
|
||||
- goto claim_free_ref;
|
||||
+ old_backbone_gw = NULL;
|
||||
+ changed = false;
|
||||
+ }
|
||||
+ spin_unlock_bh(&claim->backbone_lock);
|
||||
|
||||
+ if (changed) {
|
||||
batadv_dbg(BATADV_DBG_BLA, bat_priv,
|
||||
"%s(): changing ownership for %pM, vid %d to gw %pM\n",
|
||||
__func__, mac, batadv_print_vid(vid),
|
||||
backbone_gw->orig);
|
||||
|
||||
- remove_crc = true;
|
||||
+ /* add claim address to new backbone_gw */
|
||||
+ spin_lock_bh(&backbone_gw->crc_lock);
|
||||
+ backbone_gw->crc ^= claim_crc;
|
||||
+ spin_unlock_bh(&backbone_gw->crc_lock);
|
||||
}
|
||||
|
||||
- /* replace backbone_gw atomically and adjust reference counters */
|
||||
- spin_lock_bh(&claim->backbone_lock);
|
||||
- old_backbone_gw = claim->backbone_gw;
|
||||
- kref_get(&backbone_gw->refcount);
|
||||
- claim->backbone_gw = backbone_gw;
|
||||
- spin_unlock_bh(&claim->backbone_lock);
|
||||
-
|
||||
- if (remove_crc) {
|
||||
+ if (old_backbone_gw) {
|
||||
/* remove claim address from old backbone_gw */
|
||||
spin_lock_bh(&old_backbone_gw->crc_lock);
|
||||
- old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
|
||||
+ old_backbone_gw->crc ^= claim_crc;
|
||||
spin_unlock_bh(&old_backbone_gw->crc_lock);
|
||||
- }
|
||||
|
||||
- batadv_backbone_gw_put(old_backbone_gw);
|
||||
+ batadv_backbone_gw_put(old_backbone_gw);
|
||||
+ }
|
||||
|
||||
- /* add claim address to new backbone_gw */
|
||||
- spin_lock_bh(&backbone_gw->crc_lock);
|
||||
- backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
|
||||
- spin_unlock_bh(&backbone_gw->crc_lock);
|
||||
WRITE_ONCE(backbone_gw->lasttime, jiffies);
|
||||
-
|
||||
-claim_free_ref:
|
||||
batadv_claim_put(claim);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Sun, 5 Jul 2026 22:21:50 +0200
|
||||
Subject: batman-adv: bla: prevent CRC corruptions after claim flush
|
||||
|
||||
When batadv_bla_del_backbone_claims() tried to remove all claims of a
|
||||
backbone, it sets the CRC to 0. It assumes that the it had the last
|
||||
reference of the claims because batadv_claim_release() (which runs after
|
||||
the last reference was released), is XORing the crc16 of the claim address
|
||||
with the backbone CRC.
|
||||
|
||||
If there would be a parallel holder of any of these references, it could
|
||||
happen that the backbone CRC is (0 ^ crc16(delayed_released_claim)). Which
|
||||
is the wrong starting point for the new claims it may receive when the
|
||||
remote answers the claim request from batadv_bla_send_request().
|
||||
|
||||
This reinitializations can be completely dropped to avoid this problem.
|
||||
batadv_claim_release() will take care of fixing the backbone CRC.
|
||||
|
||||
Fixes: a9ce0dc43e2c ("batman-adv: add basic bridge loop avoidance code")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=76e6026f15c9f4aa9ad1f83e122fac6446fc1132
|
||||
|
||||
--- a/net/batman-adv/bridge_loop_avoidance.c
|
||||
+++ b/net/batman-adv/bridge_loop_avoidance.c
|
||||
@@ -324,11 +324,6 @@ batadv_bla_del_backbone_claims(struct ba
|
||||
}
|
||||
spin_unlock_bh(list_lock);
|
||||
}
|
||||
-
|
||||
- /* all claims gone, initialize CRC */
|
||||
- spin_lock_bh(&backbone_gw->crc_lock);
|
||||
- backbone_gw->crc = BATADV_BLA_CRC_INIT;
|
||||
- spin_unlock_bh(&backbone_gw->crc_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,41 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Mon, 6 Jul 2026 19:46:37 +0200
|
||||
Subject: batman-adv: dat: avoid unaligned fault in IP extraction
|
||||
|
||||
Independent of the alignment of the ARP packet in the SKB, either the
|
||||
batadv_arp_ip_src or the batadv_arp_ip_dst will have an unaligned access
|
||||
(on HW without native unaligned read support).
|
||||
|
||||
Use get_unaligned() to handle this properly on all architectures.
|
||||
|
||||
Reported-by: Sashiko <sashiko-bot@kernel.org>
|
||||
Fixes: 0591c25abca9 ("batman-adv: Distributed ARP Table - add ARP parsing functions")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=2ba19c19805d21753cba095cdad3a32b0d49971b
|
||||
|
||||
--- a/net/batman-adv/distributed-arp-table.c
|
||||
+++ b/net/batman-adv/distributed-arp-table.c
|
||||
@@ -249,7 +249,10 @@ static u8 *batadv_arp_hw_src(struct sk_b
|
||||
*/
|
||||
static __be32 batadv_arp_ip_src(struct sk_buff *skb, int hdr_size)
|
||||
{
|
||||
- return *(__force __be32 *)(batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN);
|
||||
+ u8 *src = batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN;
|
||||
+ __be32 *ip = (__force __be32 *)src;
|
||||
+
|
||||
+ return get_unaligned(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,8 +277,9 @@ static u8 *batadv_arp_hw_dst(struct sk_b
|
||||
static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size)
|
||||
{
|
||||
u8 *dst = batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN * 2 + 4;
|
||||
+ __be32 *ip = (__force __be32 *)dst;
|
||||
|
||||
- return *(__force __be32 *)dst;
|
||||
+ return get_unaligned(ip);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,202 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Mon, 6 Jul 2026 18:36:47 +0200
|
||||
Subject: batman-adv: dat: atomically update mac addresses
|
||||
|
||||
When a MAC address is updated in batadv_dat_entry_add(), it is done using a
|
||||
simple copy function. A parallel reader might only see parts of this
|
||||
update. In worst case, the reader is transporting the half updated MAC
|
||||
address over the network or is creating an ARP response using it -
|
||||
poisoning the ARP cache.
|
||||
|
||||
atomic64_t can be used to store the 48 bit of a mac address. A reader will
|
||||
then either see the old mac address or the new one - never a mixture of
|
||||
both.
|
||||
|
||||
Reported-by: Sashiko <sashiko-bot@kernel.org>
|
||||
Fixes: f6badf9eb582 ("batman-adv: Distributed ARP Table - implement local storage")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=f22cdaf1f4df73442504e428be94300fac7dfc12
|
||||
|
||||
--- a/net/batman-adv/distributed-arp-table.c
|
||||
+++ b/net/batman-adv/distributed-arp-table.c
|
||||
@@ -375,18 +375,19 @@ batadv_dat_entry_hash_find(struct batadv
|
||||
static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
|
||||
u8 *mac_addr, unsigned short vid)
|
||||
{
|
||||
+ u64 u64_mac = ether_addr_to_u64(mac_addr);
|
||||
struct batadv_dat_entry *dat_entry;
|
||||
int hash_added;
|
||||
|
||||
dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid);
|
||||
/* if this entry is already known, just update it */
|
||||
if (dat_entry) {
|
||||
- if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))
|
||||
- ether_addr_copy(dat_entry->mac_addr, mac_addr);
|
||||
+ atomic64_set(&dat_entry->mac_addr, u64_mac);
|
||||
+
|
||||
dat_entry->last_update = jiffies;
|
||||
batadv_dbg(BATADV_DBG_DAT, bat_priv,
|
||||
"Entry updated: %pI4 %pM (vid: %d)\n",
|
||||
- &dat_entry->ip, dat_entry->mac_addr,
|
||||
+ &dat_entry->ip, mac_addr,
|
||||
batadv_print_vid(vid));
|
||||
goto out;
|
||||
}
|
||||
@@ -397,7 +398,7 @@ static void batadv_dat_entry_add(struct
|
||||
|
||||
dat_entry->ip = ip;
|
||||
dat_entry->vid = vid;
|
||||
- ether_addr_copy(dat_entry->mac_addr, mac_addr);
|
||||
+ atomic64_set(&dat_entry->mac_addr, u64_mac);
|
||||
dat_entry->last_update = jiffies;
|
||||
kref_init(&dat_entry->refcount);
|
||||
|
||||
@@ -413,7 +414,7 @@ static void batadv_dat_entry_add(struct
|
||||
}
|
||||
|
||||
batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %d)\n",
|
||||
- &dat_entry->ip, dat_entry->mac_addr, batadv_print_vid(vid));
|
||||
+ &dat_entry->ip, mac_addr, batadv_print_vid(vid));
|
||||
|
||||
out:
|
||||
batadv_dat_entry_put(dat_entry);
|
||||
@@ -868,6 +869,8 @@ batadv_dat_cache_dump_entry(struct sk_bu
|
||||
struct netlink_callback *cb,
|
||||
struct batadv_dat_entry *dat_entry)
|
||||
{
|
||||
+ u8 mac[ETH_ALEN];
|
||||
+ u64 u64_mac;
|
||||
int msecs;
|
||||
void *hdr;
|
||||
|
||||
@@ -880,11 +883,12 @@ batadv_dat_cache_dump_entry(struct sk_bu
|
||||
genl_dump_check_consistent(cb, hdr);
|
||||
|
||||
msecs = jiffies_to_msecs(jiffies - dat_entry->last_update);
|
||||
+ u64_mac = atomic64_read(&dat_entry->mac_addr);
|
||||
+ u64_to_ether_addr(u64_mac, mac);
|
||||
|
||||
if (nla_put_in_addr(msg, BATADV_ATTR_DAT_CACHE_IP4ADDRESS,
|
||||
dat_entry->ip) ||
|
||||
- nla_put(msg, BATADV_ATTR_DAT_CACHE_HWADDRESS, ETH_ALEN,
|
||||
- dat_entry->mac_addr) ||
|
||||
+ nla_put(msg, BATADV_ATTR_DAT_CACHE_HWADDRESS, ETH_ALEN, mac) ||
|
||||
nla_put_u16(msg, BATADV_ATTR_DAT_CACHE_VID, dat_entry->vid) ||
|
||||
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, msecs)) {
|
||||
genlmsg_cancel(msg, hdr);
|
||||
@@ -1151,6 +1155,8 @@ bool batadv_dat_snoop_outgoing_arp_reque
|
||||
struct net_device *mesh_iface = bat_priv->mesh_iface;
|
||||
int hdr_size = 0;
|
||||
unsigned short vid;
|
||||
+ u8 mac[ETH_ALEN];
|
||||
+ u64 u64_mac;
|
||||
|
||||
if (!atomic_read(&bat_priv->distributed_arp_table))
|
||||
goto out;
|
||||
@@ -1178,6 +1184,9 @@ bool batadv_dat_snoop_outgoing_arp_reque
|
||||
|
||||
dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
|
||||
if (dat_entry) {
|
||||
+ u64_mac = atomic64_read(&dat_entry->mac_addr);
|
||||
+ u64_to_ether_addr(u64_mac, mac);
|
||||
+
|
||||
/* If the ARP request is destined for a local client the local
|
||||
* client will answer itself. DAT would only generate a
|
||||
* duplicate packet.
|
||||
@@ -1186,7 +1195,7 @@ bool batadv_dat_snoop_outgoing_arp_reque
|
||||
* additional DAT answer may trigger kernel warnings about
|
||||
* a packet coming from the wrong port.
|
||||
*/
|
||||
- if (batadv_is_my_client(bat_priv, dat_entry->mac_addr, vid)) {
|
||||
+ if (batadv_is_my_client(bat_priv, mac, vid)) {
|
||||
ret = true;
|
||||
goto out;
|
||||
}
|
||||
@@ -1196,18 +1205,16 @@ bool batadv_dat_snoop_outgoing_arp_reque
|
||||
* the backbone gws belonging to our backbone has claimed the
|
||||
* destination.
|
||||
*/
|
||||
- if (!batadv_bla_check_claim(bat_priv,
|
||||
- dat_entry->mac_addr, vid)) {
|
||||
+ if (!batadv_bla_check_claim(bat_priv, mac, vid)) {
|
||||
batadv_dbg(BATADV_DBG_DAT, bat_priv,
|
||||
"Device %pM claimed by another backbone gw. Don't send ARP reply!",
|
||||
- dat_entry->mac_addr);
|
||||
+ mac);
|
||||
ret = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,
|
||||
- dat_entry->mac_addr,
|
||||
- hw_src, vid);
|
||||
+ mac, hw_src, vid);
|
||||
if (!skb_new)
|
||||
goto out;
|
||||
|
||||
@@ -1249,6 +1256,8 @@ bool batadv_dat_snoop_incoming_arp_reque
|
||||
struct batadv_dat_entry *dat_entry = NULL;
|
||||
bool ret = false;
|
||||
unsigned short vid;
|
||||
+ u8 mac[ETH_ALEN];
|
||||
+ u64 u64_mac;
|
||||
int err;
|
||||
|
||||
if (!atomic_read(&bat_priv->distributed_arp_table))
|
||||
@@ -1276,8 +1285,11 @@ bool batadv_dat_snoop_incoming_arp_reque
|
||||
if (!dat_entry)
|
||||
goto out;
|
||||
|
||||
+ u64_mac = atomic64_read(&dat_entry->mac_addr);
|
||||
+ u64_to_ether_addr(u64_mac, mac);
|
||||
+
|
||||
skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,
|
||||
- dat_entry->mac_addr, hw_src, vid);
|
||||
+ mac, hw_src, vid);
|
||||
if (!skb_new)
|
||||
goto out;
|
||||
|
||||
@@ -1368,6 +1380,8 @@ bool batadv_dat_snoop_incoming_arp_reply
|
||||
u8 *hw_src, *hw_dst;
|
||||
bool dropped = false;
|
||||
unsigned short vid;
|
||||
+ u8 mac[ETH_ALEN];
|
||||
+ u64 u64_mac;
|
||||
|
||||
if (!atomic_read(&bat_priv->distributed_arp_table))
|
||||
goto out;
|
||||
@@ -1396,11 +1410,17 @@ bool batadv_dat_snoop_incoming_arp_reply
|
||||
* this frame would lead to doubled receive of an ARP reply.
|
||||
*/
|
||||
dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_src, vid);
|
||||
- if (dat_entry && batadv_compare_eth(hw_src, dat_entry->mac_addr)) {
|
||||
- batadv_dbg(BATADV_DBG_DAT, bat_priv, "Doubled ARP reply removed: ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]; dat_entry: %pM-%pI4\n",
|
||||
- hw_src, &ip_src, hw_dst, &ip_dst,
|
||||
- dat_entry->mac_addr, &dat_entry->ip);
|
||||
- dropped = true;
|
||||
+ if (dat_entry) {
|
||||
+ u64_mac = atomic64_read(&dat_entry->mac_addr);
|
||||
+ u64_to_ether_addr(u64_mac, mac);
|
||||
+
|
||||
+ if (batadv_compare_eth(hw_src, mac)) {
|
||||
+ batadv_dbg(BATADV_DBG_DAT, bat_priv,
|
||||
+ "Doubled ARP reply removed: ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]; dat_entry: %pM-%pI4\n",
|
||||
+ hw_src, &ip_src, hw_dst, &ip_dst,
|
||||
+ mac, &dat_entry->ip);
|
||||
+ dropped = true;
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Update our internal cache with both the IP addresses the node got
|
||||
--- a/net/batman-adv/types.h
|
||||
+++ b/net/batman-adv/types.h
|
||||
@@ -2127,7 +2127,7 @@ struct batadv_dat_entry {
|
||||
__be32 ip;
|
||||
|
||||
/** @mac_addr: the MAC address associated to the stored IPv4 */
|
||||
- u8 mac_addr[ETH_ALEN];
|
||||
+ atomic64_t mac_addr;
|
||||
|
||||
/** @vid: the vlan ID associated to this entry */
|
||||
unsigned short vid;
|
||||
@@ -0,0 +1,48 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Thu, 9 Jul 2026 20:44:24 +0200
|
||||
Subject: batman-adv: fix TX priority extraction for BATADV_FORW_MCAST
|
||||
|
||||
batadv_mcast_forw_mode_by_count() pushs the skb->data for BATADV_FORW_MCAST
|
||||
forwarding via batadv_mcast_forw_mcsend(). But the
|
||||
batadv_skb_set_priority() expects the ethernet header directly before
|
||||
(skb->data + offset). With the moved skb->data, just some random data would
|
||||
be accessed to get the priority data.
|
||||
|
||||
Move the batadv_skb_set_priority() before the decision about the handling
|
||||
multicast packets and potential header modifications.
|
||||
|
||||
Fixes: be9b0169c840 ("batman-adv: mcast: implement multicast packet generation")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: backported, https://git.open-mesh.org/batman-adv.git/commit/?id=b2d7dfd897e1f8005bb610cf14c77238e488bea8
|
||||
|
||||
--- a/net/batman-adv/mesh-interface.c
|
||||
+++ b/net/batman-adv/mesh-interface.c
|
||||
@@ -258,6 +258,8 @@ static netdev_tx_t batadv_interface_tx(s
|
||||
if (batadv_compare_eth(ethhdr->h_dest, ectp_addr))
|
||||
goto dropped;
|
||||
|
||||
+ batadv_skb_set_priority(skb, 0);
|
||||
+
|
||||
gw_mode = atomic_read(&bat_priv->gw.mode);
|
||||
if (is_multicast_ether_addr(ethhdr->h_dest)) {
|
||||
/* if gw mode is off, broadcast every packet */
|
||||
@@ -291,6 +293,9 @@ static netdev_tx_t batadv_interface_tx(s
|
||||
|
||||
send:
|
||||
if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) {
|
||||
+ /* WARNING batadv_mcast_forw_mode might add more headers
|
||||
+ * in front of the skb. and might even reallocate the skb
|
||||
+ */
|
||||
forw_mode = batadv_mcast_forw_mode(bat_priv, skb, vid,
|
||||
&mcast_is_routable);
|
||||
switch (forw_mode) {
|
||||
@@ -308,8 +313,6 @@ send:
|
||||
}
|
||||
}
|
||||
|
||||
- batadv_skb_set_priority(skb, 0);
|
||||
-
|
||||
/* ethernet packet should be broadcasted */
|
||||
if (do_bcast) {
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
@@ -0,0 +1,28 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Thu, 9 Jul 2026 21:17:08 +0200
|
||||
Subject: batman-adv: mcast: ensure unshared skb for multicast packets
|
||||
|
||||
When a packet is transmitted via a batman-adv interface and has already
|
||||
enough room for the header then the nothing will make sure that the skbuff
|
||||
is unshared. But it is now allowed to modify a currently shared skbuff.
|
||||
|
||||
Always make sure that the pskb_expand_head() is not only called for a too
|
||||
small header but also for shared skbuffs.
|
||||
|
||||
Fixes: be9b0169c840 ("batman-adv: mcast: implement multicast packet generation")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=e30382561093d4adefc64bd46d2273c4921543ac
|
||||
|
||||
--- a/net/batman-adv/multicast_forw.c
|
||||
+++ b/net/batman-adv/multicast_forw.c
|
||||
@@ -1100,8 +1100,7 @@ static int batadv_mcast_forw_expand_head
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- if (skb_headroom(skb) < hdr_size &&
|
||||
- pskb_expand_head(skb, hdr_size, 0, GFP_ATOMIC) < 0)
|
||||
+ if (skb_cow(skb, hdr_size) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
@@ -0,0 +1,43 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Thu, 9 Jul 2026 21:26:13 +0200
|
||||
Subject: batman-adv: mcast: linearize skbuff for packet generation
|
||||
|
||||
batadv_mcast_forw_packet() and batadv_mcast_forw_packet() is not only
|
||||
called by the unsharing+linearizing batadv_recv_mcast_packet() handler.
|
||||
When it is called by batadv_mcast_forw_mcsend() then it will be unshared
|
||||
but not linearized. The SKB_LINEAR_ASSERT() can therefore cause a fatal
|
||||
BUG().
|
||||
|
||||
The linearization should happen during the expansion of the head because
|
||||
the call chain because the scrape function can be hit already during the
|
||||
initial batadv_mcast_forw_mode() selection code:
|
||||
|
||||
* batadv_interface_tx
|
||||
* batadv_mcast_forw_mode
|
||||
* batadv_mcast_forw_mode_by_count()
|
||||
* batadv_mcast_forw_push()
|
||||
-> calls batadv_mcast_forw_expand_head() before everything else
|
||||
* batadv_mcast_forw_push_tvlvs()
|
||||
* batadv_mcast_forw_push_dests()
|
||||
* batadv_mcast_forw_push_adjust_padding()
|
||||
* batadv_mcast_forw_scrape()
|
||||
|
||||
Reported-by: Sashiko <sashiko-bot@kernel.org>
|
||||
Fixes: 8ed36122d709 ("batman-adv: mcast: implement multicast packet reception and forwarding")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=426e36bbbc8497bcef8a7ea3fee5f93a563efe16
|
||||
|
||||
--- a/net/batman-adv/multicast_forw.c
|
||||
+++ b/net/batman-adv/multicast_forw.c
|
||||
@@ -1103,6 +1103,10 @@ static int batadv_mcast_forw_expand_head
|
||||
if (skb_cow(skb, hdr_size) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
+ /* batadv_mcast_forw_scrape() + batadv_mcast_forw_packet() require linearized skb */
|
||||
+ if (skb_linearize(skb) < 0)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zhiling Zou <zhilinz@nebusec.ai>
|
||||
Date: Fri, 31 Jul 2026 11:18:49 +0800
|
||||
Subject: batman-adv: fix stale receive device on merged fragments
|
||||
|
||||
Fragment reassembly reuses the skb from the highest-numbered buffered
|
||||
fragment as the merged packet. When that fragment was received on a hard
|
||||
interface which is deleted before the chain completes, the merged skb can
|
||||
re-enter the receive path with a stale skb->dev and skb_iif.
|
||||
|
||||
batadv_batman_skb_recv() passes such merged packets through the normal
|
||||
receive handlers again. DAT and bridge loop avoidance both derive the ARP
|
||||
header length from skb->dev, so they can dereference the freed net_device
|
||||
before the packet reaches the local mesh interface.
|
||||
|
||||
Refresh the receive device metadata from the current receive device before
|
||||
running the packet handlers. This keeps internally reinjected merged
|
||||
fragments consistent with the normal receive path after hard interface
|
||||
teardown.
|
||||
|
||||
Fixes: 9b3eab61754d ("batman-adv: Receive fragmented packets and merge")
|
||||
Reported-by: Vega <vega@nebusec.ai>
|
||||
Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=dc92cfae652a109fca4d0db084328395ce88d38e
|
||||
|
||||
--- a/net/batman-adv/main.c
|
||||
+++ b/net/batman-adv/main.c
|
||||
@@ -436,6 +436,10 @@ int batadv_batman_skb_recv(struct sk_buf
|
||||
if (!skb)
|
||||
goto err_put;
|
||||
|
||||
+ /* Merged fragments re-enter here with reused skb metadata. */
|
||||
+ skb->dev = dev;
|
||||
+ skb->skb_iif = dev->ifindex;
|
||||
+
|
||||
/* packet should hold at least type and version */
|
||||
if (unlikely(!pskb_may_pull(skb, 2)))
|
||||
goto err_free;
|
||||
@@ -0,0 +1,92 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Thu, 30 Jul 2026 10:57:53 +0200
|
||||
Subject: batman-adv: tvlv: handle negative tvlv processing return codes
|
||||
|
||||
batadv_tvlv_containers_process() was implemented with only two return codes
|
||||
from the handlers in mind:
|
||||
|
||||
* NET_RX_SUCCESS (0)
|
||||
* NET_RX_DROP (1)
|
||||
|
||||
The multicast handlers broke this convention and are also returning
|
||||
negative return codes. But the processing code was never updated to
|
||||
correctly aggregate them.
|
||||
|
||||
To handle negative return codes for non-OGM(2) handlers, they are now
|
||||
aggregated to:
|
||||
|
||||
* NET_RX_SUCCESS when no handlers returned a different return code
|
||||
* the last negative return code when at least one handler returned a
|
||||
negative return code
|
||||
* NET_RX_DROP otherwise
|
||||
|
||||
Fixes: 8ed36122d709 ("batman-adv: mcast: implement multicast packet reception and forwarding")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=fb5afe23d039f942f109abed8e4581c4bef5da68
|
||||
|
||||
--- a/net/batman-adv/routing.c
|
||||
+++ b/net/batman-adv/routing.c
|
||||
@@ -1334,7 +1334,9 @@ out:
|
||||
* contents of its TVLV forwards it and/or decapsulates it to hand it to the
|
||||
* mesh interface.
|
||||
*
|
||||
- * Return: NET_RX_DROP if the skb is not consumed, NET_RX_SUCCESS otherwise.
|
||||
+ * Return: NET_RX_SUCCESS if the skb was locally received, NET_RX_DROP otherwise
|
||||
+ * or a negative errno code when the multicast tracker TVLV could not be
|
||||
+ * processed
|
||||
*/
|
||||
int batadv_recv_mcast_packet(struct sk_buff *skb,
|
||||
struct batadv_hard_iface *recv_if)
|
||||
--- a/net/batman-adv/tvlv.c
|
||||
+++ b/net/batman-adv/tvlv.c
|
||||
@@ -370,8 +370,9 @@ end:
|
||||
* @tvlv_value: tvlv content
|
||||
* @tvlv_value_len: tvlv content length
|
||||
*
|
||||
- * Return: success if the handler was not found or the return value of the
|
||||
- * handler callback.
|
||||
+ * Return: NET_RX_SUCCESS if the handler was not found or the return value of
|
||||
+ * the handler callback. The latter is NET_RX_SUCCESS or NET_RX_DROP for the
|
||||
+ * unicast handler and additionally a negative errno code for the mcast handler.
|
||||
*/
|
||||
static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv,
|
||||
struct batadv_tvlv_handler *tvlv_handler,
|
||||
@@ -481,8 +482,9 @@ static bool batadv_tvlv_containers_conta
|
||||
* @tvlv_value: tvlv content
|
||||
* @tvlv_value_len: tvlv content length
|
||||
*
|
||||
- * Return: success when processing an OGM or the return value of all called
|
||||
- * handler callbacks.
|
||||
+ * Return: NET_RX_SUCCESS when processing an OGM or the combined return value of
|
||||
+ * all called handler callbacks. The latter is NET_RX_SUCCESS, NET_RX_DROP or,
|
||||
+ * for BATADV_MCAST packets, a negative errno code.
|
||||
*/
|
||||
int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
|
||||
u8 packet_type,
|
||||
@@ -497,6 +499,7 @@ int batadv_tvlv_containers_process(struc
|
||||
u16 tvlv_value_cont_len;
|
||||
u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND;
|
||||
int ret = NET_RX_SUCCESS;
|
||||
+ int res;
|
||||
|
||||
while (tvlv_value_len >= sizeof(*tvlv_hdr)) {
|
||||
tvlv_hdr = tvlv_value;
|
||||
@@ -517,10 +520,13 @@ int batadv_tvlv_containers_process(struc
|
||||
tvlv_hdr->type,
|
||||
tvlv_hdr->version);
|
||||
|
||||
- ret |= batadv_tvlv_call_handler(bat_priv, tvlv_handler,
|
||||
- packet_type, orig_node, skb,
|
||||
- tvlv_value,
|
||||
- tvlv_value_cont_len);
|
||||
+ res = batadv_tvlv_call_handler(bat_priv, tvlv_handler,
|
||||
+ packet_type, orig_node, skb,
|
||||
+ tvlv_value,
|
||||
+ tvlv_value_cont_len);
|
||||
+ if (ret == NET_RX_SUCCESS || res < 0)
|
||||
+ ret = res;
|
||||
+
|
||||
batadv_tvlv_handler_put(tvlv_handler);
|
||||
tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len;
|
||||
tvlv_value_len -= tvlv_value_cont_len;
|
||||
@@ -0,0 +1,59 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sven Eckelmann <sven@narfation.org>
|
||||
Date: Wed, 22 Jul 2026 12:08:09 +0200
|
||||
Subject: batman-adv: bla: fix freeing of claims on meshif deletion
|
||||
|
||||
When the mesh interface is getting deleted, then
|
||||
batadv_bla_del_backbone_claims() (via batadv_bla_purge_backbone_gw()) could
|
||||
make sure that all claims gets removed. But this function is only executed
|
||||
when bat_priv->bla.claim_hash is not NULL. And since batadv_bla_free() is
|
||||
always setting it to NULL before it is (indirectly) called, it was never
|
||||
actually executed.
|
||||
|
||||
But the batadv_bla_purge_claims() -> batadv_handle_unclaim() is at the
|
||||
moment too fragile because the BLA code is not handling the rehashing in
|
||||
batadv_bla_update_orig_address(). The stored backbone address doesn't have
|
||||
to be the one actually used for the hash bucket selection during the
|
||||
initial adding of the backbone. The batadv_handle_unclaim() can therefore
|
||||
fail to find the respective backbone for the unclaim and then stop the
|
||||
deletion.
|
||||
|
||||
But the actual backbone_gw object is not needed for the unclaim because all
|
||||
relevant information is always provided by the caller. And the check for
|
||||
the existence of the backbone_gw doesn't provide any additional security
|
||||
check for the deletion of a claim.
|
||||
|
||||
Fixes: a9ce0dc43e2c ("batman-adv: add basic bridge loop avoidance code")
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/?id=e48f421ba209b24e51f25126ca06cfa50de1139e
|
||||
|
||||
--- a/net/batman-adv/bridge_loop_avoidance.c
|
||||
+++ b/net/batman-adv/bridge_loop_avoidance.c
|
||||
@@ -951,26 +951,18 @@ static bool batadv_handle_unclaim(struct
|
||||
const u8 *backbone_addr, const u8 *claim_addr,
|
||||
unsigned short vid)
|
||||
{
|
||||
- struct batadv_bla_backbone_gw *backbone_gw;
|
||||
-
|
||||
/* unclaim in any case if it is our own */
|
||||
if (primary_if && batadv_compare_eth(backbone_addr,
|
||||
primary_if->net_dev->dev_addr))
|
||||
batadv_bla_send_claim(bat_priv, claim_addr, vid,
|
||||
BATADV_CLAIM_TYPE_UNCLAIM);
|
||||
|
||||
- backbone_gw = batadv_backbone_hash_find(bat_priv, backbone_addr, vid);
|
||||
-
|
||||
- if (!backbone_gw)
|
||||
- return true;
|
||||
-
|
||||
/* this must be an UNCLAIM frame */
|
||||
batadv_dbg(BATADV_DBG_BLA, bat_priv,
|
||||
"%s(): UNCLAIM %pM on vid %d (sent by %pM)...\n", __func__,
|
||||
- claim_addr, batadv_print_vid(vid), backbone_gw->orig);
|
||||
+ claim_addr, batadv_print_vid(vid), backbone_addr);
|
||||
|
||||
batadv_bla_del_claim(bat_priv, claim_addr, vid);
|
||||
- batadv_backbone_gw_put(backbone_gw);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Kyle Zeng <kylebot@openai.com>
|
||||
Date: Mon, 17 Aug 2026 08:49:54 +0000
|
||||
Subject: batman-adv: reject unrepresentable multicast TVLV offsets
|
||||
|
||||
The network and transport header fields in struct sk_buff are 16-bit
|
||||
offsets from skb->head, and U16_MAX is reserved as the unset transport
|
||||
header value. batadv_tvlv_call_handler() sets both fields from a received
|
||||
multicast TVLV without checking whether the TVLV end is representable.
|
||||
|
||||
If the end offset exceeds the field's range, skb_set_transport_header()
|
||||
truncates it so that the transport header precedes the network header.
|
||||
The negative difference is then returned by skb_network_header_len() as
|
||||
a large u32. batadv_mcast_forw_packet() consequently accepts an oversized
|
||||
multicast tracker and accesses memory beyond the skb data.
|
||||
|
||||
Add skb_set_transport_header_careful(), an offset-aware counterpart to
|
||||
skb_reset_transport_header_careful(), which validates the final
|
||||
head-relative offset before assigning it. Use the new helper in
|
||||
batadv_tvlv_call_handler() and reject unrepresentable TVLVs before
|
||||
setting the network header.
|
||||
|
||||
Fixes: 8ed36122d709 ("batman-adv: mcast: implement multicast packet reception and forwarding")
|
||||
Suggested-by: Sven Eckelmann <sven@narfation.org>
|
||||
Assisted-by: Codex:gpt-5.6-sol Codex:gpt-5.5-cyber
|
||||
Signed-off-by: Kyle Zeng <kylebot@openai.com>
|
||||
Co-developed-by: David Lee <david.lee@trailofbits.com>
|
||||
Signed-off-by: David Lee <david.lee@trailofbits.com>
|
||||
Signed-off-by: Sven Eckelmann <sven@narfation.org>
|
||||
Origin: backported, https://git.open-mesh.org/batman-adv.git/commit/?id=1a89187fb01aefde94abf5ec65ec594b900257b6
|
||||
|
||||
--- a/net/batman-adv/tvlv.c
|
||||
+++ b/net/batman-adv/tvlv.c
|
||||
@@ -421,8 +421,11 @@ static int batadv_tvlv_call_handler(stru
|
||||
return NET_RX_SUCCESS;
|
||||
|
||||
tvlv_offset = (unsigned char *)tvlv_value - skb->data;
|
||||
+ if (!skb_set_transport_header_careful(skb,
|
||||
+ tvlv_offset + tvlv_value_len))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
skb_set_network_header(skb, tvlv_offset);
|
||||
- skb_set_transport_header(skb, tvlv_offset + tvlv_value_len);
|
||||
|
||||
return tvlv_handler->mcast_handler(bat_priv, skb);
|
||||
}
|
||||
@@ -22,6 +22,29 @@
|
||||
|
||||
#endif /* LINUX_VERSION_IS_LESS(6, 16, 0) */
|
||||
|
||||
#if LINUX_VERSION_IS_LESS(7, 3, 0)
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
static inline bool __must_check
|
||||
batadv_skb_set_transport_header_careful(struct sk_buff *skb, const int offset)
|
||||
{
|
||||
long thoff = skb->data - skb->head + offset;
|
||||
|
||||
if (unlikely(thoff != (typeof(skb->transport_header))thoff))
|
||||
return false;
|
||||
|
||||
if (unlikely(thoff == (typeof(skb->transport_header))~0U))
|
||||
return false;
|
||||
|
||||
skb->transport_header = thoff;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define skb_set_transport_header_careful batadv_skb_set_transport_header_careful
|
||||
|
||||
#endif /* LINUX_VERSION_IS_LESS(7, 3, 0) */
|
||||
|
||||
/* <DECLARE_EWMA> */
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
Reference in new issue
Block a user