--- /dev/null
+From a8d23cbbf6c9f515ed678204ad2962be7c336344 Mon Sep 17 00:00:00 2001
+From: Sven Eckelmann <sven@narfation.org>
+Date: Thu, 3 Oct 2019 17:02:01 +0200
+Subject: batman-adv: Avoid free/alloc race when handling OGM2 buffer
+
+From: Sven Eckelmann <sven@narfation.org>
+
+commit a8d23cbbf6c9f515ed678204ad2962be7c336344 upstream.
+
+A B.A.T.M.A.N. V virtual interface has an OGM2 packet buffer which is
+initialized using data from the 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 data is sent out or the functions modifying the
+OGM2 buffer try to access already freed memory regions.
+
+Fixes: 0da0035942d4 ("batman-adv: OGMv2 - add basic infrastructure")
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/batman-adv/bat_v_ogm.c | 42 ++++++++++++++++++++++++++++++++++--------
+ net/batman-adv/types.h | 4 ++++
+ 2 files changed, 38 insertions(+), 8 deletions(-)
+
+--- a/net/batman-adv/bat_v_ogm.c
++++ b/net/batman-adv/bat_v_ogm.c
+@@ -29,6 +29,8 @@
+ #include <linux/kernel.h>
+ #include <linux/kref.h>
+ #include <linux/list.h>
++#include <linux/lockdep.h>
++#include <linux/mutex.h>
+ #include <linux/netdevice.h>
+ #include <linux/random.h>
+ #include <linux/rculist.h>
+@@ -128,14 +130,12 @@ static void batadv_v_ogm_send_to_if(stru
+ }
+
+ /**
+- * batadv_v_ogm_send() - periodic worker broadcasting the own OGM
+- * @work: work queue item
++ * batadv_v_ogm_send_softif() - periodic worker broadcasting the own OGM
++ * @bat_priv: the bat priv with all the soft interface information
+ */
+-static void batadv_v_ogm_send(struct work_struct *work)
++static void batadv_v_ogm_send_softif(struct batadv_priv *bat_priv)
+ {
+ struct batadv_hard_iface *hard_iface;
+- struct batadv_priv_bat_v *bat_v;
+- struct batadv_priv *bat_priv;
+ struct batadv_ogm2_packet *ogm_packet;
+ struct sk_buff *skb, *skb_tmp;
+ unsigned char *ogm_buff;
+@@ -143,8 +143,7 @@ static void batadv_v_ogm_send(struct wor
+ u16 tvlv_len = 0;
+ int ret;
+
+- bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
+- bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
++ lockdep_assert_held(&bat_priv->bat_v.ogm_buff_mutex);
+
+ if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
+ goto out;
+@@ -236,6 +235,23 @@ out:
+ }
+
+ /**
++ * batadv_v_ogm_send() - periodic worker broadcasting the own OGM
++ * @work: work queue item
++ */
++static void batadv_v_ogm_send(struct work_struct *work)
++{
++ struct batadv_priv_bat_v *bat_v;
++ struct batadv_priv *bat_priv;
++
++ bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
++ bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
++
++ mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
++ batadv_v_ogm_send_softif(bat_priv);
++ mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
++}
++
++/**
+ * batadv_v_ogm_iface_enable() - prepare an interface for B.A.T.M.A.N. V
+ * @hard_iface: the interface to prepare
+ *
+@@ -261,11 +277,15 @@ void batadv_v_ogm_primary_iface_set(stru
+ struct batadv_priv *bat_priv = netdev_priv(primary_iface->soft_iface);
+ struct batadv_ogm2_packet *ogm_packet;
+
++ mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
+ if (!bat_priv->bat_v.ogm_buff)
+- return;
++ goto unlock;
+
+ ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
+ ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr);
++
++unlock:
++ mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
+ }
+
+ /**
+@@ -887,6 +907,8 @@ int batadv_v_ogm_init(struct batadv_priv
+ atomic_set(&bat_priv->bat_v.ogm_seqno, random_seqno);
+ INIT_DELAYED_WORK(&bat_priv->bat_v.ogm_wq, batadv_v_ogm_send);
+
++ mutex_init(&bat_priv->bat_v.ogm_buff_mutex);
++
+ return 0;
+ }
+
+@@ -898,7 +920,11 @@ void batadv_v_ogm_free(struct batadv_pri
+ {
+ cancel_delayed_work_sync(&bat_priv->bat_v.ogm_wq);
+
++ mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
++
+ kfree(bat_priv->bat_v.ogm_buff);
+ bat_priv->bat_v.ogm_buff = NULL;
+ bat_priv->bat_v.ogm_buff_len = 0;
++
++ mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
+ }
+--- a/net/batman-adv/types.h
++++ b/net/batman-adv/types.h
+@@ -28,6 +28,7 @@
+ #include <linux/compiler.h>
+ #include <linux/if_ether.h>
+ #include <linux/kref.h>
++#include <linux/mutex.h>
+ #include <linux/netdevice.h>
+ #include <linux/netlink.h>
+ #include <linux/sched.h> /* for linux/wait.h */
+@@ -1493,6 +1494,9 @@ struct batadv_priv_bat_v {
+ /** @ogm_seqno: OGM sequence number - used to identify each OGM */
+ atomic_t ogm_seqno;
+
++ /** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */
++ struct mutex ogm_buff_mutex;
++
+ /** @ogm_wq: workqueue used to schedule OGM transmissions */
+ struct delayed_work ogm_wq;
+ };