summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-02-08 18:48:21 +0000
committerDavid S. Miller <davem@davemloft.net>2013-02-10 20:39:39 -0500
commit044453b3efdc90bdd5feffe74b99d95dec70ac43 (patch)
tree62f3107f82879cc5aeec7cf02f39f7e37de07a41
parent839c8cc32bc252345f4d5767d2d6cf695f2124ab (diff)
downloadlinux-3.10-044453b3efdc90bdd5feffe74b99d95dec70ac43.tar.gz
linux-3.10-044453b3efdc90bdd5feffe74b99d95dec70ac43.tar.bz2
linux-3.10-044453b3efdc90bdd5feffe74b99d95dec70ac43.zip
arp: fix possible crash in arp_rcv()
We should call skb_share_check() before pskb_may_pull(), or we can crash in pskb_expand_head() Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/arp.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 9547a273b9e..ded146b217f 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -928,24 +928,25 @@ static void parp_redo(struct sk_buff *skb)
static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
- struct arphdr *arp;
+ const struct arphdr *arp;
+
+ if (dev->flags & IFF_NOARP ||
+ skb->pkt_type == PACKET_OTHERHOST ||
+ skb->pkt_type == PACKET_LOOPBACK)
+ goto freeskb;
+
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (!skb)
+ goto out_of_mem;
/* ARP header, plus 2 device addresses, plus 2 IP addresses. */
if (!pskb_may_pull(skb, arp_hdr_len(dev)))
goto freeskb;
arp = arp_hdr(skb);
- if (arp->ar_hln != dev->addr_len ||
- dev->flags & IFF_NOARP ||
- skb->pkt_type == PACKET_OTHERHOST ||
- skb->pkt_type == PACKET_LOOPBACK ||
- arp->ar_pln != 4)
+ if (arp->ar_hln != dev->addr_len || arp->ar_pln != 4)
goto freeskb;
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (skb == NULL)
- goto out_of_mem;
-
memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, skb, dev, NULL, arp_process);