mirror of https://github.com/torvalds/linux.git
tcp: Free TCP-AO/TCP-MD5 info/keys without RCU
Now that the destruction of info/keys is delayed until the socket destructor, it's safe to use kfree() without an RCU callback. The socket is in TCP_CLOSE state either because it never left it, or it's already closed and the refcounter is zero. In any way, no one can discover it anymore, it's safe to release memory straight away. Similar thing was possible for twsk already. Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Signed-off-by: Dmitry Safonov <dima@arista.com> Link: https://patch.msgid.link/20250909-b4-tcp-ao-md5-rst-finwait2-v5-2-9ffaaaf8b236@arista.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
9e472d9e84
commit
51e547e8c8
|
|
@ -130,7 +130,6 @@ struct tcp_ao_info {
|
|||
u32 snd_sne;
|
||||
u32 rcv_sne;
|
||||
refcount_t refcnt; /* Protects twsk destruction */
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
|
|
|
|||
|
|
@ -413,27 +413,16 @@ static u64 tcp_compute_delivery_rate(const struct tcp_sock *tp)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
static void tcp_md5sig_info_free_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct tcp_md5sig_info *md5sig;
|
||||
|
||||
md5sig = container_of(head, struct tcp_md5sig_info, rcu);
|
||||
kfree(md5sig);
|
||||
static_branch_slow_dec_deferred(&tcp_md5_needed);
|
||||
tcp_md5_release_sigpool();
|
||||
}
|
||||
|
||||
void tcp_md5_destruct_sock(struct sock *sk)
|
||||
{
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
|
||||
if (tp->md5sig_info) {
|
||||
struct tcp_md5sig_info *md5sig;
|
||||
|
||||
md5sig = rcu_dereference_protected(tp->md5sig_info, 1);
|
||||
tcp_clear_md5_list(sk);
|
||||
rcu_assign_pointer(tp->md5sig_info, NULL);
|
||||
call_rcu(&md5sig->rcu, tcp_md5sig_info_free_rcu);
|
||||
kfree(rcu_replace_pointer(tp->md5sig_info, NULL, 1));
|
||||
static_branch_slow_dec_deferred(&tcp_md5_needed);
|
||||
tcp_md5_release_sigpool();
|
||||
}
|
||||
}
|
||||
EXPORT_IPV6_MOD_GPL(tcp_md5_destruct_sock);
|
||||
|
|
|
|||
|
|
@ -268,9 +268,8 @@ static void tcp_ao_key_free_rcu(struct rcu_head *head)
|
|||
kfree_sensitive(key);
|
||||
}
|
||||
|
||||
static void tcp_ao_info_free_rcu(struct rcu_head *head)
|
||||
static void tcp_ao_info_free(struct tcp_ao_info *ao)
|
||||
{
|
||||
struct tcp_ao_info *ao = container_of(head, struct tcp_ao_info, rcu);
|
||||
struct tcp_ao_key *key;
|
||||
struct hlist_node *n;
|
||||
|
||||
|
|
@ -310,7 +309,7 @@ void tcp_ao_destroy_sock(struct sock *sk, bool twsk)
|
|||
|
||||
if (!twsk)
|
||||
tcp_ao_sk_omem_free(sk, ao);
|
||||
call_rcu(&ao->rcu, tcp_ao_info_free_rcu);
|
||||
tcp_ao_info_free(ao);
|
||||
}
|
||||
|
||||
void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp)
|
||||
|
|
|
|||
|
|
@ -1503,9 +1503,9 @@ void tcp_clear_md5_list(struct sock *sk)
|
|||
md5sig = rcu_dereference_protected(tp->md5sig_info, 1);
|
||||
|
||||
hlist_for_each_entry_safe(key, n, &md5sig->head, node) {
|
||||
hlist_del_rcu(&key->node);
|
||||
hlist_del(&key->node);
|
||||
atomic_sub(sizeof(*key), &sk->sk_omem_alloc);
|
||||
kfree_rcu(key, rcu);
|
||||
kfree(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -377,26 +377,17 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
|
|||
}
|
||||
EXPORT_SYMBOL(tcp_time_wait);
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
static void tcp_md5_twsk_free_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct tcp_md5sig_key *key;
|
||||
|
||||
key = container_of(head, struct tcp_md5sig_key, rcu);
|
||||
kfree(key);
|
||||
static_branch_slow_dec_deferred(&tcp_md5_needed);
|
||||
tcp_md5_release_sigpool();
|
||||
}
|
||||
#endif
|
||||
|
||||
void tcp_twsk_destructor(struct sock *sk)
|
||||
{
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
if (static_branch_unlikely(&tcp_md5_needed.key)) {
|
||||
struct tcp_timewait_sock *twsk = tcp_twsk(sk);
|
||||
|
||||
if (twsk->tw_md5_key)
|
||||
call_rcu(&twsk->tw_md5_key->rcu, tcp_md5_twsk_free_rcu);
|
||||
if (twsk->tw_md5_key) {
|
||||
kfree(twsk->tw_md5_key);
|
||||
static_branch_slow_dec_deferred(&tcp_md5_needed);
|
||||
tcp_md5_release_sigpool();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
tcp_ao_destroy_sock(sk, true);
|
||||
|
|
|
|||
Loading…
Reference in New Issue