aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2015-12-08 10:22:02 -0500
committerDavid S. Miller <davem@davemloft.net>2015-12-11 19:22:06 -0500
commitd188ba86dd07a72ebebfa22fe9cb0b0572e57740 (patch)
tree3633c759d096b6fccc50e5641b1dcf8633a1dbf5 /net/xfrm
parent56f047305dd4b6b61771ac4f523718e4111052a8 (diff)
xfrm: add rcu protection to sk->sk_policy[]
XFRM can deal with SYNACK messages, sent while listener socket is not locked. We add proper rcu protection to __xfrm_sk_clone_policy() and xfrm_sk_policy_lookup() This might serve as the first step to remove xfrm.xfrm_policy_lock use in fast path. Fixes: fa76ce7328b2 ("inet: get rid of central tcp/dccp listener timer") Signed-off-by: Eric Dumazet <edumazet@google.com> Acked-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c37
1 files changed, 25 insertions, 12 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index f57a5712cedd..948fa5560de5 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1221,8 +1221,10 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
1221 struct xfrm_policy *pol; 1221 struct xfrm_policy *pol;
1222 struct net *net = sock_net(sk); 1222 struct net *net = sock_net(sk);
1223 1223
1224 rcu_read_lock();
1224 read_lock_bh(&net->xfrm.xfrm_policy_lock); 1225 read_lock_bh(&net->xfrm.xfrm_policy_lock);
1225 if ((pol = sk->sk_policy[dir]) != NULL) { 1226 pol = rcu_dereference(sk->sk_policy[dir]);
1227 if (pol != NULL) {
1226 bool match = xfrm_selector_match(&pol->selector, fl, 1228 bool match = xfrm_selector_match(&pol->selector, fl,
1227 sk->sk_family); 1229 sk->sk_family);
1228 int err = 0; 1230 int err = 0;
@@ -1246,6 +1248,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
1246 } 1248 }
1247out: 1249out:
1248 read_unlock_bh(&net->xfrm.xfrm_policy_lock); 1250 read_unlock_bh(&net->xfrm.xfrm_policy_lock);
1251 rcu_read_unlock();
1249 return pol; 1252 return pol;
1250} 1253}
1251 1254
@@ -1314,13 +1317,14 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
1314#endif 1317#endif
1315 1318
1316 write_lock_bh(&net->xfrm.xfrm_policy_lock); 1319 write_lock_bh(&net->xfrm.xfrm_policy_lock);
1317 old_pol = sk->sk_policy[dir]; 1320 old_pol = rcu_dereference_protected(sk->sk_policy[dir],
1318 sk->sk_policy[dir] = pol; 1321 lockdep_is_held(&net->xfrm.xfrm_policy_lock));
1319 if (pol) { 1322 if (pol) {
1320 pol->curlft.add_time = get_seconds(); 1323 pol->curlft.add_time = get_seconds();
1321 pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0); 1324 pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
1322 xfrm_sk_policy_link(pol, dir); 1325 xfrm_sk_policy_link(pol, dir);
1323 } 1326 }
1327 rcu_assign_pointer(sk->sk_policy[dir], pol);
1324 if (old_pol) { 1328 if (old_pol) {
1325 if (pol) 1329 if (pol)
1326 xfrm_policy_requeue(old_pol, pol); 1330 xfrm_policy_requeue(old_pol, pol);
@@ -1368,17 +1372,26 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
1368 return newp; 1372 return newp;
1369} 1373}
1370 1374
1371int __xfrm_sk_clone_policy(struct sock *sk) 1375int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
1372{ 1376{
1373 struct xfrm_policy *p0 = sk->sk_policy[0], 1377 const struct xfrm_policy *p;
1374 *p1 = sk->sk_policy[1]; 1378 struct xfrm_policy *np;
1379 int i, ret = 0;
1375 1380
1376 sk->sk_policy[0] = sk->sk_policy[1] = NULL; 1381 rcu_read_lock();
1377 if (p0 && (sk->sk_policy[0] = clone_policy(p0, 0)) == NULL) 1382 for (i = 0; i < 2; i++) {
1378 return -ENOMEM; 1383 p = rcu_dereference(osk->sk_policy[i]);
1379 if (p1 && (sk->sk_policy[1] = clone_policy(p1, 1)) == NULL) 1384 if (p) {
1380 return -ENOMEM; 1385 np = clone_policy(p, i);
1381 return 0; 1386 if (unlikely(!np)) {
1387 ret = -ENOMEM;
1388 break;
1389 }
1390 rcu_assign_pointer(sk->sk_policy[i], np);
1391 }
1392 }
1393 rcu_read_unlock();
1394 return ret;
1382} 1395}
1383 1396
1384static int 1397static int