Merge pull request #624 from ecsv/batadv-for-18.06
[feed/routing.git] / batman-adv / patches / 0037-batman-adv-Avoid-free-alloc-race-when-handling-OGM-b.patch
1 From: Sven Eckelmann <sven@narfation.org>
2 Date: Thu, 3 Oct 2019 17:02:01 +0200
3 Subject: batman-adv: Avoid free/alloc race when handling OGM buffer
4
5 Each slave interface of an B.A.T.M.A.N. IV virtual interface has an OGM
6 packet buffer which is initialized using data from the RTNL lock protected
7 netdevice notifier and other rtnetlink related hooks. It is sent regularly
8 via various slave interfaces of the batadv virtual interface and in this
9 process also modified (realloced) to integrate additional state information
10 via TVLV containers.
11
12 It must be avoided that the worker item is executed without a common lock
13 with the netdevice notifier/rtnetlink helpers. Otherwise it can either
14 happen that half modified/freed data is sent out or functions modifying the
15 OGM buffer try to access already freed memory regions.
16
17 Reported-by: syzbot+0cc629f19ccb8534935b@syzkaller.appspotmail.com
18 Fixes: ea6f8d42a595 ("batman-adv: move /proc interface handling to /sys")
19 Signed-off-by: Sven Eckelmann <sven@narfation.org>
20
21 Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/9b8ceef26c697d0c8319748428944c3339a498dc
22
23 diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
24 index 36f244125d24c800d35249af7639d39a516588d4..5b2ef12cfabb24ccbe2c1848cfff4d1ded9bd0b0 100644
25 --- a/net/batman-adv/bat_iv_ogm.c
26 +++ b/net/batman-adv/bat_iv_ogm.c
27 @@ -42,6 +42,7 @@
28 #include <linux/random.h>
29 #include <linux/rculist.h>
30 #include <linux/rcupdate.h>
31 +#include <linux/rtnetlink.h>
32 #include <linux/seq_file.h>
33 #include <linux/skbuff.h>
34 #include <linux/slab.h>
35 @@ -379,6 +380,8 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
36 unsigned char *ogm_buff;
37 u32 random_seqno;
38
39 + ASSERT_RTNL();
40 +
41 /* randomize initial seqno to avoid collision */
42 get_random_bytes(&random_seqno, sizeof(random_seqno));
43 atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno);
44 @@ -403,6 +406,8 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
45
46 static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
47 {
48 + ASSERT_RTNL();
49 +
50 kfree(hard_iface->bat_iv.ogm_buff);
51 hard_iface->bat_iv.ogm_buff = NULL;
52 }
53 @@ -412,6 +417,8 @@ static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface)
54 struct batadv_ogm_packet *batadv_ogm_packet;
55 unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
56
57 + ASSERT_RTNL();
58 +
59 batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
60 ether_addr_copy(batadv_ogm_packet->orig,
61 hard_iface->net_dev->dev_addr);
62 @@ -425,6 +432,8 @@ batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
63 struct batadv_ogm_packet *batadv_ogm_packet;
64 unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
65
66 + ASSERT_RTNL();
67 +
68 batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
69 batadv_ogm_packet->ttl = BATADV_TTL;
70 }
71 @@ -935,6 +944,8 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
72 u16 tvlv_len = 0;
73 unsigned long send_time;
74
75 + ASSERT_RTNL();
76 +
77 if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
78 hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
79 return;
80 @@ -1791,16 +1802,12 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
81 batadv_orig_node_put(orig_node);
82 }
83
84 -static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
85 +static void
86 +batadv_iv_send_outstanding_forw_packet(struct batadv_forw_packet *forw_packet)
87 {
88 - struct delayed_work *delayed_work;
89 - struct batadv_forw_packet *forw_packet;
90 struct batadv_priv *bat_priv;
91 bool dropped = false;
92
93 - delayed_work = to_delayed_work(work);
94 - forw_packet = container_of(delayed_work, struct batadv_forw_packet,
95 - delayed_work);
96 bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
97
98 if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) {
99 @@ -1829,6 +1836,20 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
100 batadv_forw_packet_free(forw_packet, dropped);
101 }
102
103 +static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
104 +{
105 + struct delayed_work *delayed_work;
106 + struct batadv_forw_packet *forw_packet;
107 +
108 + delayed_work = to_delayed_work(work);
109 + forw_packet = container_of(delayed_work, struct batadv_forw_packet,
110 + delayed_work);
111 +
112 + rtnl_lock();
113 + batadv_iv_send_outstanding_forw_packet(forw_packet);
114 + rtnl_unlock();
115 +}
116 +
117 static int batadv_iv_ogm_receive(struct sk_buff *skb,
118 struct batadv_hard_iface *if_incoming)
119 {
120 diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
121 index 3392198ff146ba77d320104663e97ab21559d556..49e4e6cb506f192e85e96e8b3e68be3fdc2dca57 100644
122 --- a/net/batman-adv/types.h
123 +++ b/net/batman-adv/types.h
124 @@ -82,10 +82,10 @@ enum batadv_dhcp_recipient {
125 * struct batadv_hard_iface_bat_iv - per hard-interface B.A.T.M.A.N. IV data
126 */
127 struct batadv_hard_iface_bat_iv {
128 - /** @ogm_buff: buffer holding the OGM packet */
129 + /** @ogm_buff: buffer holding the OGM packet. rtnl protected */
130 unsigned char *ogm_buff;
131
132 - /** @ogm_buff_len: length of the OGM packet buffer */
133 + /** @ogm_buff_len: length of the OGM packet buffer. rtnl protected */
134 int ogm_buff_len;
135
136 /** @ogm_seqno: OGM sequence number - used to identify each OGM */