aboutsummaryrefslogtreecommitdiffstats
path: root/net/l2tp
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-05-11 14:22:36 -0400
committerDavid S. Miller <davem@davemloft.net>2011-05-12 17:27:10 -0400
commit1769192a3c50778e03352a3d95faec830d47ba55 (patch)
tree9764b821abc0ddc4fa22c239e00460636aa77203 /net/l2tp
parent3c709f8fb43e07a0403bba4a8ca7ba00ab874994 (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/l2tp')
-rw-r--r--net/l2tp/l2tp_core.c10
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;
1450err: 1449err:
@@ -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 */