diff options
author | Marek Lindner <lindner_marek@yahoo.de> | 2011-02-10 09:33:51 -0500 |
---|---|---|
committer | Marek Lindner <lindner_marek@yahoo.de> | 2011-03-05 06:50:07 -0500 |
commit | ed75ccbe26f4a672a41556120390e67c80a2c441 (patch) | |
tree | 3f4f844d2311e662b4c42e7a275188d1346ac77d /net/batman-adv/bat_sysfs.c | |
parent | 7d2b554826195372764910da2f0dcb0d9b869108 (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.c | 20 |
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 | ||
504 | out: | ||
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 | } |