Skip to content

Commit 3d4bf93

Browse files
edumazetdavem330
authored andcommitted
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: Eric Dumazet <[email protected]> Acked-by: Soheil Hassas Yeganeh <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f4a3313 commit 3d4bf93

File tree

1 file changed

+13
-2
lines changed

1 file changed

+13
-2
lines changed

net/ipv4/tcp_input.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4902,6 +4902,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root,
49024902
static void tcp_collapse_ofo_queue(struct sock *sk)
49034903
{
49044904
struct tcp_sock *tp = tcp_sk(sk);
4905+
u32 range_truesize, sum_tiny = 0;
49054906
struct sk_buff *skb, *head;
49064907
u32 start, end;
49074908

@@ -4913,6 +4914,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk)
49134914
}
49144915
start = TCP_SKB_CB(skb)->seq;
49154916
end = TCP_SKB_CB(skb)->end_seq;
4917+
range_truesize = skb->truesize;
49164918

49174919
for (head = skb;;) {
49184920
skb = skb_rb_next(skb);
@@ -4923,11 +4925,20 @@ static void tcp_collapse_ofo_queue(struct sock *sk)
49234925
if (!skb ||
49244926
after(TCP_SKB_CB(skb)->seq, end) ||
49254927
before(TCP_SKB_CB(skb)->end_seq, start)) {
4926-
tcp_collapse(sk, NULL, &tp->out_of_order_queue,
4927-
head, skb, start, end);
4928+
/* Do not attempt collapsing tiny skbs */
4929+
if (range_truesize != head->truesize ||
4930+
end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) {
4931+
tcp_collapse(sk, NULL, &tp->out_of_order_queue,
4932+
head, skb, start, end);
4933+
} else {
4934+
sum_tiny += range_truesize;
4935+
if (sum_tiny > sk->sk_rcvbuf >> 3)
4936+
return;
4937+
}
49284938
goto new_range;
49294939
}
49304940

4941+
range_truesize += skb->truesize;
49314942
if (unlikely(before(TCP_SKB_CB(skb)->seq, start)))
49324943
start = TCP_SKB_CB(skb)->seq;
49334944
if (after(TCP_SKB_CB(skb)->end_seq, end))

0 commit comments

Comments
 (0)