tipc: eliminate risk of finding to-be-deleted node instance
Although we have never seen it happen, we have identified the following problematic scenario when nodes are stopped and deleted: CPU0: CPU1: tipc_node_xxx() //ref == 1 tipc_node_put() //ref -> 0 tipc_node_find() // node still in table tipc_node_delete() list_del_rcu(n. list) tipc_node_get() //ref -> 1, bad kfree_rcu() tipc_node_put() //ref to 0 again. kfree_rcu() // BOOM! We fix this by introducing use of the conditional kref_get_if_not_zero() instead of kref_get() in the function tipc_node_find(). This eliminates any risk of post-mortem access. Reported-by: Zhijiang Hu <huzhijiang@gmail.com> Acked-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
3da7611f42
Коммит
b170997ace
|
@ -245,23 +245,23 @@ static void tipc_node_get(struct tipc_node *node)
|
||||||
*/
|
*/
|
||||||
static struct tipc_node *tipc_node_find(struct net *net, u32 addr)
|
static struct tipc_node *tipc_node_find(struct net *net, u32 addr)
|
||||||
{
|
{
|
||||||
struct tipc_net *tn = net_generic(net, tipc_net_id);
|
struct tipc_net *tn = tipc_net(net);
|
||||||
struct tipc_node *node;
|
struct tipc_node *node;
|
||||||
|
unsigned int thash = tipc_hashfn(addr);
|
||||||
|
|
||||||
if (unlikely(!in_own_cluster_exact(net, addr)))
|
if (unlikely(!in_own_cluster_exact(net, addr)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
hlist_for_each_entry_rcu(node, &tn->node_htable[tipc_hashfn(addr)],
|
hlist_for_each_entry_rcu(node, &tn->node_htable[thash], hash) {
|
||||||
hash) {
|
if (node->addr != addr)
|
||||||
if (node->addr == addr) {
|
continue;
|
||||||
tipc_node_get(node);
|
if (!kref_get_unless_zero(&node->kref))
|
||||||
rcu_read_unlock();
|
node = NULL;
|
||||||
return node;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return NULL;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tipc_node_read_lock(struct tipc_node *n)
|
static void tipc_node_read_lock(struct tipc_node *n)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче