aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2010-03-04 13:01:40 -0500
committerDavid S. Miller <davem@davemloft.net>2010-03-05 16:33:59 -0500
commit8eae939f1400326b06d0c9afe53d2a484a326871 (patch)
tree0896163cf1a00205fab76cc1c35855157a05cbbc /net
parent12c3400a84742f8bb0e4edc822e9ccba58781e0c (diff)
net: add limit for socket backlog
We got system OOM while running some UDP netperf testing on the loopback device. The case is multiple senders sent stream UDP packets to a single receiver via loopback on local host. Of course, the receiver is not able to handle all the packets in time. But we surprisingly found that these packets were not discarded due to the receiver's sk->sk_rcvbuf limit. Instead, they are kept queuing to sk->sk_backlog and finally ate up all the memory. We believe this is a secure hole that a none privileged user can crash the system. The root cause for this problem is, when the receiver is doing __release_sock() (i.e. after userspace recv, kernel udp_recvmsg -> skb_free_datagram_locked -> release_sock), it moves skbs from backlog to sk_receive_queue with the softirq enabled. In the above case, multiple busy senders will almost make it an endless loop. The skbs in the backlog end up eat all the system memory. The issue is not only for UDP. Any protocols using socket backlog is potentially affected. The patch adds limit for socket backlog so that the backlog size cannot be expanded endlessly. Reported-by: Alex Shi <alex.shi@intel.com> Cc: David Miller <davem@davemloft.net> Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru Cc: "Pekka Savola (ipv6)" <pekkas@netcore.fi> Cc: Patrick McHardy <kaber@trash.net> Cc: Vlad Yasevich <vladislav.yasevich@hp.com> Cc: Sridhar Samudrala <sri@us.ibm.com> Cc: Jon Maloy <jon.maloy@ericsson.com> Cc: Allan Stephens <allan.stephens@windriver.com> Cc: Andrew Hendry <andrew.hendry@gmail.com> Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/sock.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/net/core/sock.c b/net/core/sock.c
index fcd397a762ff..6e22dc973d23 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -340,8 +340,12 @@ int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested)
340 rc = sk_backlog_rcv(sk, skb); 340 rc = sk_backlog_rcv(sk, skb);
341 341
342 mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_); 342 mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_);
343 } else 343 } else if (sk_add_backlog_limited(sk, skb)) {
344 sk_add_backlog(sk, skb); 344 bh_unlock_sock(sk);
345 atomic_inc(&sk->sk_drops);
346 goto discard_and_relse;
347 }
348
345 bh_unlock_sock(sk); 349 bh_unlock_sock(sk);
346out: 350out:
347 sock_put(sk); 351 sock_put(sk);
@@ -1139,6 +1143,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
1139 sock_lock_init(newsk); 1143 sock_lock_init(newsk);
1140 bh_lock_sock(newsk); 1144 bh_lock_sock(newsk);
1141 newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL; 1145 newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL;
1146 newsk->sk_backlog.len = 0;
1142 1147
1143 atomic_set(&newsk->sk_rmem_alloc, 0); 1148 atomic_set(&newsk->sk_rmem_alloc, 0);
1144 /* 1149 /*
@@ -1542,6 +1547,12 @@ static void __release_sock(struct sock *sk)
1542 1547
1543 bh_lock_sock(sk); 1548 bh_lock_sock(sk);
1544 } while ((skb = sk->sk_backlog.head) != NULL); 1549 } while ((skb = sk->sk_backlog.head) != NULL);
1550
1551 /*
1552 * Doing the zeroing here guarantee we can not loop forever
1553 * while a wild producer attempts to flood us.
1554 */
1555 sk->sk_backlog.len = 0;
1545} 1556}
1546 1557
1547/** 1558/**
@@ -1874,6 +1885,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
1874 sk->sk_allocation = GFP_KERNEL; 1885 sk->sk_allocation = GFP_KERNEL;
1875 sk->sk_rcvbuf = sysctl_rmem_default; 1886 sk->sk_rcvbuf = sysctl_rmem_default;
1876 sk->sk_sndbuf = sysctl_wmem_default; 1887 sk->sk_sndbuf = sysctl_wmem_default;
1888 sk->sk_backlog.limit = sk->sk_rcvbuf << 1;
1877 sk->sk_state = TCP_CLOSE; 1889 sk->sk_state = TCP_CLOSE;
1878 sk_set_socket(sk, sock); 1890 sk_set_socket(sk, sock);
1879 1891