aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/bat_sysfs.c
diff options
context:
space:
mode:
authorMarek Lindner <lindner_marek@yahoo.de>2011-02-10 09:33:51 -0500
committerMarek Lindner <lindner_marek@yahoo.de>2011-03-05 06:50:07 -0500
commited75ccbe26f4a672a41556120390e67c80a2c441 (patch)
tree3f4f844d2311e662b4c42e7a275188d1346ac77d /net/batman-adv/bat_sysfs.c
parent7d2b554826195372764910da2f0dcb0d9b869108 (diff)
batman-adv: Correct rcu refcounting for batman_if
It might be possible that 2 threads access the same data in the same rcu grace period. The first thread calls call_rcu() to decrement the refcount and free the data while the second thread increases the refcount to use the data. To avoid this race condition all refcount operations have to be atomic. Reported-by: Sven Eckelmann <sven@narfation.org> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Diffstat (limited to 'net/batman-adv/bat_sysfs.c')
-rw-r--r--net/batman-adv/bat_sysfs.c20
1 files changed, 9 insertions, 11 deletions
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c
index f7b93a0805fe..93ae20aaad0a 100644
--- a/net/batman-adv/bat_sysfs.c
+++ b/net/batman-adv/bat_sysfs.c
@@ -450,7 +450,7 @@ static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr,
450 length = sprintf(buff, "%s\n", batman_if->if_status == IF_NOT_IN_USE ? 450 length = sprintf(buff, "%s\n", batman_if->if_status == IF_NOT_IN_USE ?
451 "none" : batman_if->soft_iface->name); 451 "none" : batman_if->soft_iface->name);
452 452
453 kref_put(&batman_if->refcount, hardif_free_ref); 453 hardif_free_ref(batman_if);
454 454
455 return length; 455 return length;
456} 456}
@@ -461,7 +461,7 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
461 struct net_device *net_dev = kobj_to_netdev(kobj); 461 struct net_device *net_dev = kobj_to_netdev(kobj);
462 struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); 462 struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
463 int status_tmp = -1; 463 int status_tmp = -1;
464 int ret; 464 int ret = count;
465 465
466 if (!batman_if) 466 if (!batman_if)
467 return count; 467 return count;
@@ -472,7 +472,7 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
472 if (strlen(buff) >= IFNAMSIZ) { 472 if (strlen(buff) >= IFNAMSIZ) {
473 pr_err("Invalid parameter for 'mesh_iface' setting received: " 473 pr_err("Invalid parameter for 'mesh_iface' setting received: "
474 "interface name too long '%s'\n", buff); 474 "interface name too long '%s'\n", buff);
475 kref_put(&batman_if->refcount, hardif_free_ref); 475 hardif_free_ref(batman_if);
476 return -EINVAL; 476 return -EINVAL;
477 } 477 }
478 478
@@ -482,17 +482,14 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
482 status_tmp = IF_I_WANT_YOU; 482 status_tmp = IF_I_WANT_YOU;
483 483
484 if ((batman_if->if_status == status_tmp) || ((batman_if->soft_iface) && 484 if ((batman_if->if_status == status_tmp) || ((batman_if->soft_iface) &&
485 (strncmp(batman_if->soft_iface->name, buff, IFNAMSIZ) == 0))) { 485 (strncmp(batman_if->soft_iface->name, buff, IFNAMSIZ) == 0)))
486 kref_put(&batman_if->refcount, hardif_free_ref); 486 goto out;
487 return count;
488 }
489 487
490 if (status_tmp == IF_NOT_IN_USE) { 488 if (status_tmp == IF_NOT_IN_USE) {
491 rtnl_lock(); 489 rtnl_lock();
492 hardif_disable_interface(batman_if); 490 hardif_disable_interface(batman_if);
493 rtnl_unlock(); 491 rtnl_unlock();
494 kref_put(&batman_if->refcount, hardif_free_ref); 492 goto out;
495 return count;
496 } 493 }
497 494
498 /* if the interface already is in use */ 495 /* if the interface already is in use */
@@ -503,8 +500,9 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
503 } 500 }
504 501
505 ret = hardif_enable_interface(batman_if, buff); 502 ret = hardif_enable_interface(batman_if, buff);
506 kref_put(&batman_if->refcount, hardif_free_ref);
507 503
504out:
505 hardif_free_ref(batman_if);
508 return ret; 506 return ret;
509} 507}
510 508
@@ -537,7 +535,7 @@ static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
537 break; 535 break;
538 } 536 }
539 537
540 kref_put(&batman_if->refcount, hardif_free_ref); 538 hardif_free_ref(batman_if);
541 539
542 return length; 540 return length;
543} 541}