Merge pull request #538 from ecsv/batadv-for-17.01
[feed/routing.git] / batman-adv / patches / 0071-batman-adv-Avoid-free-alloc-race-when-handling-OGM-b.patch
diff --git a/batman-adv/patches/0071-batman-adv-Avoid-free-alloc-race-when-handling-OGM-b.patch b/batman-adv/patches/0071-batman-adv-Avoid-free-alloc-race-when-handling-OGM-b.patch
new file mode 100644 (file)
index 0000000..06ecbe9
--- /dev/null
@@ -0,0 +1,134 @@
+From: Sven Eckelmann <sven@narfation.org>
+Date: Thu, 3 Oct 2019 17:02:01 +0200
+Subject: batman-adv: Avoid free/alloc race when handling OGM buffer
+
+Each slave interface of an B.A.T.M.A.N. IV virtual interface has an OGM
+packet buffer which is initialized using data from the RTNL lock protected
+netdevice notifier and other rtnetlink related hooks. It is sent regularly
+via various slave interfaces of the batadv virtual interface and in this
+process also modified (realloced) to integrate additional state information
+via TVLV containers.
+
+It must be avoided that the worker item is executed without a common lock
+with the netdevice notifier/rtnetlink helpers. Otherwise it can either
+happen that half modified/freed data is sent out or functions modifying the
+OGM buffer try to access already freed memory regions.
+
+Reported-by: syzbot+0cc629f19ccb8534935b@syzkaller.appspotmail.com
+Fixes: ea6f8d42a595 ("batman-adv: move /proc interface handling to /sys")
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+
+Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/9b8ceef26c697d0c8319748428944c3339a498dc
+
+diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
+index 8967bc91423cd36b3a4dc240150ff2a694f5bed4..ccb60591a01886ceef22408e9387a8a3fda05a36 100644
+--- a/net/batman-adv/bat_iv_ogm.c
++++ b/net/batman-adv/bat_iv_ogm.c
+@@ -41,6 +41,7 @@
+ #include <linux/random.h>
+ #include <linux/rculist.h>
+ #include <linux/rcupdate.h>
++#include <linux/rtnetlink.h>
+ #include <linux/seq_file.h>
+ #include <linux/skbuff.h>
+ #include <linux/slab.h>
+@@ -370,6 +371,8 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
+       unsigned char *ogm_buff;
+       u32 random_seqno;
++      ASSERT_RTNL();
++
+       /* randomize initial seqno to avoid collision */
+       get_random_bytes(&random_seqno, sizeof(random_seqno));
+       atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno);
+@@ -394,6 +397,8 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
+ static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
+ {
++      ASSERT_RTNL();
++
+       kfree(hard_iface->bat_iv.ogm_buff);
+       hard_iface->bat_iv.ogm_buff = NULL;
+ }
+@@ -403,6 +408,8 @@ static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface)
+       struct batadv_ogm_packet *batadv_ogm_packet;
+       unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
++      ASSERT_RTNL();
++
+       batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
+       ether_addr_copy(batadv_ogm_packet->orig,
+                       hard_iface->net_dev->dev_addr);
+@@ -416,6 +423,8 @@ batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
+       struct batadv_ogm_packet *batadv_ogm_packet;
+       unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
++      ASSERT_RTNL();
++
+       batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
+       batadv_ogm_packet->ttl = BATADV_TTL;
+ }
+@@ -927,6 +936,8 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
+       u16 tvlv_len = 0;
+       unsigned long send_time;
++      ASSERT_RTNL();
++
+       if ((hard_iface->if_status == BATADV_IF_NOT_IN_USE) ||
+           (hard_iface->if_status == BATADV_IF_TO_BE_REMOVED))
+               return;
+@@ -1781,16 +1792,12 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
+       batadv_orig_node_put(orig_node);
+ }
+-static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
++static void
++batadv_iv_send_outstanding_forw_packet(struct batadv_forw_packet *forw_packet)
+ {
+-      struct delayed_work *delayed_work;
+-      struct batadv_forw_packet *forw_packet;
+       struct batadv_priv *bat_priv;
+       bool dropped = false;
+-      delayed_work = to_delayed_work(work);
+-      forw_packet = container_of(delayed_work, struct batadv_forw_packet,
+-                                 delayed_work);
+       bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
+       if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) {
+@@ -1819,6 +1826,20 @@ out:
+               batadv_forw_packet_free(forw_packet, dropped);
+ }
++static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
++{
++      struct delayed_work *delayed_work;
++      struct batadv_forw_packet *forw_packet;
++
++      delayed_work = to_delayed_work(work);
++      forw_packet = container_of(delayed_work, struct batadv_forw_packet,
++                                 delayed_work);
++
++      rtnl_lock();
++      batadv_iv_send_outstanding_forw_packet(forw_packet);
++      rtnl_unlock();
++}
++
+ static int batadv_iv_ogm_receive(struct sk_buff *skb,
+                                struct batadv_hard_iface *if_incoming)
+ {
+diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
+index 11ced015ab639f0d82f12ae533a92f356734cafa..2489d5e403c1bcbcc9008f51303f7b1ea4753ea2 100644
+--- a/net/batman-adv/types.h
++++ b/net/batman-adv/types.h
+@@ -78,8 +78,8 @@ enum batadv_dhcp_recipient {
+ /**
+  * struct batadv_hard_iface_bat_iv - per hard-interface B.A.T.M.A.N. IV data
+- * @ogm_buff: buffer holding the OGM packet
+- * @ogm_buff_len: length of the OGM packet buffer
++ * @ogm_buff: buffer holding the OGM packet. rtnl protected
++ * @ogm_buff_len: length of the OGM packet buffer. rtnl protected
+  * @ogm_seqno: OGM sequence number - used to identify each OGM
+  */
+ struct batadv_hard_iface_bat_iv {