@@ -879,14 +879,18 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk,
879
879
struct tcp_md5sig_key * key ;
880
880
struct hlist_node * pos ;
881
881
unsigned int size = sizeof (struct in_addr );
882
+ struct tcp_md5sig_info * md5sig ;
882
883
883
- if (!tp -> md5sig_info )
884
+ /* caller either holds rcu_read_lock() or socket lock */
885
+ md5sig = rcu_dereference_check (tp -> md5sig_info ,
886
+ sock_owned_by_user (sk ));
887
+ if (!md5sig )
884
888
return NULL ;
885
889
#if IS_ENABLED (CONFIG_IPV6 )
886
890
if (family == AF_INET6 )
887
891
size = sizeof (struct in6_addr );
888
892
#endif
889
- hlist_for_each_entry_rcu (key , pos , & tp -> md5sig_info -> head , node ) {
893
+ hlist_for_each_entry_rcu (key , pos , & md5sig -> head , node ) {
890
894
if (key -> family != family )
891
895
continue ;
892
896
if (!memcmp (& key -> addr , addr , size ))
@@ -932,15 +936,16 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
932
936
return 0 ;
933
937
}
934
938
935
- md5sig = tp -> md5sig_info ;
939
+ md5sig = rcu_dereference_protected (tp -> md5sig_info ,
940
+ sock_owned_by_user (sk ));
936
941
if (!md5sig ) {
937
942
md5sig = kmalloc (sizeof (* md5sig ), gfp );
938
943
if (!md5sig )
939
944
return - ENOMEM ;
940
945
941
946
sk_nocaps_add (sk , NETIF_F_GSO_MASK );
942
947
INIT_HLIST_HEAD (& md5sig -> head );
943
- tp -> md5sig_info = md5sig ;
948
+ rcu_assign_pointer ( tp -> md5sig_info , md5sig ) ;
944
949
}
945
950
946
951
key = sock_kmalloc (sk , sizeof (* key ), gfp );
@@ -966,14 +971,17 @@ int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family)
966
971
{
967
972
struct tcp_sock * tp = tcp_sk (sk );
968
973
struct tcp_md5sig_key * key ;
974
+ struct tcp_md5sig_info * md5sig ;
969
975
970
976
key = tcp_md5_do_lookup (sk , (union tcp_md5_addr * )& addr , AF_INET );
971
977
if (!key )
972
978
return - ENOENT ;
973
979
hlist_del_rcu (& key -> node );
974
980
atomic_sub (sizeof (* key ), & sk -> sk_omem_alloc );
975
981
kfree_rcu (key , rcu );
976
- if (hlist_empty (& tp -> md5sig_info -> head ))
982
+ md5sig = rcu_dereference_protected (tp -> md5sig_info ,
983
+ sock_owned_by_user (sk ));
984
+ if (hlist_empty (& md5sig -> head ))
977
985
tcp_free_md5sig_pool ();
978
986
return 0 ;
979
987
}
@@ -984,10 +992,13 @@ void tcp_clear_md5_list(struct sock *sk)
984
992
struct tcp_sock * tp = tcp_sk (sk );
985
993
struct tcp_md5sig_key * key ;
986
994
struct hlist_node * pos , * n ;
995
+ struct tcp_md5sig_info * md5sig ;
987
996
988
- if (!hlist_empty (& tp -> md5sig_info -> head ))
997
+ md5sig = rcu_dereference_protected (tp -> md5sig_info , 1 );
998
+
999
+ if (!hlist_empty (& md5sig -> head ))
989
1000
tcp_free_md5sig_pool ();
990
- hlist_for_each_entry_safe (key , pos , n , & tp -> md5sig_info -> head , node ) {
1001
+ hlist_for_each_entry_safe (key , pos , n , & md5sig -> head , node ) {
991
1002
hlist_del_rcu (& key -> node );
992
1003
atomic_sub (sizeof (* key ), & sk -> sk_omem_alloc );
993
1004
kfree_rcu (key , rcu );
@@ -1009,12 +1020,9 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
1009
1020
if (sin -> sin_family != AF_INET )
1010
1021
return - EINVAL ;
1011
1022
1012
- if (!cmd .tcpm_key || !cmd .tcpm_keylen ) {
1013
- if (!tcp_sk (sk )-> md5sig_info )
1014
- return - ENOENT ;
1023
+ if (!cmd .tcpm_key || !cmd .tcpm_keylen )
1015
1024
return tcp_md5_do_del (sk , (union tcp_md5_addr * )& sin -> sin_addr .s_addr ,
1016
1025
AF_INET );
1017
- }
1018
1026
1019
1027
if (cmd .tcpm_keylen > TCP_MD5SIG_MAXKEYLEN )
1020
1028
return - EINVAL ;
@@ -1896,7 +1904,7 @@ void tcp_v4_destroy_sock(struct sock *sk)
1896
1904
/* Clean up the MD5 key list, if any */
1897
1905
if (tp -> md5sig_info ) {
1898
1906
tcp_clear_md5_list (sk );
1899
- kfree (tp -> md5sig_info );
1907
+ kfree_rcu (tp -> md5sig_info , rcu );
1900
1908
tp -> md5sig_info = NULL ;
1901
1909
}
1902
1910
#endif
0 commit comments