From: Sven Eckelmann Date: Thu, 28 Mar 2019 19:39:10 +0000 (+0100) Subject: batman-adv: Merge bugfixes from 2019.1 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=refs%2Fpull%2F462%2Fhead;p=feed%2Frouting.git batman-adv: Merge bugfixes from 2019.1 * fix uninit-value in batadv_interface_tx() * Reduce claim hash refcnt only for removed entry * Reduce tt_local hash refcnt only for removed entry * Reduce tt_global hash refcnt only for removed entry Signed-off-by: Sven Eckelmann --- diff --git a/batman-adv/Makefile b/batman-adv/Makefile index 74ef4b8..42f1300 100644 --- a/batman-adv/Makefile +++ b/batman-adv/Makefile @@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=batman-adv PKG_VERSION:=2018.1 -PKG_RELEASE:=5 +PKG_RELEASE:=6 PKG_HASH:=b866b28dbbe5c9238abbdf5abbc30fc526dea56898ce4c1bd76d5c017843048b PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz diff --git a/batman-adv/patches/0024-batman-adv-fix-uninit-value-in-batadv_interface_tx.patch b/batman-adv/patches/0024-batman-adv-fix-uninit-value-in-batadv_interface_tx.patch new file mode 100644 index 0000000..dd2edad --- /dev/null +++ b/batman-adv/patches/0024-batman-adv-fix-uninit-value-in-batadv_interface_tx.patch @@ -0,0 +1,95 @@ +From: Eric Dumazet +Date: Mon, 11 Feb 2019 14:41:22 -0800 +Subject: batman-adv: fix uninit-value in batadv_interface_tx() + +KMSAN reported batadv_interface_tx() was possibly using a +garbage value [1] + +batadv_get_vid() does have a pskb_may_pull() call +but batadv_interface_tx() does not actually make sure +this did not fail. + +[1] +BUG: KMSAN: uninit-value in batadv_interface_tx+0x908/0x1e40 net/batman-adv/soft-interface.c:231 +CPU: 0 PID: 10006 Comm: syz-executor469 Not tainted 4.20.0-rc7+ #5 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 +Call Trace: + __dump_stack lib/dump_stack.c:77 [inline] + dump_stack+0x173/0x1d0 lib/dump_stack.c:113 + kmsan_report+0x12e/0x2a0 mm/kmsan/kmsan.c:613 + __msan_warning+0x82/0xf0 mm/kmsan/kmsan_instr.c:313 + batadv_interface_tx+0x908/0x1e40 net/batman-adv/soft-interface.c:231 + __netdev_start_xmit include/linux/netdevice.h:4356 [inline] + netdev_start_xmit include/linux/netdevice.h:4365 [inline] + xmit_one net/core/dev.c:3257 [inline] + dev_hard_start_xmit+0x607/0xc40 net/core/dev.c:3273 + __dev_queue_xmit+0x2e42/0x3bc0 net/core/dev.c:3843 + dev_queue_xmit+0x4b/0x60 net/core/dev.c:3876 + packet_snd net/packet/af_packet.c:2928 [inline] + packet_sendmsg+0x8306/0x8f30 net/packet/af_packet.c:2953 + sock_sendmsg_nosec net/socket.c:621 [inline] + sock_sendmsg net/socket.c:631 [inline] + __sys_sendto+0x8c4/0xac0 net/socket.c:1788 + __do_sys_sendto net/socket.c:1800 [inline] + __se_sys_sendto+0x107/0x130 net/socket.c:1796 + __x64_sys_sendto+0x6e/0x90 net/socket.c:1796 + do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291 + entry_SYSCALL_64_after_hwframe+0x63/0xe7 +RIP: 0033:0x441889 +Code: 18 89 d0 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 bb 10 fc ff c3 66 2e 0f 1f 84 00 00 00 00 +RSP: 002b:00007ffdda6fd468 EFLAGS: 00000216 ORIG_RAX: 000000000000002c +RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 0000000000441889 +RDX: 000000000000000e RSI: 00000000200000c0 RDI: 0000000000000003 +RBP: 0000000000000003 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000216 R12: 00007ffdda6fd4c0 +R13: 00007ffdda6fd4b0 R14: 0000000000000000 R15: 0000000000000000 + +Uninit was created at: + kmsan_save_stack_with_flags mm/kmsan/kmsan.c:204 [inline] + kmsan_internal_poison_shadow+0x92/0x150 mm/kmsan/kmsan.c:158 + kmsan_kmalloc+0xa6/0x130 mm/kmsan/kmsan_hooks.c:176 + kmsan_slab_alloc+0xe/0x10 mm/kmsan/kmsan_hooks.c:185 + slab_post_alloc_hook mm/slab.h:446 [inline] + slab_alloc_node mm/slub.c:2759 [inline] + __kmalloc_node_track_caller+0xe18/0x1030 mm/slub.c:4383 + __kmalloc_reserve net/core/skbuff.c:137 [inline] + __alloc_skb+0x309/0xa20 net/core/skbuff.c:205 + alloc_skb include/linux/skbuff.h:998 [inline] + alloc_skb_with_frags+0x1c7/0xac0 net/core/skbuff.c:5220 + sock_alloc_send_pskb+0xafd/0x10e0 net/core/sock.c:2083 + packet_alloc_skb net/packet/af_packet.c:2781 [inline] + packet_snd net/packet/af_packet.c:2872 [inline] + packet_sendmsg+0x661a/0x8f30 net/packet/af_packet.c:2953 + sock_sendmsg_nosec net/socket.c:621 [inline] + sock_sendmsg net/socket.c:631 [inline] + __sys_sendto+0x8c4/0xac0 net/socket.c:1788 + __do_sys_sendto net/socket.c:1800 [inline] + __se_sys_sendto+0x107/0x130 net/socket.c:1796 + __x64_sys_sendto+0x6e/0x90 net/socket.c:1796 + do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291 + entry_SYSCALL_64_after_hwframe+0x63/0xe7 + +Fixes: 48628bb9419f ("batman-adv: softif bridge loop avoidance") +Signed-off-by: Eric Dumazet +Reported-by: syzbot +Cc: Marek Lindner +Cc: Simon Wunderlich +Cc: Antonio Quartulli +Signed-off-by: David S. Miller +Signed-off-by: Sven Eckelmann + +Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/35482922b38bb5f5b03b0e92bc58cec2b7c77cdf + +diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c +index d3f540ba2a1388a8aa693a539d01d6a1cad95b44..97e28907a0acbb3d64d8ceebf7b1df13dc396300 100644 +--- a/net/batman-adv/soft-interface.c ++++ b/net/batman-adv/soft-interface.c +@@ -227,6 +227,8 @@ static int batadv_interface_tx(struct sk_buff *skb, + + switch (ntohs(ethhdr->h_proto)) { + case ETH_P_8021Q: ++ if (!pskb_may_pull(skb, sizeof(*vhdr))) ++ goto dropped; + vhdr = vlan_eth_hdr(skb); + + /* drop batman-in-batman packets to prevent loops */ diff --git a/batman-adv/patches/0025-batman-adv-Reduce-claim-hash-refcnt-only-for-removed.patch b/batman-adv/patches/0025-batman-adv-Reduce-claim-hash-refcnt-only-for-removed.patch new file mode 100644 index 0000000..7a2f999 --- /dev/null +++ b/batman-adv/patches/0025-batman-adv-Reduce-claim-hash-refcnt-only-for-removed.patch @@ -0,0 +1,65 @@ +From: Sven Eckelmann +Date: Sat, 23 Feb 2019 15:09:04 +0100 +Subject: batman-adv: Reduce claim hash refcnt only for removed entry + +The batadv_hash_remove is a function which searches the hashtable for an +entry using a needle, a hashtable bucket selection function and a compare +function. It will lock the bucket list and delete an entry when the compare +function matches it with the needle. It returns the pointer to the +hlist_node which matches or NULL when no entry matches the needle. + +The batadv_bla_del_claim is not itself protected in anyway to avoid that +any other function is modifying the hashtable between the search for the +entry and the call to batadv_hash_remove. It can therefore happen that the +entry either doesn't exist anymore or an entry was deleted which is not the +same object as the needle. In such an situation, the reference counter (for +the reference stored in the hashtable) must not be reduced for the needle. +Instead the reference counter of the actually removed entry has to be +reduced. + +Otherwise the reference counter will underflow and the object might be +freed before all its references were dropped. The kref helpers reported +this problem as: + + refcount_t: underflow; use-after-free. + +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/3a7af70ae7c4209324dbb08b91e013c17108bdd6 + +diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c +index 58c093caf49e804c1e11426959d70e79f1729d41..0842080a71f4ac89b3fbebc4b95c6c27d1cc4254 100644 +--- a/net/batman-adv/bridge_loop_avoidance.c ++++ b/net/batman-adv/bridge_loop_avoidance.c +@@ -803,6 +803,8 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv, + const u8 *mac, const unsigned short vid) + { + struct batadv_bla_claim search_claim, *claim; ++ struct batadv_bla_claim *claim_removed_entry; ++ struct hlist_node *claim_removed_node; + + ether_addr_copy(search_claim.addr, mac); + search_claim.vid = vid; +@@ -813,10 +815,18 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv, + batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): %pM, vid %d\n", __func__, + mac, batadv_print_vid(vid)); + +- batadv_hash_remove(bat_priv->bla.claim_hash, batadv_compare_claim, +- batadv_choose_claim, claim); +- batadv_claim_put(claim); /* reference from the hash is gone */ ++ claim_removed_node = batadv_hash_remove(bat_priv->bla.claim_hash, ++ batadv_compare_claim, ++ batadv_choose_claim, claim); ++ if (!claim_removed_node) ++ goto free_claim; + ++ /* reference from the hash is gone */ ++ claim_removed_entry = hlist_entry(claim_removed_node, ++ struct batadv_bla_claim, hash_entry); ++ batadv_claim_put(claim_removed_entry); ++ ++free_claim: + /* don't need the reference from hash_find() anymore */ + batadv_claim_put(claim); + } diff --git a/batman-adv/patches/0026-batman-adv-Reduce-tt_local-hash-refcnt-only-for-remo.patch b/batman-adv/patches/0026-batman-adv-Reduce-tt_local-hash-refcnt-only-for-remo.patch new file mode 100644 index 0000000..a6ffb25 --- /dev/null +++ b/batman-adv/patches/0026-batman-adv-Reduce-tt_local-hash-refcnt-only-for-remo.patch @@ -0,0 +1,69 @@ +From: Sven Eckelmann +Date: Sat, 23 Feb 2019 15:09:05 +0100 +Subject: batman-adv: Reduce tt_local hash refcnt only for removed entry + +The batadv_hash_remove is a function which searches the hashtable for an +entry using a needle, a hashtable bucket selection function and a compare +function. It will lock the bucket list and delete an entry when the compare +function matches it with the needle. It returns the pointer to the +hlist_node which matches or NULL when no entry matches the needle. + +The batadv_tt_local_remove is not itself protected in anyway to avoid that +any other function is modifying the hashtable between the search for the +entry and the call to batadv_hash_remove. It can therefore happen that the +entry either doesn't exist anymore or an entry was deleted which is not the +same object as the needle. In such an situation, the reference counter (for +the reference stored in the hashtable) must not be reduced for the needle. +Instead the reference counter of the actually removed entry has to be +reduced. + +Otherwise the reference counter will underflow and the object might be +freed before all its references were dropped. The kref helpers reported +this problem as: + + refcount_t: underflow; use-after-free. + +Fixes: af912d77181f ("batman-adv: protect tt_local_entry from concurrent delete events") +Signed-off-by: Sven Eckelmann + +Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/0c86a0511e97de502276900c5d6f22b09e042d21 + +diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c +index 7502cb54c152d06d78c88d9f8fb841cada9f3b5d..d2ecfdbdc64956b238f0554b4c354df9a9e9f26a 100644 +--- a/net/batman-adv/translation-table.c ++++ b/net/batman-adv/translation-table.c +@@ -1332,9 +1332,10 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, + unsigned short vid, const char *message, + bool roaming) + { ++ struct batadv_tt_local_entry *tt_removed_entry; + struct batadv_tt_local_entry *tt_local_entry; + u16 flags, curr_flags = BATADV_NO_FLAGS; +- void *tt_entry_exists; ++ struct hlist_node *tt_removed_node; + + tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); + if (!tt_local_entry) +@@ -1363,15 +1364,18 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, + */ + batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); + +- tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash, ++ tt_removed_node = batadv_hash_remove(bat_priv->tt.local_hash, + batadv_compare_tt, + batadv_choose_tt, + &tt_local_entry->common); +- if (!tt_entry_exists) ++ if (!tt_removed_node) + goto out; + +- /* extra call to free the local tt entry */ +- batadv_tt_local_entry_put(tt_local_entry); ++ /* drop reference of remove hash entry */ ++ tt_removed_entry = hlist_entry(tt_removed_node, ++ struct batadv_tt_local_entry, ++ common.hash_entry); ++ batadv_tt_local_entry_put(tt_removed_entry); + + out: + if (tt_local_entry) diff --git a/batman-adv/patches/0027-batman-adv-Reduce-tt_global-hash-refcnt-only-for-rem.patch b/batman-adv/patches/0027-batman-adv-Reduce-tt_global-hash-refcnt-only-for-rem.patch new file mode 100644 index 0000000..cd08563 --- /dev/null +++ b/batman-adv/patches/0027-batman-adv-Reduce-tt_global-hash-refcnt-only-for-rem.patch @@ -0,0 +1,66 @@ +From: Sven Eckelmann +Date: Sat, 23 Feb 2019 15:09:06 +0100 +Subject: batman-adv: Reduce tt_global hash refcnt only for removed entry + +The batadv_hash_remove is a function which searches the hashtable for an +entry using a needle, a hashtable bucket selection function and a compare +function. It will lock the bucket list and delete an entry when the compare +function matches it with the needle. It returns the pointer to the +hlist_node which matches or NULL when no entry matches the needle. + +The batadv_tt_global_free is not itself protected in anyway to avoid that +any other function is modifying the hashtable between the search for the +entry and the call to batadv_hash_remove. It can therefore happen that the +entry either doesn't exist anymore or an entry was deleted which is not the +same object as the needle. In such an situation, the reference counter (for +the reference stored in the hashtable) must not be reduced for the needle. +Instead the reference counter of the actually removed entry has to be +reduced. + +Otherwise the reference counter will underflow and the object might be +freed before all its references were dropped. The kref helpers reported +this problem as: + + refcount_t: underflow; use-after-free. + +Fixes: 7bad46397eff ("batman-adv: protect the local and the global trans-tables with rcu") +Reported-by: Martin Weinelt +Signed-off-by: Sven Eckelmann +Acked-by: Antonio Quartulli + +Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/bd6df24da0063fe50828c287d05bdc1876f4f6cc + +diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c +index d2ecfdbdc64956b238f0554b4c354df9a9e9f26a..554fd886e652c7c206ff43a5627d342ccbcc2123 100644 +--- a/net/batman-adv/translation-table.c ++++ b/net/batman-adv/translation-table.c +@@ -616,14 +616,26 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv, + struct batadv_tt_global_entry *tt_global, + const char *message) + { ++ struct batadv_tt_global_entry *tt_removed_entry; ++ struct hlist_node *tt_removed_node; ++ + batadv_dbg(BATADV_DBG_TT, bat_priv, + "Deleting global tt entry %pM (vid: %d): %s\n", + tt_global->common.addr, + batadv_print_vid(tt_global->common.vid), message); + +- batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, +- batadv_choose_tt, &tt_global->common); +- batadv_tt_global_entry_put(tt_global); ++ tt_removed_node = batadv_hash_remove(bat_priv->tt.global_hash, ++ batadv_compare_tt, ++ batadv_choose_tt, ++ &tt_global->common); ++ if (!tt_removed_node) ++ return; ++ ++ /* drop reference of remove hash entry */ ++ tt_removed_entry = hlist_entry(tt_removed_node, ++ struct batadv_tt_global_entry, ++ common.hash_entry); ++ batadv_tt_global_entry_put(tt_removed_entry); + } + + /**