Commit 630e4576 authored by Maciej Żenczykowski's avatar Maciej Żenczykowski Committed by David S. Miller

net-ipv6: bugfix - raw & sctp - switch to ipv6_can_nonlocal_bind()

Found by virtue of ipv6 raw sockets not honouring the per-socket
IP{,V6}_FREEBIND setting.

Based on hits found via:
  git grep '[.]ip_nonlocal_bind'
We fix both raw ipv6 sockets to honour IP{,V6}_FREEBIND and IP{,V6}_TRANSPARENT,
and we fix sctp sockets to honour IP{,V6}_TRANSPARENT (they already honoured
FREEBIND), and not just the ipv6 'ip_nonlocal_bind' sysctl.

The helper is defined as:
  static inline bool ipv6_can_nonlocal_bind(struct net *net, struct inet_sock *inet) {
    return net->ipv6.sysctl.ip_nonlocal_bind || inet->freebind || inet->transparent;
  }
so this change only widens the accepted opt-outs and is thus a clean bugfix.

I'm not entirely sure what 'fixes' tag to add, since this is AFAICT an ancient bug,
but IMHO this should be applied to stable kernels as far back as possible.
As such I'm adding a 'fixes' tag with the commit that originally added the helper,
which happened in 4.19.  Backporting to older LTS kernels (at least 4.9 and 4.14)
would presumably require open-coding it or backporting the helper as well.

Other possibly relevant commits:
  v4.18-rc6-1502-g83ba4645 net: add helpers checking if socket can be bound to nonlocal address
  v4.18-rc6-1431-gd0c1f011 net/ipv6: allow any source address for sendmsg pktinfo with ip_nonlocal_bind
  v4.14-rc5-271-gb71d21c2 sctp: full support for ipv6 ip_nonlocal_bind & IP_FREEBIND
  v4.7-rc7-1883-g9b974202 sctp: support ipv6 nonlocal bind
  v4.1-12247-g35a256fe ipv6: Nonlocal bind

Cc: Lorenzo Colitti <lorenzo@google.com>
Fixes: 83ba4645 ("net: add helpers checking if socket can be bound to nonlocal address")
Signed-off-by: default avatarMaciej Żenczykowski <maze@google.com>
Reviewed-By: default avatarLorenzo Colitti <lorenzo@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4d51419d
...@@ -298,7 +298,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -298,7 +298,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
*/ */
v4addr = LOOPBACK4_IPV6; v4addr = LOOPBACK4_IPV6;
if (!(addr_type & IPV6_ADDR_MULTICAST) && if (!(addr_type & IPV6_ADDR_MULTICAST) &&
!sock_net(sk)->ipv6.sysctl.ip_nonlocal_bind) { !ipv6_can_nonlocal_bind(sock_net(sk), inet)) {
err = -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr, if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr,
dev, 0)) { dev, 0)) {
......
...@@ -664,8 +664,8 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) ...@@ -664,8 +664,8 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
if (!(type & IPV6_ADDR_UNICAST)) if (!(type & IPV6_ADDR_UNICAST))
return 0; return 0;
return sp->inet.freebind || net->ipv6.sysctl.ip_nonlocal_bind || return ipv6_can_nonlocal_bind(net, &sp->inet) ||
ipv6_chk_addr(net, in6, NULL, 0); ipv6_chk_addr(net, in6, NULL, 0);
} }
/* This function checks if the address is a valid address to be used for /* This function checks if the address is a valid address to be used for
...@@ -954,8 +954,7 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr) ...@@ -954,8 +954,7 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr)
net = sock_net(&opt->inet.sk); net = sock_net(&opt->inet.sk);
rcu_read_lock(); rcu_read_lock();
dev = dev_get_by_index_rcu(net, addr->v6.sin6_scope_id); dev = dev_get_by_index_rcu(net, addr->v6.sin6_scope_id);
if (!dev || !(opt->inet.freebind || if (!dev || !(ipv6_can_nonlocal_bind(net, &opt->inet) ||
net->ipv6.sysctl.ip_nonlocal_bind ||
ipv6_chk_addr(net, &addr->v6.sin6_addr, ipv6_chk_addr(net, &addr->v6.sin6_addr,
dev, 0))) { dev, 0))) {
rcu_read_unlock(); rcu_read_unlock();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment