| @@ -80,6 +80,7 @@ · 79 unmodified lines |
| 80 | #include <linux/stddef.h> | 80 | #include <linux/stddef.h> |
| 81 | #include <linux/proc_fs.h> | 81 | #include <linux/proc_fs.h> |
| 82 | #include <linux/seq_file.h> | 82 | #include <linux/seq_file.h> |
| | 83 | #include <linux/inetdevice.h> |
| 83 | | 84 | |
| 84 | #include <crypto/hash.h> | 85 | #include <crypto/hash.h> |
| 85 | #include <linux/scatterlist.h> | 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 | struct tcp_md5sig_key *key; | 909 | struct tcp_md5sig_key *key; |
| 909 | unsigned int size = sizeof(struct in_addr); | 910 | unsigned int size = sizeof(struct in_addr); |
| 910 | const struct tcp_md5sig_info *md5sig; | 911 | const struct tcp_md5sig_info *md5sig; |
| | 912 | __be32 mask; |
| | 913 | struct tcp_md5sig_key *best_match = NULL; |
| | 914 | bool match; |
| 911 | | 915 | |
| 912 | /* caller either holds rcu_read_lock() or socket lock */ | 916 | /* caller either holds rcu_read_lock() or socket lock */ |
| 913 | md5sig = rcu_dereference_check(tp->md5sig_info, | 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 | hlist_for_each_entry_rcu(key, &md5sig->head, node) { | 925 | hlist_for_each_entry_rcu(key, &md5sig->head, node) { |
| 922 | if (key->family != family) | 926 | if (key->family != family) |
| 923 | continue; | 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 | return key; | 973 | return key; |
| 926 | } | 974 | } |
| 927 | return NULL; | 975 | return NULL; |
| 928 | } | 976 | } |
| 929 | EXPORT_SYMBOL(tcp_md5_do_lookup); | | |
| 930 | | 977 | |
| 931 | struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk, | 978 | struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk, |
| 932 | const struct sock *addr_sk) | 979 | const struct sock *addr_sk) |
| @@ -940,14 +987,15 @@ EXPORT_SYMBOL(tcp_v4_md5_lookup); · 7 unmodified lines |
| 940 | | 987 | |
| 941 | /* This can be called on a newly created socket, from other files */ | 988 | /* This can be called on a newly created socket, from other files */ |
| 942 | int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, | 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 | /* Add Key to the list */ | 993 | /* Add Key to the list */ |
| 946 | struct tcp_md5sig_key *key; | 994 | struct tcp_md5sig_key *key; |
| 947 | struct tcp_sock *tp = tcp_sk(sk); | 995 | struct tcp_sock *tp = tcp_sk(sk); |
| 948 | struct tcp_md5sig_info *md5sig; | 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 | if (key) { | 999 | if (key) { |
| 952 | /* Pre-existing entry - just update that one. */ | 1000 | /* Pre-existing entry - just update that one. */ |
| 953 | memcpy(key->key, newkey, newkeylen); | 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 | memcpy(key->key, newkey, newkeylen); | 1026 | memcpy(key->key, newkey, newkeylen); |
| 979 | key->keylen = newkeylen; | 1027 | key->keylen = newkeylen; |
| 980 | key->family = family; | 1028 | key->family = family; |
| | 1029 | key->prefixlen = prefixlen; |
| 981 | memcpy(&key->addr, addr, | 1030 | memcpy(&key->addr, addr, |
| 982 | (family == AF_INET6) ? sizeof(struct in6_addr) : | 1031 | (family == AF_INET6) ? sizeof(struct in6_addr) : |
| 983 | sizeof(struct in_addr)); | 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 | EXPORT_SYMBOL(tcp_md5_do_add); | 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 | struct tcp_md5sig_key *key; | 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 | if (!key) | 1044 | if (!key) |
| 995 | return -ENOENT; | 1045 | return -ENOENT; |
| 996 | hlist_del_rcu(&key->node); | 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 | if (!cmd.tcpm_keylen) | 1084 | if (!cmd.tcpm_keylen) |
| 1035 | return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, | 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 | if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) | 1088 | if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) |
| 1039 | return -EINVAL; | 1089 | return -EINVAL; |
| 1040 | | 1090 | |
| 1041 | return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, | 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 | GFP_KERNEL); | 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 | * across. Shucks. | 1392 | * across. Shucks. |
| 1343 | */ | 1393 | */ |
| 1344 | tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newinet->inet_daddr, | 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 | sk_nocaps_add(newsk, NETIF_F_GSO_MASK); | 1396 | sk_nocaps_add(newsk, NETIF_F_GSO_MASK); |
| 1347 | } | 1397 | } |
| 1348 | #endif | 1398 | #endif |