X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fipv4%2Fping.c;h=dac4aeea39b02166416a659e4ef77f058677ce4a;hb=dc14192ea9e7bfd6a9e21b08ac712360a5552930;hp=d495d4bcd745becbe0d6bda8cebd2eaad0019f34;hpb=a8a695a43272a19b08004a3632da23d03170bd87;p=pandora-kernel.git diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index d495d4bcd745..dac4aeea39b0 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -135,15 +135,17 @@ static void ping_v4_hash(struct sock *sk) static void ping_v4_unhash(struct sock *sk) { struct inet_sock *isk = inet_sk(sk); + pr_debug("ping_v4_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); + write_lock_bh(&ping_table.lock); if (sk_hashed(sk)) { - write_lock_bh(&ping_table.lock); hlist_nulls_del(&sk->sk_nulls_node); + sk_nulls_node_init(&sk->sk_nulls_node); sock_put(sk); isk->inet_num = isk->inet_sport = 0; sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - write_unlock_bh(&ping_table.lock); } + write_unlock_bh(&ping_table.lock); } static struct sock *ping_v4_lookup(struct net *net, u32 saddr, u32 daddr, @@ -257,6 +259,11 @@ static int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; + if (addr->sin_family != AF_INET && + !(addr->sin_family == AF_UNSPEC && + addr->sin_addr.s_addr == htonl(INADDR_ANY))) + return -EAFNOSUPPORT; + pr_debug("ping_v4_bind(sk=%p,sa_addr=%08x,sa_port=%d)\n", sk, addr->sin_addr.s_addr, ntohs(addr->sin_port)); @@ -446,6 +453,8 @@ static int ping_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh, { struct sk_buff *skb = skb_peek(&sk->sk_write_queue); + if (!skb) + return 0; pfh->wcheck = csum_partial((char *)&pfh->icmph, sizeof(struct icmphdr), pfh->wcheck); pfh->icmph.checksum = csum_fold(pfh->wcheck); @@ -476,6 +485,10 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (len > 0xFFFF) return -EMSGSIZE; + /* Must have at least a full ICMP header. */ + if (len < sizeof(struct icmphdr)) + return -EINVAL; + /* * Check the flags. */ @@ -504,7 +517,7 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (msg->msg_namelen < sizeof(*usin)) return -EINVAL; if (usin->sin_family != AF_INET) - return -EINVAL; + return -EAFNOSUPPORT; daddr = usin->sin_addr.s_addr; /* no remote port */ } else { @@ -524,8 +537,10 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (msg->msg_controllen) { err = ip_cmsg_send(sock_net(sk), msg, &ipc); - if (err) + if (unlikely(err)) { + kfree(ipc.opt); return err; + } if (ipc.opt) free = 1; } @@ -716,8 +731,11 @@ void ping_rcv(struct sk_buff *skb) sk = ping_v4_lookup(net, saddr, daddr, ntohs(icmph->un.echo.id), skb->dev->ifindex); if (sk != NULL) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + pr_debug("rcv on socket %p\n", sk); - ping_queue_rcv_skb(sk, skb_get(skb)); + if (skb2) + ping_queue_rcv_skb(sk, skb2); sock_put(sk); return; }