@@ -1569,15 +1569,16 @@ void sock_map_unhash(struct sock *sk)
15691569 psock = sk_psock (sk );
15701570 if (unlikely (!psock )) {
15711571 rcu_read_unlock ();
1572- if (sk -> sk_prot -> unhash )
1573- sk -> sk_prot -> unhash (sk );
1574- return ;
1572+ saved_unhash = READ_ONCE (sk -> sk_prot )-> unhash ;
1573+ } else {
1574+ saved_unhash = psock -> saved_unhash ;
1575+ sock_map_remove_links (sk , psock );
1576+ rcu_read_unlock ();
15751577 }
1576-
1577- saved_unhash = psock -> saved_unhash ;
1578- sock_map_remove_links (sk , psock );
1579- rcu_read_unlock ();
1580- saved_unhash (sk );
1578+ if (WARN_ON_ONCE (saved_unhash == sock_map_unhash ))
1579+ return ;
1580+ if (saved_unhash )
1581+ saved_unhash (sk );
15811582}
15821583EXPORT_SYMBOL_GPL (sock_map_unhash );
15831584
@@ -1590,17 +1591,18 @@ void sock_map_destroy(struct sock *sk)
15901591 psock = sk_psock_get (sk );
15911592 if (unlikely (!psock )) {
15921593 rcu_read_unlock ();
1593- if (sk -> sk_prot -> destroy )
1594- sk -> sk_prot -> destroy (sk );
1595- return ;
1594+ saved_destroy = READ_ONCE (sk -> sk_prot )-> destroy ;
1595+ } else {
1596+ saved_destroy = psock -> saved_destroy ;
1597+ sock_map_remove_links (sk , psock );
1598+ rcu_read_unlock ();
1599+ sk_psock_stop (psock );
1600+ sk_psock_put (sk , psock );
15961601 }
1597-
1598- saved_destroy = psock -> saved_destroy ;
1599- sock_map_remove_links (sk , psock );
1600- rcu_read_unlock ();
1601- sk_psock_stop (psock );
1602- sk_psock_put (sk , psock );
1603- saved_destroy (sk );
1602+ if (WARN_ON_ONCE (saved_destroy == sock_map_destroy ))
1603+ return ;
1604+ if (saved_destroy )
1605+ saved_destroy (sk );
16041606}
16051607EXPORT_SYMBOL_GPL (sock_map_destroy );
16061608
@@ -1615,16 +1617,21 @@ void sock_map_close(struct sock *sk, long timeout)
16151617 if (unlikely (!psock )) {
16161618 rcu_read_unlock ();
16171619 release_sock (sk );
1618- return sk -> sk_prot -> close (sk , timeout );
1620+ saved_close = READ_ONCE (sk -> sk_prot )-> close ;
1621+ } else {
1622+ saved_close = psock -> saved_close ;
1623+ sock_map_remove_links (sk , psock );
1624+ rcu_read_unlock ();
1625+ sk_psock_stop (psock );
1626+ release_sock (sk );
1627+ cancel_work_sync (& psock -> work );
1628+ sk_psock_put (sk , psock );
16191629 }
1620-
1621- saved_close = psock -> saved_close ;
1622- sock_map_remove_links (sk , psock );
1623- rcu_read_unlock ();
1624- sk_psock_stop (psock );
1625- release_sock (sk );
1626- cancel_work_sync (& psock -> work );
1627- sk_psock_put (sk , psock );
1630+ /* Make sure we do not recurse. This is a bug.
1631+ * Leak the socket instead of crashing on a stack overflow.
1632+ */
1633+ if (WARN_ON_ONCE (saved_close == sock_map_close ))
1634+ return ;
16281635 saved_close (sk , timeout );
16291636}
16301637EXPORT_SYMBOL_GPL (sock_map_close );
0 commit comments