diff options
author | Jason Wang <jasowang@redhat.com> | 2012-05-30 17:18:10 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-05-31 18:22:45 -0400 |
commit | cc9b17ad29ecaa20bfe426a8d4dbfb94b13ff1cc (patch) | |
tree | dbf402b10788ab22d1d9d8c14866a910be497c29 | |
parent | 914bec1011a25f65cdc94988a6f974bfb9a3c10d (diff) |
net: sock: validate data_len before allocating skb in sock_alloc_send_pskb()
We need to validate the number of pages consumed by data_len, otherwise frags
array could be overflowed by userspace. So this patch validate data_len and
return -EMSGSIZE when data_len may occupies more frags than MAX_SKB_FRAGS.
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/core/sock.c | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index 653f8c0aedc5..9e5b71fda6ec 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -1592,6 +1592,11 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len, | |||
1592 | gfp_t gfp_mask; | 1592 | gfp_t gfp_mask; |
1593 | long timeo; | 1593 | long timeo; |
1594 | int err; | 1594 | int err; |
1595 | int npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT; | ||
1596 | |||
1597 | err = -EMSGSIZE; | ||
1598 | if (npages > MAX_SKB_FRAGS) | ||
1599 | goto failure; | ||
1595 | 1600 | ||
1596 | gfp_mask = sk->sk_allocation; | 1601 | gfp_mask = sk->sk_allocation; |
1597 | if (gfp_mask & __GFP_WAIT) | 1602 | if (gfp_mask & __GFP_WAIT) |
@@ -1610,14 +1615,12 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len, | |||
1610 | if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { | 1615 | if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { |
1611 | skb = alloc_skb(header_len, gfp_mask); | 1616 | skb = alloc_skb(header_len, gfp_mask); |
1612 | if (skb) { | 1617 | if (skb) { |
1613 | int npages; | ||
1614 | int i; | 1618 | int i; |
1615 | 1619 | ||
1616 | /* No pages, we're done... */ | 1620 | /* No pages, we're done... */ |
1617 | if (!data_len) | 1621 | if (!data_len) |
1618 | break; | 1622 | break; |
1619 | 1623 | ||
1620 | npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT; | ||
1621 | skb->truesize += data_len; | 1624 | skb->truesize += data_len; |
1622 | skb_shinfo(skb)->nr_frags = npages; | 1625 | skb_shinfo(skb)->nr_frags = npages; |
1623 | for (i = 0; i < npages; i++) { | 1626 | for (i = 0; i < npages; i++) { |