diff --git a/batman-adv/Makefile b/batman-adv/Makefile index af28a3c..31d7d73 100644 --- a/batman-adv/Makefile +++ b/batman-adv/Makefile @@ -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) diff --git a/batman-adv/patches/0075-batman-adv-ensure-minimal-ethernet-header-on-TX.patch b/batman-adv/patches/0075-batman-adv-ensure-minimal-ethernet-header-on-TX.patch new file mode 100644 index 0000000..feb26e6 --- /dev/null +++ b/batman-adv/patches/0075-batman-adv-ensure-minimal-ethernet-header-on-TX.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +Signed-off-by: Sven Eckelmann +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)); + diff --git a/batman-adv/patches/0076-batman-adv-fix-VLAN-priority-offset.patch b/batman-adv/patches/0076-batman-adv-fix-VLAN-priority-offset.patch new file mode 100644 index 0000000..d41c031 --- /dev/null +++ b/batman-adv/patches/0076-batman-adv-fix-VLAN-priority-offset.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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; diff --git a/batman-adv/patches/0077-batman-adv-tt-avoid-request-storms-during-pending-re.patch b/batman-adv/patches/0077-batman-adv-tt-avoid-request-storms-during-pending-re.patch new file mode 100644 index 0000000..78527a8 --- /dev/null +++ b/batman-adv/patches/0077-batman-adv-tt-avoid-request-storms-during-pending-re.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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); diff --git a/batman-adv/patches/0078-batman-adv-frag-fix-primary_if-leak-on-failed-linear.patch b/batman-adv/patches/0078-batman-adv-frag-fix-primary_if-leak-on-failed-linear.patch new file mode 100644 index 0000000..b9c39ce --- /dev/null +++ b/batman-adv/patches/0078-batman-adv-frag-fix-primary_if-leak-on-failed-linear.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +Fixes: d467720acaf1 ("batman-adv: Don't skb_split skbuffs with frag_list") +Signed-off-by: Sven Eckelmann +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 */ diff --git a/batman-adv/patches/0079-batman-adv-frag-free-unfragmentable-packet.patch b/batman-adv/patches/0079-batman-adv-frag-free-unfragmentable-packet.patch new file mode 100644 index 0000000..77c1123 --- /dev/null +++ b/batman-adv/patches/0079-batman-adv-frag-free-unfragmentable-packet.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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; diff --git a/batman-adv/patches/0080-batman-adv-mcast-avoid-OOB-read-of-num_dests-header.patch b/batman-adv/patches/0080-batman-adv-mcast-avoid-OOB-read-of-num_dests-header.patch new file mode 100644 index 0000000..b2c5845 --- /dev/null +++ b/batman-adv/patches/0080-batman-adv-mcast-avoid-OOB-read-of-num_dests-header.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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); diff --git a/batman-adv/patches/0081-batman-adv-tt-prevent-TVLV-OOB-check-overflow.patch b/batman-adv/patches/0081-batman-adv-tt-prevent-TVLV-OOB-check-overflow.patch new file mode 100644 index 0000000..fac4419 --- /dev/null +++ b/batman-adv/patches/0081-batman-adv-tt-prevent-TVLV-OOB-check-overflow.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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; + diff --git a/batman-adv/patches/0082-batman-adv-clean-untagged-VLAN-on-netdev-registratio.patch b/batman-adv/patches/0082-batman-adv-clean-untagged-VLAN-on-netdev-registratio.patch new file mode 100644 index 0000000..02cabf7 --- /dev/null +++ b/batman-adv/patches/0082-batman-adv-clean-untagged-VLAN-on-netdev-registratio.patch @@ -0,0 +1,92 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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); diff --git a/batman-adv/patches/0083-batman-adv-dat-fix-tie-break-for-candidate-selection.patch b/batman-adv/patches/0083-batman-adv-dat-fix-tie-break-for-candidate-selection.patch new file mode 100644 index 0000000..3bcd136 --- /dev/null +++ b/batman-adv/patches/0083-batman-adv-dat-fix-tie-break-for-candidate-selection.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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; diff --git a/batman-adv/patches/0084-batman-adv-bla-avoid-CRC-corruption-due-to-parallel-.patch b/batman-adv/patches/0084-batman-adv-bla-avoid-CRC-corruption-due-to-parallel-.patch new file mode 100644 index 0000000..18789f4 --- /dev/null +++ b/batman-adv/patches/0084-batman-adv-bla-avoid-CRC-corruption-due-to-parallel-.patch @@ -0,0 +1,148 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +Fixes: a9ce0dc43e2c ("batman-adv: add basic bridge loop avoidance code") +Signed-off-by: Sven Eckelmann +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); + } + diff --git a/batman-adv/patches/0085-batman-adv-bla-prevent-CRC-corruptions-after-claim-f.patch b/batman-adv/patches/0085-batman-adv-bla-prevent-CRC-corruptions-after-claim-f.patch new file mode 100644 index 0000000..00c54f6 --- /dev/null +++ b/batman-adv/patches/0085-batman-adv-bla-prevent-CRC-corruptions-after-claim-f.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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); + } + + /** diff --git a/batman-adv/patches/0086-batman-adv-dat-avoid-unaligned-fault-in-IP-extractio.patch b/batman-adv/patches/0086-batman-adv-dat-avoid-unaligned-fault-in-IP-extractio.patch new file mode 100644 index 0000000..7226c02 --- /dev/null +++ b/batman-adv/patches/0086-batman-adv-dat-avoid-unaligned-fault-in-IP-extractio.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +Fixes: 0591c25abca9 ("batman-adv: Distributed ARP Table - add ARP parsing functions") +Signed-off-by: Sven Eckelmann +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); + } + + /** diff --git a/batman-adv/patches/0087-batman-adv-dat-atomically-update-mac-addresses.patch b/batman-adv/patches/0087-batman-adv-dat-atomically-update-mac-addresses.patch new file mode 100644 index 0000000..029f399 --- /dev/null +++ b/batman-adv/patches/0087-batman-adv-dat-atomically-update-mac-addresses.patch @@ -0,0 +1,202 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +Fixes: f6badf9eb582 ("batman-adv: Distributed ARP Table - implement local storage") +Signed-off-by: Sven Eckelmann +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; diff --git a/batman-adv/patches/0088-batman-adv-fix-TX-priority-extraction-for-BATADV_FOR.patch b/batman-adv/patches/0088-batman-adv-fix-TX-priority-extraction-for-BATADV_FOR.patch new file mode 100644 index 0000000..806fe1a --- /dev/null +++ b/batman-adv/patches/0088-batman-adv-fix-TX-priority-extraction-for-BATADV_FOR.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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); diff --git a/batman-adv/patches/0089-batman-adv-mcast-ensure-unshared-skb-for-multicast-p.patch b/batman-adv/patches/0089-batman-adv-mcast-ensure-unshared-skb-for-multicast-p.patch new file mode 100644 index 0000000..2d9c6fe --- /dev/null +++ b/batman-adv/patches/0089-batman-adv-mcast-ensure-unshared-skb-for-multicast-p.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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; diff --git a/batman-adv/patches/0090-batman-adv-mcast-linearize-skbuff-for-packet-generat.patch b/batman-adv/patches/0090-batman-adv-mcast-linearize-skbuff-for-packet-generat.patch new file mode 100644 index 0000000..9f61c7c --- /dev/null +++ b/batman-adv/patches/0090-batman-adv-mcast-linearize-skbuff-for-packet-generat.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +Fixes: 8ed36122d709 ("batman-adv: mcast: implement multicast packet reception and forwarding") +Signed-off-by: Sven Eckelmann +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; + } + diff --git a/batman-adv/patches/0091-batman-adv-fix-stale-receive-device-on-merged-fragme.patch b/batman-adv/patches/0091-batman-adv-fix-stale-receive-device-on-merged-fragme.patch new file mode 100644 index 0000000..0ee6813 --- /dev/null +++ b/batman-adv/patches/0091-batman-adv-fix-stale-receive-device-on-merged-fragme.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhiling Zou +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 +Signed-off-by: Zhiling Zou +Signed-off-by: Sven Eckelmann +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; diff --git a/batman-adv/patches/0092-batman-adv-tvlv-handle-negative-tvlv-processing-retu.patch b/batman-adv/patches/0092-batman-adv-tvlv-handle-negative-tvlv-processing-retu.patch new file mode 100644 index 0000000..5a86580 --- /dev/null +++ b/batman-adv/patches/0092-batman-adv-tvlv-handle-negative-tvlv-processing-retu.patch @@ -0,0 +1,92 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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; diff --git a/batman-adv/patches/0093-batman-adv-bla-fix-freeing-of-claims-on-meshif-delet.patch b/batman-adv/patches/0093-batman-adv-bla-fix-freeing-of-claims-on-meshif-delet.patch new file mode 100644 index 0000000..972e326 --- /dev/null +++ b/batman-adv/patches/0093-batman-adv-bla-fix-freeing-of-claims-on-meshif-delet.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sven Eckelmann +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 +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; + } + diff --git a/batman-adv/patches/0094-batman-adv-reject-unrepresentable-multicast-TVLV-off.patch b/batman-adv/patches/0094-batman-adv-reject-unrepresentable-multicast-TVLV-off.patch new file mode 100644 index 0000000..5cd0818 --- /dev/null +++ b/batman-adv/patches/0094-batman-adv-reject-unrepresentable-multicast-TVLV-off.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kyle Zeng +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 +Assisted-by: Codex:gpt-5.6-sol Codex:gpt-5.5-cyber +Signed-off-by: Kyle Zeng +Co-developed-by: David Lee +Signed-off-by: David Lee +Signed-off-by: Sven Eckelmann +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); + } diff --git a/batman-adv/src/compat-hacks.h b/batman-adv/src/compat-hacks.h index 57911f4..47bf17e 100644 --- a/batman-adv/src/compat-hacks.h +++ b/batman-adv/src/compat-hacks.h @@ -22,6 +22,29 @@ #endif /* LINUX_VERSION_IS_LESS(6, 16, 0) */ +#if LINUX_VERSION_IS_LESS(7, 3, 0) + +#include + +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) */ + /* */ #include