sctp: check ipv6 addr with sk_bound_dev if set
authorXin Long <lucien.xin@gmail.com>
Wed, 16 Nov 2022 20:01:17 +0000 (15:01 -0500)
committerDavid S. Miller <davem@davemloft.net>
Fri, 18 Nov 2022 11:42:54 +0000 (11:42 +0000)
When binding to an ipv6 address, it calls ipv6_chk_addr() to check if
this address is on any dev. If a socket binds to a l3mdev but no dev
is passed to do this check, all l3mdev and slaves will be skipped and
the check will fail.

This patch is to pass the bound_dev to make sure the devices under the
same l3mdev can be returned in ipv6_chk_addr(). When the bound_dev is
not a l3mdev or l3slave, l3mdev_master_dev_rcu() will return NULL in
__ipv6_chk_addr_and_flags(), it will keep compitable with before when
NULL dev was passed.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/sctp/ipv6.c

index d081858..e6274cd 100644 (file)
@@ -680,9 +680,11 @@ static int sctp_v6_is_any(const union sctp_addr *addr)
 /* Should this be available for binding?   */
 static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
 {
-       int type;
-       struct net *net = sock_net(&sp->inet.sk);
        const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr;
+       struct sock *sk = &sp->inet.sk;
+       struct net *net = sock_net(sk);
+       struct net_device *dev = NULL;
+       int type;
 
        type = ipv6_addr_type(in6);
        if (IPV6_ADDR_ANY == type)
@@ -696,8 +698,14 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
        if (!(type & IPV6_ADDR_UNICAST))
                return 0;
 
+       if (sk->sk_bound_dev_if) {
+               dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
+               if (!dev)
+                       return 0;
+       }
+
        return ipv6_can_nonlocal_bind(net, &sp->inet) ||
-              ipv6_chk_addr(net, in6, NULL, 0);
+              ipv6_chk_addr(net, in6, dev, 0);
 }
 
 /* This function checks if the address is a valid address to be used for