Commit d42da7c9 authored by Eric Dumazet's avatar Eric Dumazet Committed by Stefan Bader

tcp: detect malicious patterns in tcp_collapse_ofo_queue()

In case an attacker feeds tiny packets completely out of order,
tcp_collapse_ofo_queue() might scan the whole rb-tree, performing
expensive copies, but not changing socket memory usage at all.

1) Do not attempt to collapse tiny skbs.
2) Add logic to exit early when too many tiny skbs are detected.

We prefer not doing aggressive collapsing (which copies packets)
for pathological flows, and revert to tcp_prune_ofo_queue() which
will be less expensive.

In the future, we might add the possibility of terminating flows
that are proven to be malicious.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Acked-by: default avatarSoheil Hassas Yeganeh <soheil@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>

CVE-2018-5390

(backported from commit 3d4bf93a)
Signed-off-by: default avatarTyler Hicks <tyhicks@canonical.com>
Signed-off-by: default avatarStefan Bader <stefan.bader@canonical.com>
parent 60102d86
...@@ -4774,6 +4774,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, ...@@ -4774,6 +4774,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list,
static void tcp_collapse_ofo_queue(struct sock *sk) static void tcp_collapse_ofo_queue(struct sock *sk)
{ {
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
u32 range_truesize, sum_tiny = 0;
struct sk_buff *skb = skb_peek(&tp->out_of_order_queue); struct sk_buff *skb = skb_peek(&tp->out_of_order_queue);
struct sk_buff *head; struct sk_buff *head;
u32 start, end; u32 start, end;
...@@ -4783,6 +4784,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk) ...@@ -4783,6 +4784,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk)
start = TCP_SKB_CB(skb)->seq; start = TCP_SKB_CB(skb)->seq;
end = TCP_SKB_CB(skb)->end_seq; end = TCP_SKB_CB(skb)->end_seq;
range_truesize = skb->truesize;
head = skb; head = skb;
for (;;) { for (;;) {
...@@ -4797,14 +4799,24 @@ static void tcp_collapse_ofo_queue(struct sock *sk) ...@@ -4797,14 +4799,24 @@ static void tcp_collapse_ofo_queue(struct sock *sk)
if (!skb || if (!skb ||
after(TCP_SKB_CB(skb)->seq, end) || after(TCP_SKB_CB(skb)->seq, end) ||
before(TCP_SKB_CB(skb)->end_seq, start)) { before(TCP_SKB_CB(skb)->end_seq, start)) {
tcp_collapse(sk, &tp->out_of_order_queue, /* Do not attempt collapsing tiny skbs */
head, skb, start, end); if (range_truesize != head->truesize ||
end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) {
tcp_collapse(sk, &tp->out_of_order_queue,
head, skb, start, end);
} else {
sum_tiny += range_truesize;
if (sum_tiny > sk->sk_rcvbuf >> 3)
return;
}
head = skb; head = skb;
if (!skb) if (!skb)
break; break;
/* Start new segment */ /* Start new segment */
start = TCP_SKB_CB(skb)->seq; start = TCP_SKB_CB(skb)->seq;
end = TCP_SKB_CB(skb)->end_seq; end = TCP_SKB_CB(skb)->end_seq;
range_truesize += skb->truesize;
} else { } else {
if (before(TCP_SKB_CB(skb)->seq, start)) if (before(TCP_SKB_CB(skb)->seq, start))
start = TCP_SKB_CB(skb)->seq; start = TCP_SKB_CB(skb)->seq;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment