]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
tcp: md5: Allow MD5SIG_FLAG_IFINDEX with ifindex=0
authorLeonard Crestez <cdleonard@gmail.com>
Fri, 15 Oct 2021 07:26:05 +0000 (10:26 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 15 Oct 2021 13:36:57 +0000 (14:36 +0100)
Multiple VRFs are generally meant to be "separate" but right now md5
keys for the default VRF also affect connections inside VRFs if the IP
addresses happen to overlap.

So far the combination of TCP_MD5SIG_FLAG_IFINDEX with tcpm_ifindex == 0
was an error, accept this to mean "key only applies to default VRF".
This is what applications using VRFs for traffic separation want.

Signed-off-by: Leonard Crestez <cdleonard@gmail.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/tcp.h
net/ipv4/tcp_ipv4.c
net/ipv6/tcp_ipv6.c

index 3166dc15d7d634676ad30fdc1e57b7517087bb68..60c384569e9cd6e48fe09b4da5251f6b4c9d5060 100644 (file)
@@ -1576,6 +1576,7 @@ struct tcp_md5sig_key {
        u8                      keylen;
        u8                      family; /* AF_INET or AF_INET6 */
        u8                      prefixlen;
+       u8                      flags;
        union tcp_md5_addr      addr;
        int                     l3index; /* set if key added with L3 scope */
        u8                      key[TCP_MD5SIG_MAXKEYLEN];
@@ -1621,10 +1622,10 @@ struct tcp_md5sig_pool {
 int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,
                        const struct sock *sk, const struct sk_buff *skb);
 int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
-                  int family, u8 prefixlen, int l3index,
+                  int family, u8 prefixlen, int l3index, u8 flags,
                   const u8 *newkey, u8 newkeylen, gfp_t gfp);
 int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr,
-                  int family, u8 prefixlen, int l3index);
+                  int family, u8 prefixlen, int l3index, u8 flags);
 struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk,
                                         const struct sock *addr_sk);
 
index f64b6c8380e894cdbbf7fa2e976b97393f891f95..5b8ce65dfc06789c4363fd49ea3525690bf54198 100644 (file)
@@ -1073,7 +1073,7 @@ struct tcp_md5sig_key *__tcp_md5_do_lookup(const struct sock *sk, int l3index,
                                 lockdep_sock_is_held(sk)) {
                if (key->family != family)
                        continue;
-               if (key->l3index && key->l3index != l3index)
+               if (key->flags & TCP_MD5SIG_FLAG_IFINDEX && key->l3index != l3index)
                        continue;
                if (family == AF_INET) {
                        mask = inet_make_mask(key->prefixlen);
@@ -1098,7 +1098,7 @@ EXPORT_SYMBOL(__tcp_md5_do_lookup);
 static struct tcp_md5sig_key *tcp_md5_do_lookup_exact(const struct sock *sk,
                                                      const union tcp_md5_addr *addr,
                                                      int family, u8 prefixlen,
-                                                     int l3index)
+                                                     int l3index, u8 flags)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
        struct tcp_md5sig_key *key;
@@ -1118,6 +1118,8 @@ static struct tcp_md5sig_key *tcp_md5_do_lookup_exact(const struct sock *sk,
                                 lockdep_sock_is_held(sk)) {
                if (key->family != family)
                        continue;
+               if ((key->flags & TCP_MD5SIG_FLAG_IFINDEX) != (flags & TCP_MD5SIG_FLAG_IFINDEX))
+                       continue;
                if (key->l3index != l3index)
                        continue;
                if (!memcmp(&key->addr, addr, size) &&
@@ -1142,7 +1144,7 @@ EXPORT_SYMBOL(tcp_v4_md5_lookup);
 
 /* This can be called on a newly created socket, from other files */
 int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
-                  int family, u8 prefixlen, int l3index,
+                  int family, u8 prefixlen, int l3index, u8 flags,
                   const u8 *newkey, u8 newkeylen, gfp_t gfp)
 {
        /* Add Key to the list */
@@ -1150,7 +1152,7 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
        struct tcp_sock *tp = tcp_sk(sk);
        struct tcp_md5sig_info *md5sig;
 
-       key = tcp_md5_do_lookup_exact(sk, addr, family, prefixlen, l3index);
+       key = tcp_md5_do_lookup_exact(sk, addr, family, prefixlen, l3index, flags);
        if (key) {
                /* Pre-existing entry - just update that one.
                 * Note that the key might be used concurrently.
@@ -1195,6 +1197,7 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
        key->family = family;
        key->prefixlen = prefixlen;
        key->l3index = l3index;
+       key->flags = flags;
        memcpy(&key->addr, addr,
               (family == AF_INET6) ? sizeof(struct in6_addr) :
                                      sizeof(struct in_addr));
@@ -1204,11 +1207,11 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
 EXPORT_SYMBOL(tcp_md5_do_add);
 
 int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family,
-                  u8 prefixlen, int l3index)
+                  u8 prefixlen, int l3index, u8 flags)
 {
        struct tcp_md5sig_key *key;
 
-       key = tcp_md5_do_lookup_exact(sk, addr, family, prefixlen, l3index);
+       key = tcp_md5_do_lookup_exact(sk, addr, family, prefixlen, l3index, flags);
        if (!key)
                return -ENOENT;
        hlist_del_rcu(&key->node);
@@ -1242,6 +1245,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, int optname,
        const union tcp_md5_addr *addr;
        u8 prefixlen = 32;
        int l3index = 0;
+       u8 flags;
 
        if (optlen < sizeof(cmd))
                return -EINVAL;
@@ -1252,6 +1256,8 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, int optname,
        if (sin->sin_family != AF_INET)
                return -EINVAL;
 
+       flags = cmd.tcpm_flags & TCP_MD5SIG_FLAG_IFINDEX;
+
        if (optname == TCP_MD5SIG_EXT &&
            cmd.tcpm_flags & TCP_MD5SIG_FLAG_PREFIX) {
                prefixlen = cmd.tcpm_prefixlen;
@@ -1259,7 +1265,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, int optname,
                        return -EINVAL;
        }
 
-       if (optname == TCP_MD5SIG_EXT &&
+       if (optname == TCP_MD5SIG_EXT && cmd.tcpm_ifindex &&
            cmd.tcpm_flags & TCP_MD5SIG_FLAG_IFINDEX) {
                struct net_device *dev;
 
@@ -1280,12 +1286,12 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, int optname,
        addr = (union tcp_md5_addr *)&sin->sin_addr.s_addr;
 
        if (!cmd.tcpm_keylen)
-               return tcp_md5_do_del(sk, addr, AF_INET, prefixlen, l3index);
+               return tcp_md5_do_del(sk, addr, AF_INET, prefixlen, l3index, flags);
 
        if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
                return -EINVAL;
 
-       return tcp_md5_do_add(sk, addr, AF_INET, prefixlen, l3index,
+       return tcp_md5_do_add(sk, addr, AF_INET, prefixlen, l3index, flags,
                              cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
 }
 
@@ -1609,7 +1615,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
                 * memory, then we end up not copying the key
                 * across. Shucks.
                 */
-               tcp_md5_do_add(newsk, addr, AF_INET, 32, l3index,
+               tcp_md5_do_add(newsk, addr, AF_INET, 32, l3index, key->flags,
                               key->key, key->keylen, GFP_ATOMIC);
                sk_nocaps_add(newsk, NETIF_F_GSO_MASK);
        }
index 0ce52d46e4f81b221a6acd4a0dd7b0d462dbac7a..b03dd02c9f13c50aa6731174d23d4218859cb49d 100644 (file)
@@ -599,6 +599,7 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr;
        int l3index = 0;
        u8 prefixlen;
+       u8 flags;
 
        if (optlen < sizeof(cmd))
                return -EINVAL;
@@ -609,6 +610,8 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
        if (sin6->sin6_family != AF_INET6)
                return -EINVAL;
 
+       flags = cmd.tcpm_flags & TCP_MD5SIG_FLAG_IFINDEX;
+
        if (optname == TCP_MD5SIG_EXT &&
            cmd.tcpm_flags & TCP_MD5SIG_FLAG_PREFIX) {
                prefixlen = cmd.tcpm_prefixlen;
@@ -619,7 +622,7 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
                prefixlen = ipv6_addr_v4mapped(&sin6->sin6_addr) ? 32 : 128;
        }
 
-       if (optname == TCP_MD5SIG_EXT &&
+       if (optname == TCP_MD5SIG_EXT && cmd.tcpm_ifindex &&
            cmd.tcpm_flags & TCP_MD5SIG_FLAG_IFINDEX) {
                struct net_device *dev;
 
@@ -640,9 +643,9 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
                if (ipv6_addr_v4mapped(&sin6->sin6_addr))
                        return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
                                              AF_INET, prefixlen,
-                                             l3index);
+                                             l3index, flags);
                return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
-                                     AF_INET6, prefixlen, l3index);
+                                     AF_INET6, prefixlen, l3index, flags);
        }
 
        if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN)
@@ -650,12 +653,12 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
 
        if (ipv6_addr_v4mapped(&sin6->sin6_addr))
                return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3],
-                                     AF_INET, prefixlen, l3index,
+                                     AF_INET, prefixlen, l3index, flags,
                                      cmd.tcpm_key, cmd.tcpm_keylen,
                                      GFP_KERNEL);
 
        return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr,
-                             AF_INET6, prefixlen, l3index,
+                             AF_INET6, prefixlen, l3index, flags,
                              cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
 }
 
@@ -1404,7 +1407,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
                 * across. Shucks.
                 */
                tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newsk->sk_v6_daddr,
-                              AF_INET6, 128, l3index, key->key, key->keylen,
+                              AF_INET6, 128, l3index, key->flags, key->key, key->keylen,
                               sk_gfp_mask(sk, GFP_ATOMIC));
        }
 #endif