diff options
author | David S. Miller <davem@davemloft.net> | 2011-05-08 16:39:01 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-05-08 16:39:01 -0400 |
commit | 2f16270f41e1499e23e6be25c51be87d950ffc91 (patch) | |
tree | b3d40d33c4ff5470eb3642d44064fe4ec4caff92 /net | |
parent | da905bd1d5a6480d206f4b3dc61243f95adfae2c (diff) |
l2tp: Fix locking in l2tp_ip.c
Both l2tp_ip_connect() and l2tp_ip_sendmsg() must take the socket
lock. They both modify socket state non-atomically, and in particular
l2tp_ip_sendmsg() increments socket private counters without using
atomic operations.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/l2tp/l2tp_ip.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 81899600abe2..bd0cc0b8f32f 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c | |||
@@ -311,6 +311,8 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len | |||
311 | if (lsa->l2tp_family != AF_INET) | 311 | if (lsa->l2tp_family != AF_INET) |
312 | goto out; | 312 | goto out; |
313 | 313 | ||
314 | lock_sock(sk); | ||
315 | |||
314 | sk_dst_reset(sk); | 316 | sk_dst_reset(sk); |
315 | 317 | ||
316 | oif = sk->sk_bound_dev_if; | 318 | oif = sk->sk_bound_dev_if; |
@@ -356,6 +358,7 @@ static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len | |||
356 | 358 | ||
357 | rc = 0; | 359 | rc = 0; |
358 | out: | 360 | out: |
361 | release_sock(sk); | ||
359 | return rc; | 362 | return rc; |
360 | } | 363 | } |
361 | 364 | ||
@@ -420,18 +423,23 @@ static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | |||
420 | int connected = 0; | 423 | int connected = 0; |
421 | __be32 daddr; | 424 | __be32 daddr; |
422 | 425 | ||
426 | lock_sock(sk); | ||
427 | |||
428 | rc = -ENOTCONN; | ||
423 | if (sock_flag(sk, SOCK_DEAD)) | 429 | if (sock_flag(sk, SOCK_DEAD)) |
424 | return -ENOTCONN; | 430 | goto out; |
425 | 431 | ||
426 | /* Get and verify the address. */ | 432 | /* Get and verify the address. */ |
427 | if (msg->msg_name) { | 433 | if (msg->msg_name) { |
428 | struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name; | 434 | struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name; |
435 | rc = -EINVAL; | ||
429 | if (msg->msg_namelen < sizeof(*lip)) | 436 | if (msg->msg_namelen < sizeof(*lip)) |
430 | return -EINVAL; | 437 | goto out; |
431 | 438 | ||
432 | if (lip->l2tp_family != AF_INET) { | 439 | if (lip->l2tp_family != AF_INET) { |
440 | rc = -EAFNOSUPPORT; | ||
433 | if (lip->l2tp_family != AF_UNSPEC) | 441 | if (lip->l2tp_family != AF_UNSPEC) |
434 | return -EAFNOSUPPORT; | 442 | goto out; |
435 | } | 443 | } |
436 | 444 | ||
437 | daddr = lip->l2tp_addr.s_addr; | 445 | daddr = lip->l2tp_addr.s_addr; |
@@ -510,12 +518,15 @@ error: | |||
510 | lsa->tx_errors++; | 518 | lsa->tx_errors++; |
511 | } | 519 | } |
512 | 520 | ||
521 | out: | ||
522 | release_sock(sk); | ||
513 | return rc; | 523 | return rc; |
514 | 524 | ||
515 | no_route: | 525 | no_route: |
516 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | 526 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); |
517 | kfree_skb(skb); | 527 | kfree_skb(skb); |
518 | return -EHOSTUNREACH; | 528 | rc = -EHOSTUNREACH; |
529 | goto out; | ||
519 | } | 530 | } |
520 | 531 | ||
521 | static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 532 | static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |