@@ -1569,15 +1569,16 @@ void sock_map_unhash(struct sock *sk)
1569
1569
psock = sk_psock (sk );
1570
1570
if (unlikely (!psock )) {
1571
1571
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 ();
1575
1577
}
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 );
1581
1582
}
1582
1583
EXPORT_SYMBOL_GPL (sock_map_unhash );
1583
1584
@@ -1590,17 +1591,18 @@ void sock_map_destroy(struct sock *sk)
1590
1591
psock = sk_psock_get (sk );
1591
1592
if (unlikely (!psock )) {
1592
1593
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 );
1596
1601
}
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 );
1604
1606
}
1605
1607
EXPORT_SYMBOL_GPL (sock_map_destroy );
1606
1608
@@ -1615,16 +1617,21 @@ void sock_map_close(struct sock *sk, long timeout)
1615
1617
if (unlikely (!psock )) {
1616
1618
rcu_read_unlock ();
1617
1619
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 );
1619
1629
}
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 ;
1628
1635
saved_close (sk , timeout );
1629
1636
}
1630
1637
EXPORT_SYMBOL_GPL (sock_map_close );
0 commit comments