aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-05-08 16:39:01 -0400
committerDavid S. Miller <davem@davemloft.net>2011-05-08 16:39:01 -0400
commit2f16270f41e1499e23e6be25c51be87d950ffc91 (patch)
treeb3d40d33c4ff5470eb3642d44064fe4ec4caff92 /net
parentda905bd1d5a6480d206f4b3dc61243f95adfae2c (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.c19
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;
358out: 360out:
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
521out:
522 release_sock(sk);
513 return rc; 523 return rc;
514 524
515no_route: 525no_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
521static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 532static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,