[3.16.y-ckt stable] Patch "net: ping: Return EAFNOSUPPORT when appropriate." has been added to staging queue

Luis Henriques luis.henriques at canonical.com
Thu Mar 19 10:11:39 UTC 2015

This is a note to let you know that I have just added a patch titled

    net: ping: Return EAFNOSUPPORT when appropriate.

to the linux-3.16.y-queue branch of the 3.16.y-ckt extended stable tree 
which can be found at:


This patch is scheduled to be released in version 3.16.7-ckt9.

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.16.y-ckt tree, see



>From ef4b058fe7f6fc0228910b331a9115a4afe6c9b0 Mon Sep 17 00:00:00 2001
From: Lorenzo Colitti <lorenzo at google.com>
Date: Tue, 3 Mar 2015 23:16:16 +0900
Subject: net: ping: Return EAFNOSUPPORT when appropriate.

commit 9145736d4862145684009d6a72a6e61324a9439e upstream.

1. For an IPv4 ping socket, ping_check_bind_addr does not check
   the family of the socket address that's passed in. Instead,
   make it behave like inet_bind, which enforces either that the
   address family is AF_INET, or that the family is AF_UNSPEC and
   the address is
2. For an IPv6 ping socket, ping_check_bind_addr returns EINVAL
   if the socket family is not AF_INET6. Return EAFNOSUPPORT
   instead, for consistency with inet6_bind.
3. Make ping_v4_sendmsg and ping_v6_sendmsg return EAFNOSUPPORT
   instead of EINVAL if an incorrect socket address structure is
   passed in.
4. Make IPv6 ping sockets be IPv6-only. The code does not support
   IPv4, and it cannot easily be made to support IPv4 because
   the protocol numbers for ICMP and ICMPv6 are different. This
   makes connect(::ffff: fail with EAFNOSUPPORT instead
   of making the socket unusable.

Among other things, this fixes an oops that can be triggered by:

    int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
    struct sockaddr_in6 sin6 = {
        .sin6_family = AF_INET6,
        .sin6_addr = in6addr_any,
    bind(s, (struct sockaddr *) &sin6, sizeof(sin6));

Change-Id: If06ca86d9f1e4593c0d6df174caca3487c57a241
Signed-off-by: Lorenzo Colitti <lorenzo at google.com>
Signed-off-by: David S. Miller <davem at davemloft.net>
[ luis: backported to 3.16: based on davem's backport to 3.14 ]
Signed-off-by: Luis Henriques <luis.henriques at canonical.com>
 net/ipv4/ping.c | 14 ++++++++++++--
 net/ipv6/ping.c |  5 +++--
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 7dec0787b4a2..45d5bc0ad86c 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -259,6 +259,11 @@ int ping_init_sock(struct sock *sk)
 	kgid_t low, high;
 	int ret = 0;

+	if (sk->sk_family == AF_INET6)
+		inet6_sk(sk)->ipv6only = 1;
 	inet_get_ping_group_range_net(net, &low, &high);
 	if (gid_lte(low, group) && gid_lte(group, high))
 		return 0;
@@ -305,6 +310,11 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
 		if (addr_len < sizeof(*addr))
 			return -EINVAL;

+		if (addr->sin_family != AF_INET &&
+		    !(addr->sin_family == AF_UNSPEC &&
+		      addr->sin_addr.s_addr == htonl(INADDR_ANY)))
+			return -EAFNOSUPPORT;
 			 sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port));

@@ -330,7 +340,7 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
 			return -EINVAL;

 		if (addr->sin6_family != AF_INET6)
-			return -EINVAL;
+			return -EAFNOSUPPORT;

 			 sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port));
@@ -716,7 +726,7 @@ static int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
 		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 {
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index 5b7a1ed2aba9..2d452a382128 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -102,9 +102,10 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,

 	if (msg->msg_name) {
 		DECLARE_SOCKADDR(struct sockaddr_in6 *, u, msg->msg_name);
-		if (msg->msg_namelen < sizeof(struct sockaddr_in6) ||
-		    u->sin6_family != AF_INET6) {
+		if (msg->msg_namelen < sizeof(*u))
 			return -EINVAL;
+		if (u->sin6_family != AF_INET6) {
+			return -EAFNOSUPPORT;
 		if (sk->sk_bound_dev_if &&
 		    sk->sk_bound_dev_if != u->sin6_scope_id) {

More information about the kernel-team mailing list