]> www.infradead.org Git - users/hch/misc.git/commitdiff
tcp: Free TCP-AO/TCP-MD5 info/keys without RCU
authorDmitry Safonov <dima@arista.com>
Tue, 9 Sep 2025 01:18:51 +0000 (02:18 +0100)
committerJakub Kicinski <kuba@kernel.org>
Fri, 12 Sep 2025 02:05:56 +0000 (19:05 -0700)
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>
include/net/tcp_ao.h
net/ipv4/tcp.c
net/ipv4/tcp_ao.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c

index df655ce6987d3730fea7a6ef0db09c2e27b34f21..1e9e27d6e06ba1be185910d7618ef6453e72ba38 100644 (file)
@@ -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
index 7c6c143017effb1522aa0b250bc90487b4d491c5..7f9c671b1ee0b1736d905efd80e57675cedf1603 100644 (file)
@@ -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);
index bbb8d5f0eae7d3d8887da3fa4d68e248af9060ad..31302be78bc4450b56fa23a390b6d03b2262741d 100644 (file)
@@ -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)
index 17176a5d8638d5850898000db41bb123eff86857..2a06020357297a9c0b2dbd79900be8911a52a17e 100644 (file)
@@ -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);
        }
 }
 
index d1c9e40886463ca308f9f3682c4039f491e7555f..7c2ae07d8d5d2a18d6ce3210cc09ee5d9850ea29 100644 (file)
@@ -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);