broken ping to ipv6 linklocal addresses on debian buster
I am seeing ping failures to IPv6 linklocal addresses with Debian
buster. Easiest example to reproduce is:
$ ping -c1 -w1 ff02::1%eth1
connect: Invalid argument
$ ping -c1 -w1 ff02::1%eth1
PING ff02::01%eth1(ff02::1%eth1) 56 data bytes
64 bytes from fe80::e0:f9ff:fe0c:37%eth1: icmp_seq=1 ttl=64 time=0.059 ms
git bisect traced the failure to
commit b9ef5513c9
("smack: Check address length before reading address family")
Arguably ping is being stupid since the buster version is not setting
the address family properly (ping on stretch for example does):
$ strace -e connect ping6 -c1 -w1 ff02::1%eth1
connect(5, {sa_family=AF_UNSPEC,
sa_data="\4\1\0\0\0\0\377\2\0\0\0\0\0\0\0\0\0\0\0\0\0\1\3\0\0\0"}, 28)
= -1 EINVAL (Invalid argument)
but the command works fine on kernels prior to this commit, so this is
breakage which goes against the Linux paradigm of "don't break userspace"
Cc: stable@vger.kernel.org
Reported-by: David Ahern <dsahern@gmail.com>
Suggested-by: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
security/smack/smack_lsm.c | 41 +++++++++++++++++++----------------------
1 file changed, 19 insertions(+), 22 deletions(-)
This commit is contained in:
parent
d5226fa6db
commit
87fbfffcc8
|
@ -2831,42 +2831,39 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
|
||||||
int addrlen)
|
int addrlen)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
|
||||||
struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap;
|
|
||||||
#endif
|
|
||||||
#ifdef SMACK_IPV6_SECMARK_LABELING
|
|
||||||
struct smack_known *rsp;
|
|
||||||
struct socket_smack *ssp;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (sock->sk == NULL)
|
if (sock->sk == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (sock->sk->sk_family != PF_INET &&
|
||||||
|
(!IS_ENABLED(CONFIG_IPV6) || sock->sk->sk_family != PF_INET6))
|
||||||
|
return 0;
|
||||||
|
if (addrlen < offsetofend(struct sockaddr, sa_family))
|
||||||
|
return 0;
|
||||||
|
if (IS_ENABLED(CONFIG_IPV6) && sap->sa_family == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap;
|
||||||
#ifdef SMACK_IPV6_SECMARK_LABELING
|
#ifdef SMACK_IPV6_SECMARK_LABELING
|
||||||
ssp = sock->sk->sk_security;
|
struct smack_known *rsp;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (sock->sk->sk_family) {
|
if (addrlen < SIN6_LEN_RFC2133)
|
||||||
case PF_INET:
|
return 0;
|
||||||
if (addrlen < sizeof(struct sockaddr_in) ||
|
|
||||||
sap->sa_family != AF_INET)
|
|
||||||
return -EINVAL;
|
|
||||||
rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
|
|
||||||
break;
|
|
||||||
case PF_INET6:
|
|
||||||
if (addrlen < SIN6_LEN_RFC2133 || sap->sa_family != AF_INET6)
|
|
||||||
return -EINVAL;
|
|
||||||
#ifdef SMACK_IPV6_SECMARK_LABELING
|
#ifdef SMACK_IPV6_SECMARK_LABELING
|
||||||
rsp = smack_ipv6host_label(sip);
|
rsp = smack_ipv6host_label(sip);
|
||||||
if (rsp != NULL)
|
if (rsp != NULL) {
|
||||||
|
struct socket_smack *ssp = sock->sk->sk_security;
|
||||||
|
|
||||||
rc = smk_ipv6_check(ssp->smk_out, rsp, sip,
|
rc = smk_ipv6_check(ssp->smk_out, rsp, sip,
|
||||||
SMK_CONNECTING);
|
SMK_CONNECTING);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef SMACK_IPV6_PORT_LABELING
|
#ifdef SMACK_IPV6_PORT_LABELING
|
||||||
rc = smk_ipv6_port_check(sock->sk, sip, SMK_CONNECTING);
|
rc = smk_ipv6_port_check(sock->sk, sip, SMK_CONNECTING);
|
||||||
#endif
|
#endif
|
||||||
break;
|
return rc;
|
||||||
}
|
}
|
||||||
|
if (sap->sa_family != AF_INET || addrlen < sizeof(struct sockaddr_in))
|
||||||
|
return 0;
|
||||||
|
rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue