aboutsummaryrefslogtreecommitdiffstats
path: root/include/net/sock.h
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 /include/net/sock.h
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 'include/net/sock.h')
-rw-r--r--include/net/sock.h15
1 files changed, 14 insertions, 1 deletions
diff --git a/include/net/sock.h b/include/net/sock.h
index 6cb1676e409a..2516d76f043c 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -253,6 +253,8 @@ struct sock {
253 struct { 253 struct {
254 struct sk_buff *head; 254 struct sk_buff *head;
255 struct sk_buff *tail; 255 struct sk_buff *tail;
256 int len;
257 int limit;
256 } sk_backlog; 258 } sk_backlog;
257 wait_queue_head_t *sk_sleep; 259 wait_queue_head_t *sk_sleep;
258 struct dst_entry *sk_dst_cache; 260 struct dst_entry *sk_dst_cache;
@@ -589,7 +591,7 @@ static inline int sk_stream_memory_free(struct sock *sk)
589 return sk->sk_wmem_queued < sk->sk_sndbuf; 591 return sk->sk_wmem_queued < sk->sk_sndbuf;
590} 592}
591 593
592/* The per-socket spinlock must be held here. */ 594/* OOB backlog add */
593static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb) 595static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb)
594{ 596{
595 if (!sk->sk_backlog.tail) { 597 if (!sk->sk_backlog.tail) {
@@ -601,6 +603,17 @@ static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb)
601 skb->next = NULL; 603 skb->next = NULL;
602} 604}
603 605
606/* The per-socket spinlock must be held here. */
607static inline int sk_add_backlog_limited(struct sock *sk, struct sk_buff *skb)
608{
609 if (sk->sk_backlog.len >= max(sk->sk_backlog.limit, sk->sk_rcvbuf << 1))
610 return -ENOBUFS;
611
612 sk_add_backlog(sk, skb);
613 sk->sk_backlog.len += skb->truesize;
614 return 0;
615}
616
604static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) 617static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
605{ 618{
606 return sk->sk_backlog_rcv(sk, skb); 619 return sk->sk_backlog_rcv(sk, skb);