@@ -879,14 +879,18 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk,
879879 struct tcp_md5sig_key * key ;
880880 struct hlist_node * pos ;
881881 unsigned int size = sizeof (struct in_addr );
882+ struct tcp_md5sig_info * md5sig ;
882883
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 )
884888 return NULL ;
885889#if IS_ENABLED (CONFIG_IPV6 )
886890 if (family == AF_INET6 )
887891 size = sizeof (struct in6_addr );
888892#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 ) {
890894 if (key -> family != family )
891895 continue ;
892896 if (!memcmp (& key -> addr , addr , size ))
@@ -932,15 +936,16 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
932936 return 0 ;
933937 }
934938
935- md5sig = tp -> md5sig_info ;
939+ md5sig = rcu_dereference_protected (tp -> md5sig_info ,
940+ sock_owned_by_user (sk ));
936941 if (!md5sig ) {
937942 md5sig = kmalloc (sizeof (* md5sig ), gfp );
938943 if (!md5sig )
939944 return - ENOMEM ;
940945
941946 sk_nocaps_add (sk , NETIF_F_GSO_MASK );
942947 INIT_HLIST_HEAD (& md5sig -> head );
943- tp -> md5sig_info = md5sig ;
948+ rcu_assign_pointer ( tp -> md5sig_info , md5sig ) ;
944949 }
945950
946951 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)
966971{
967972 struct tcp_sock * tp = tcp_sk (sk );
968973 struct tcp_md5sig_key * key ;
974+ struct tcp_md5sig_info * md5sig ;
969975
970976 key = tcp_md5_do_lookup (sk , (union tcp_md5_addr * )& addr , AF_INET );
971977 if (!key )
972978 return - ENOENT ;
973979 hlist_del_rcu (& key -> node );
974980 atomic_sub (sizeof (* key ), & sk -> sk_omem_alloc );
975981 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 ))
977985 tcp_free_md5sig_pool ();
978986 return 0 ;
979987}
@@ -984,10 +992,13 @@ void tcp_clear_md5_list(struct sock *sk)
984992 struct tcp_sock * tp = tcp_sk (sk );
985993 struct tcp_md5sig_key * key ;
986994 struct hlist_node * pos , * n ;
995+ struct tcp_md5sig_info * md5sig ;
987996
988- if (!hlist_empty (& tp -> md5sig_info -> head ))
997+ md5sig = rcu_dereference_protected (tp -> md5sig_info , 1 );
998+
999+ if (!hlist_empty (& md5sig -> head ))
9891000 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 ) {
9911002 hlist_del_rcu (& key -> node );
9921003 atomic_sub (sizeof (* key ), & sk -> sk_omem_alloc );
9931004 kfree_rcu (key , rcu );
@@ -1009,12 +1020,9 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
10091020 if (sin -> sin_family != AF_INET )
10101021 return - EINVAL ;
10111022
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 )
10151024 return tcp_md5_do_del (sk , (union tcp_md5_addr * )& sin -> sin_addr .s_addr ,
10161025 AF_INET );
1017- }
10181026
10191027 if (cmd .tcpm_keylen > TCP_MD5SIG_MAXKEYLEN )
10201028 return - EINVAL ;
@@ -1896,7 +1904,7 @@ void tcp_v4_destroy_sock(struct sock *sk)
18961904 /* Clean up the MD5 key list, if any */
18971905 if (tp -> md5sig_info ) {
18981906 tcp_clear_md5_list (sk );
1899- kfree (tp -> md5sig_info );
1907+ kfree_rcu (tp -> md5sig_info , rcu );
19001908 tp -> md5sig_info = NULL ;
19011909 }
19021910#endif
0 commit comments