mirror of
https://github.com/torvalds/linux.git
synced 2024-12-03 17:41:22 +00:00
tcp: fix potential huge kmalloc() calls in TCP_REPAIR
tcp_send_rcvq() is used for re-injecting data into tcp receive queue. Problems : - No check against size is performed, allowed user to fool kernel in attempting very large memory allocations, eventually triggering OOM when memory is fragmented. - In case of fault during the copy we do not return correct errno. Lets use alloc_skb_with_frags() to cook optimal skbs. Fixes:292e8d8c85
("tcp: Move rcvq sending to tcp_input.c") Fixes:c0e88ff0f2
("tcp: Repair socket queues") Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Pavel Emelyanov <xemul@parallels.com> Acked-by: Pavel Emelyanov <xemul@parallels.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
dd52bc2b4e
commit
5d4c9bfbab
@ -4481,19 +4481,34 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int
|
||||
int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err = -ENOMEM;
|
||||
int data_len = 0;
|
||||
bool fragstolen;
|
||||
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
skb = alloc_skb(size, sk->sk_allocation);
|
||||
if (size > PAGE_SIZE) {
|
||||
int npages = min_t(size_t, size >> PAGE_SHIFT, MAX_SKB_FRAGS);
|
||||
|
||||
data_len = npages << PAGE_SHIFT;
|
||||
size = data_len + (size & ~PAGE_MASK);
|
||||
}
|
||||
skb = alloc_skb_with_frags(size - data_len, data_len,
|
||||
PAGE_ALLOC_COSTLY_ORDER,
|
||||
&err, sk->sk_allocation);
|
||||
if (!skb)
|
||||
goto err;
|
||||
|
||||
skb_put(skb, size - data_len);
|
||||
skb->data_len = data_len;
|
||||
skb->len = size;
|
||||
|
||||
if (tcp_try_rmem_schedule(sk, skb, skb->truesize))
|
||||
goto err_free;
|
||||
|
||||
if (memcpy_from_msg(skb_put(skb, size), msg, size))
|
||||
err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size);
|
||||
if (err)
|
||||
goto err_free;
|
||||
|
||||
TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt;
|
||||
@ -4509,7 +4524,8 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
|
||||
err_free:
|
||||
kfree_skb(skb);
|
||||
err:
|
||||
return -ENOMEM;
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
|
||||
|
Loading…
Reference in New Issue
Block a user