| @@ -80,6 +80,7 @@ · 79 unmodified lines |
| 80 | 80 | #include <linux/stddef.h> |
| 81 | 81 | #include <linux/proc_fs.h> |
| 82 | 82 | #include <linux/seq_file.h> |
| 83 | +#include <linux/inetdevice.h> |
| 83 | 84 | |
| 84 | 85 | #include <crypto/hash.h> |
| 85 | 86 | #include <linux/scatterlist.h> |
| @@ -908,6 +909,9 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, · 822 unmodified lines |
| 908 | 909 | struct tcp_md5sig_key *key; |
| 909 | 910 | unsigned int size = sizeof(struct in_addr); |
| 910 | 911 | const struct tcp_md5sig_info *md5sig; |
| 912 | + __be32 mask; |
| 913 | + struct tcp_md5sig_key *best_match = NULL; |
| 914 | + bool match; |
| 911 | 915 | |
| 912 | 916 | /* caller either holds rcu_read_lock() or socket lock */ |
| 913 | 917 | md5sig = rcu_dereference_check(tp->md5sig_info, |
| @@ -921,12 +925,55 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, · 7 unmodified lines |
| 921 | 925 | hlist_for_each_entry_rcu(key, &md5sig->head, node) { |
| 922 | 926 | if (key->family != family) |
| 923 | 927 | continue; |
| 924 | | − if (!memcmp(&key->addr, addr, size)) |
| 928 | + |
| 929 | + if (family == AF_INET) { |
| 930 | + mask = inet_make_mask(key->prefixlen); |
| 931 | + match = (key->addr.a4.s_addr & mask) == |
| 932 | + (addr->a4.s_addr & mask); |
| 933 | +#if IS_ENABLED(CONFIG_IPV6) |
| 934 | + } else if (family == AF_INET6) { |
| 935 | + match = ipv6_prefix_equal(&key->addr.a6, &addr->a6, |
| 936 | + key->prefixlen); |
| 937 | +#endif |
| 938 | + } else { |
| 939 | + match = false; |
| 940 | + } |
| 941 | + |
| 942 | + if (match && (!best_match || |
| 943 | + key->prefixlen > best_match->prefixlen)) |
| 944 | + best_match = key; |
| 945 | + } |
| 946 | + return best_match; |
| 947 | +} |
| 948 | +EXPORT_SYMBOL(tcp_md5_do_lookup); |
| 949 | + |
| 950 | +struct tcp_md5sig_key *tcp_md5_do_lookup_exact(const struct sock *sk, |
| 951 | + const union tcp_md5_addr *addr, |
| 952 | + int family, u8 prefixlen) |
| 953 | +{ |
| 954 | + const struct tcp_sock *tp = tcp_sk(sk); |
| 955 | + struct tcp_md5sig_key *key; |
| 956 | + unsigned int size = sizeof(struct in_addr); |
| 957 | + const struct tcp_md5sig_info *md5sig; |
| 958 | + |
| 959 | + /* caller either holds rcu_read_lock() or socket lock */ |
| 960 | + md5sig = rcu_dereference_check(tp->md5sig_info, |
| 961 | + lockdep_sock_is_held(sk)); |
| 962 | + if (!md5sig) |
| 963 | + return NULL; |
| 964 | +#if IS_ENABLED(CONFIG_IPV6) |
| 965 | + if (family == AF_INET6) |
| 966 | + size = sizeof(struct in6_addr); |
| 967 | +#endif |
| 968 | + hlist_for_each_entry_rcu(key, &md5sig->head, node) { |
| 969 | + if (key->family != family) |
| 970 | + continue; |
| 971 | + if (!memcmp(&key->addr, addr, size) && |
| 972 | + key->prefixlen == prefixlen) |
| 925 | 973 | return key; |
| 926 | 974 | } |
| 927 | 975 | return NULL; |
| 928 | 976 | } |
| 929 | | −EXPORT_SYMBOL(tcp_md5_do_lookup); |
| 930 | 977 | |
| 931 | 978 | struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk, |
| 932 | 979 | const struct sock *addr_sk) |
| @@ -940,14 +987,15 @@ EXPORT_SYMBOL(tcp_v4_md5_lookup); · 7 unmodified lines |
| 940 | 987 | |
| 941 | 988 | /* This can be called on a newly created socket, from other files */ |
| 942 | 989 | int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, |
| 943 | | − int family, const u8 *newkey, u8 newkeylen, gfp_t gfp) |
| 990 | + int family, u8 prefixlen, const u8 *newkey, u8 newkeylen, |
| 991 | + gfp_t gfp) |
| 944 | 992 | { |
| 945 | 993 | /* Add Key to the list */ |
| 946 | 994 | struct tcp_md5sig_key *key; |
| 947 | 995 | struct tcp_sock *tp = tcp_sk(sk); |
| 948 | 996 | struct tcp_md5sig_info *md5sig; |
| 949 | 997 | |
| 950 | | − key = tcp_md5_do_lookup(sk, addr, family); |
| 998 | + key = tcp_md5_do_lookup_exact(sk, addr, family, prefixlen); |
| 951 | 999 | if (key) { |
| 952 | 1000 | /* Pre-existing entry - just update that one. */ |
| 953 | 1001 | memcpy(key->key, newkey, newkeylen); |
| @@ -978,6 +1026,7 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, · 24 unmodified lines |
| 978 | 1026 | memcpy(key->key, newkey, newkeylen); |
| 979 | 1027 | key->keylen = newkeylen; |
| 980 | 1028 | key->family = family; |
| 1029 | + key->prefixlen = prefixlen; |
| 981 | 1030 | memcpy(&key->addr, addr, |
| 982 | 1031 | (family == AF_INET6) ? sizeof(struct in6_addr) : |
| 983 | 1032 | sizeof(struct in_addr)); |
| @@ -986,11 +1035,12 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, · 2 unmodified lines |
| 986 | 1035 | } |
| 987 | 1036 | EXPORT_SYMBOL(tcp_md5_do_add); |
| 988 | 1037 | |
| 989 | | −int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family) |
| 1038 | +int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family, |
| 1039 | + u8 prefixlen) |
| 990 | 1040 | { |
| 991 | 1041 | struct tcp_md5sig_key *key; |
| 992 | 1042 | |
| 993 | | − key = tcp_md5_do_lookup(sk, addr, family); |
| 1043 | + key = tcp_md5_do_lookup_exact(sk, addr, family, prefixlen); |
| 994 | 1044 | if (!key) |
| 995 | 1045 | return -ENOENT; |
| 996 | 1046 | hlist_del_rcu(&key->node); |
| @@ -1033,13 +1083,13 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, · 36 unmodified lines |
| 1033 | 1083 | |
| 1034 | 1084 | if (!cmd.tcpm_keylen) |
| 1035 | 1085 | return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, |
| 1036 | | − AF_INET); |
| 1086 | + AF_INET, 32); |
| 1037 | 1087 | |
| 1038 | 1088 | if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) |
| 1039 | 1089 | return -EINVAL; |
| 1040 | 1090 | |
| 1041 | 1091 | return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, |
| 1042 | | − AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, |
| 1092 | + AF_INET, 32, cmd.tcpm_key, cmd.tcpm_keylen, |
| 1043 | 1093 | GFP_KERNEL); |
| 1044 | 1094 | } |
| 1045 | 1095 | |
| @@ -1342,7 +1392,7 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, · 296 unmodified lines |
| 1342 | 1392 | * across. Shucks. |
| 1343 | 1393 | */ |
| 1344 | 1394 | tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newinet->inet_daddr, |
| 1345 | | − AF_INET, key->key, key->keylen, GFP_ATOMIC); |
| 1395 | + AF_INET, 32, key->key, key->keylen, GFP_ATOMIC); |
| 1346 | 1396 | sk_nocaps_add(newsk, NETIF_F_GSO_MASK); |
| 1347 | 1397 | } |
| 1348 | 1398 | #endif |