Skip to content

Commit 5b4a79b

Browse files
jsitnickiAlexei Starovoitov
authored andcommitted
bpf, sockmap: Don't let sock_map_{close,destroy,unhash} call itself
sock_map proto callbacks should never call themselves by design. Protect against bugs like [1] and break out of the recursive loop to avoid a stack overflow in favor of a resource leak. [1] https://lore.kernel.org/all/[email protected]/ Suggested-by: Eric Dumazet <[email protected]> Signed-off-by: Jakub Sitnicki <[email protected]> Acked-by: John Fastabend <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 74bc3a5 commit 5b4a79b

File tree

1 file changed

+34
-27
lines changed

1 file changed

+34
-27
lines changed

net/core/sock_map.c

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}
15821583
EXPORT_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
}
16051607
EXPORT_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
}
16301637
EXPORT_SYMBOL_GPL(sock_map_close);

0 commit comments

Comments
 (0)