diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-05-11 14:22:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-05-12 17:27:10 -0400 |
commit | 1769192a3c50778e03352a3d95faec830d47ba55 (patch) | |
tree | 9764b821abc0ddc4fa22c239e00460636aa77203 /net | |
parent | 3c709f8fb43e07a0403bba4a8ca7ba00ab874994 (diff) |
l2tp: fix potential rcu race
While trying to remove useless synchronize_rcu() calls, I found l2tp is
indeed incorrectly using two of such calls, but also bumps tunnel
refcount after list insertion.
tunnel refcount must be incremented before being made publically visible
by rcu readers.
This fix can be applied to 2.6.35+ and might need a backport for older
kernels, since things were shuffled in commit fd558d186df2c
(l2tp: Split pppol2tp patch into separate l2tp and ppp parts)
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
CC: James Chapman <jchapman@katalix.com>
Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/l2tp/l2tp_core.c | 10 |
1 files changed, 4 insertions, 6 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 9be095e00450..ed8a2335442f 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
@@ -1435,16 +1435,15 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 | |||
1435 | 1435 | ||
1436 | /* Add tunnel to our list */ | 1436 | /* Add tunnel to our list */ |
1437 | INIT_LIST_HEAD(&tunnel->list); | 1437 | INIT_LIST_HEAD(&tunnel->list); |
1438 | spin_lock_bh(&pn->l2tp_tunnel_list_lock); | ||
1439 | list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); | ||
1440 | spin_unlock_bh(&pn->l2tp_tunnel_list_lock); | ||
1441 | synchronize_rcu(); | ||
1442 | atomic_inc(&l2tp_tunnel_count); | 1438 | atomic_inc(&l2tp_tunnel_count); |
1443 | 1439 | ||
1444 | /* Bump the reference count. The tunnel context is deleted | 1440 | /* Bump the reference count. The tunnel context is deleted |
1445 | * only when this drops to zero. | 1441 | * only when this drops to zero. Must be done before list insertion |
1446 | */ | 1442 | */ |
1447 | l2tp_tunnel_inc_refcount(tunnel); | 1443 | l2tp_tunnel_inc_refcount(tunnel); |
1444 | spin_lock_bh(&pn->l2tp_tunnel_list_lock); | ||
1445 | list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list); | ||
1446 | spin_unlock_bh(&pn->l2tp_tunnel_list_lock); | ||
1448 | 1447 | ||
1449 | err = 0; | 1448 | err = 0; |
1450 | err: | 1449 | err: |
@@ -1636,7 +1635,6 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn | |||
1636 | hlist_add_head_rcu(&session->global_hlist, | 1635 | hlist_add_head_rcu(&session->global_hlist, |
1637 | l2tp_session_id_hash_2(pn, session_id)); | 1636 | l2tp_session_id_hash_2(pn, session_id)); |
1638 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); | 1637 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); |
1639 | synchronize_rcu(); | ||
1640 | } | 1638 | } |
1641 | 1639 | ||
1642 | /* Ignore management session in session count value */ | 1640 | /* Ignore management session in session count value */ |