Skip to content

Commit dc6ae4d

Browse files
edumazetgregkh
authored andcommitted
tcp: detect malicious patterns in tcp_collapse_ofo_queue()
[ Upstream commit 3d4bf93 ] 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]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 5fbec48 commit dc6ae4d

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

net/ipv4/tcp_input.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4789,6 +4789,7 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list,
47894789
static void tcp_collapse_ofo_queue(struct sock *sk)
47904790
{
47914791
struct tcp_sock *tp = tcp_sk(sk);
4792+
u32 range_truesize, sum_tiny = 0;
47924793
struct sk_buff *skb = skb_peek(&tp->out_of_order_queue);
47934794
struct sk_buff *head;
47944795
u32 start, end;
@@ -4798,6 +4799,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk)
47984799

47994800
start = TCP_SKB_CB(skb)->seq;
48004801
end = TCP_SKB_CB(skb)->end_seq;
4802+
range_truesize = skb->truesize;
48014803
head = skb;
48024804

48034805
for (;;) {
@@ -4812,14 +4814,24 @@ static void tcp_collapse_ofo_queue(struct sock *sk)
48124814
if (!skb ||
48134815
after(TCP_SKB_CB(skb)->seq, end) ||
48144816
before(TCP_SKB_CB(skb)->end_seq, start)) {
4815-
tcp_collapse(sk, &tp->out_of_order_queue,
4816-
head, skb, start, end);
4817+
/* Do not attempt collapsing tiny skbs */
4818+
if (range_truesize != head->truesize ||
4819+
end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) {
4820+
tcp_collapse(sk, &tp->out_of_order_queue,
4821+
head, skb, start, end);
4822+
} else {
4823+
sum_tiny += range_truesize;
4824+
if (sum_tiny > sk->sk_rcvbuf >> 3)
4825+
return;
4826+
}
4827+
48174828
head = skb;
48184829
if (!skb)
48194830
break;
48204831
/* Start new segment */
48214832
start = TCP_SKB_CB(skb)->seq;
48224833
end = TCP_SKB_CB(skb)->end_seq;
4834+
range_truesize = skb->truesize;
48234835
} else {
48244836
if (before(TCP_SKB_CB(skb)->seq, start))
48254837
start = TCP_SKB_CB(skb)->seq;

0 commit comments

Comments
 (0)