diff options
author | Marek Lindner <lindner_marek@yahoo.de> | 2011-04-20 09:40:58 -0400 |
---|---|---|
committer | Sven Eckelmann <sven@narfation.org> | 2011-05-01 16:49:03 -0400 |
commit | 32ae9b221e788413ce68feaae2ca39e406211a0a (patch) | |
tree | d827f989976a28fea5cdcb349c308baa98182c35 /net/batman-adv/vis.c | |
parent | 71e4aa9c465fd66c110667ab5d620fb6a4ef2157 (diff) |
batman-adv: Make bat_priv->primary_if an rcu protected pointer
The rcu protected macros rcu_dereference() and rcu_assign_pointer()
for the bat_priv->primary_if need to be used, as well as spin/rcu locking.
Otherwise we might end up using a primary_if pointer pointing to already
freed memory.
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Diffstat (limited to 'net/batman-adv/vis.c')
-rw-r--r-- | net/batman-adv/vis.c | 37 |
1 files changed, 26 insertions, 11 deletions
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index d4cc4f5399f4..c8f571d3b5d4 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c | |||
@@ -204,6 +204,7 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, | |||
204 | 204 | ||
205 | int vis_seq_print_text(struct seq_file *seq, void *offset) | 205 | int vis_seq_print_text(struct seq_file *seq, void *offset) |
206 | { | 206 | { |
207 | struct hard_iface *primary_if; | ||
207 | struct hlist_node *node; | 208 | struct hlist_node *node; |
208 | struct hlist_head *head; | 209 | struct hlist_head *head; |
209 | struct vis_info *info; | 210 | struct vis_info *info; |
@@ -215,15 +216,18 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
215 | HLIST_HEAD(vis_if_list); | 216 | HLIST_HEAD(vis_if_list); |
216 | struct if_list_entry *entry; | 217 | struct if_list_entry *entry; |
217 | struct hlist_node *pos, *n; | 218 | struct hlist_node *pos, *n; |
218 | int i, j; | 219 | int i, j, ret = 0; |
219 | int vis_server = atomic_read(&bat_priv->vis_mode); | 220 | int vis_server = atomic_read(&bat_priv->vis_mode); |
220 | size_t buff_pos, buf_size; | 221 | size_t buff_pos, buf_size; |
221 | char *buff; | 222 | char *buff; |
222 | int compare; | 223 | int compare; |
223 | 224 | ||
224 | if ((!bat_priv->primary_if) || | 225 | primary_if = primary_if_get_selected(bat_priv); |
225 | (vis_server == VIS_TYPE_CLIENT_UPDATE)) | 226 | if (!primary_if) |
226 | return 0; | 227 | goto out; |
228 | |||
229 | if (vis_server == VIS_TYPE_CLIENT_UPDATE) | ||
230 | goto out; | ||
227 | 231 | ||
228 | buf_size = 1; | 232 | buf_size = 1; |
229 | /* Estimate length */ | 233 | /* Estimate length */ |
@@ -270,7 +274,8 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
270 | buff = kmalloc(buf_size, GFP_ATOMIC); | 274 | buff = kmalloc(buf_size, GFP_ATOMIC); |
271 | if (!buff) { | 275 | if (!buff) { |
272 | spin_unlock_bh(&bat_priv->vis_hash_lock); | 276 | spin_unlock_bh(&bat_priv->vis_hash_lock); |
273 | return -ENOMEM; | 277 | ret = -ENOMEM; |
278 | goto out; | ||
274 | } | 279 | } |
275 | buff[0] = '\0'; | 280 | buff[0] = '\0'; |
276 | buff_pos = 0; | 281 | buff_pos = 0; |
@@ -328,7 +333,10 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
328 | seq_printf(seq, "%s", buff); | 333 | seq_printf(seq, "%s", buff); |
329 | kfree(buff); | 334 | kfree(buff); |
330 | 335 | ||
331 | return 0; | 336 | out: |
337 | if (primary_if) | ||
338 | hardif_free_ref(primary_if); | ||
339 | return ret; | ||
332 | } | 340 | } |
333 | 341 | ||
334 | /* add the info packet to the send list, if it was not | 342 | /* add the info packet to the send list, if it was not |
@@ -815,16 +823,20 @@ out: | |||
815 | /* only send one vis packet. called from send_vis_packets() */ | 823 | /* only send one vis packet. called from send_vis_packets() */ |
816 | static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) | 824 | static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) |
817 | { | 825 | { |
826 | struct hard_iface *primary_if; | ||
818 | struct vis_packet *packet; | 827 | struct vis_packet *packet; |
819 | 828 | ||
829 | primary_if = primary_if_get_selected(bat_priv); | ||
830 | if (!primary_if) | ||
831 | goto out; | ||
832 | |||
820 | packet = (struct vis_packet *)info->skb_packet->data; | 833 | packet = (struct vis_packet *)info->skb_packet->data; |
821 | if (packet->ttl < 2) { | 834 | if (packet->ttl < 2) { |
822 | pr_debug("Error - can't send vis packet: ttl exceeded\n"); | 835 | pr_debug("Error - can't send vis packet: ttl exceeded\n"); |
823 | return; | 836 | goto out; |
824 | } | 837 | } |
825 | 838 | ||
826 | memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr, | 839 | memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN); |
827 | ETH_ALEN); | ||
828 | packet->ttl--; | 840 | packet->ttl--; |
829 | 841 | ||
830 | if (is_broadcast_ether_addr(packet->target_orig)) | 842 | if (is_broadcast_ether_addr(packet->target_orig)) |
@@ -832,6 +844,10 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) | |||
832 | else | 844 | else |
833 | unicast_vis_packet(bat_priv, info); | 845 | unicast_vis_packet(bat_priv, info); |
834 | packet->ttl++; /* restore TTL */ | 846 | packet->ttl++; /* restore TTL */ |
847 | |||
848 | out: | ||
849 | if (primary_if) | ||
850 | hardif_free_ref(primary_if); | ||
835 | } | 851 | } |
836 | 852 | ||
837 | /* called from timer; send (and maybe generate) vis packet. */ | 853 | /* called from timer; send (and maybe generate) vis packet. */ |
@@ -858,8 +874,7 @@ static void send_vis_packets(struct work_struct *work) | |||
858 | kref_get(&info->refcount); | 874 | kref_get(&info->refcount); |
859 | spin_unlock_bh(&bat_priv->vis_hash_lock); | 875 | spin_unlock_bh(&bat_priv->vis_hash_lock); |
860 | 876 | ||
861 | if (bat_priv->primary_if) | 877 | send_vis_packet(bat_priv, info); |
862 | send_vis_packet(bat_priv, info); | ||
863 | 878 | ||
864 | spin_lock_bh(&bat_priv->vis_hash_lock); | 879 | spin_lock_bh(&bat_priv->vis_hash_lock); |
865 | send_list_del(info); | 880 | send_list_del(info); |