All of lore.kernel.org
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: stable@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	patches@lists.linux.dev, Dmitry Safonov <dima@arista.com>,
	Steen Hegelund <Steen.Hegelund@microchip.com>,
	David Ahern <dsahern@kernel.org>,
	"David S. Miller" <davem@davemloft.net>,
	Sasha Levin <sashal@kernel.org>
Subject: [PATCH 6.6 054/156] net/tcp: Prepare tcp_md5sig_pool for TCP-AO
Date: Mon, 17 Aug 2026 15:33:08 +0200	[thread overview]
Message-ID: <20260817132536.701376772@linuxfoundation.org> (raw)
In-Reply-To: <20260817132534.666299318@linuxfoundation.org>

6.6-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Dmitry Safonov <dima@arista.com>

[ Upstream commit 8c73b26315aadb82218360d0a9a05e515f6e4118 ]

TCP-AO, similarly to TCP-MD5, needs to allocate tfms on a slow-path,
which is setsockopt() and use crypto ahash requests on fast paths,
which are RX/TX softirqs. Also, it needs a temporary/scratch buffer
for preparing the hash.

Rework tcp_md5sig_pool in order to support other hashing algorithms
than MD5. It will make it possible to share pre-allocated crypto_ahash
descriptors and scratch area between all TCP hash users.

Internally tcp_sigpool calls crypto_clone_ahash() API over pre-allocated
crypto ahash tfm. Kudos to Herbert, who provided this new crypto API.

I was a little concerned over GFP_ATOMIC allocations of ahash and
crypto_request in RX/TX (see tcp_sigpool_start()), so I benchmarked both
"backends" with different algorithms, using patched version of iperf3[2].
On my laptop with i7-7600U @ 2.80GHz:

                         clone-tfm                per-CPU-requests
TCP-MD5                  2.25 Gbits/sec           2.30 Gbits/sec
TCP-AO(hmac(sha1))       2.53 Gbits/sec           2.54 Gbits/sec
TCP-AO(hmac(sha512))     1.67 Gbits/sec           1.64 Gbits/sec
TCP-AO(hmac(sha384))     1.77 Gbits/sec           1.80 Gbits/sec
TCP-AO(hmac(sha224))     1.29 Gbits/sec           1.30 Gbits/sec
TCP-AO(hmac(sha3-512))    481 Mbits/sec            480 Mbits/sec
TCP-AO(hmac(md5))        2.07 Gbits/sec           2.12 Gbits/sec
TCP-AO(hmac(rmd160))     1.01 Gbits/sec            995 Mbits/sec
TCP-AO(cmac(aes128))     [not supporetd yet]      2.11 Gbits/sec

So, it seems that my concerns don't have strong grounds and per-CPU
crypto_request allocation can be dropped/removed from tcp_sigpool once
ciphers get crypto_clone_ahash() support.

[1]: https://lore.kernel.org/all/ZDefxOq6Ax0JeTRH@gondor.apana.org.au/T/#u
[2]: https://github.com/0x7f454c46/iperf/tree/tcp-md5-ao
Signed-off-by: Dmitry Safonov <dima@arista.com>
Reviewed-by: Steen Hegelund <Steen.Hegelund@microchip.com>
Acked-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Stable-dep-of: d0c80dbb9704 ("net/atm: fix slab-out-of-bounds read in vcc_setsockopt()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/net/tcp.h        |  50 ++++--
 net/ipv4/Kconfig         |   4 +
 net/ipv4/Makefile        |   1 +
 net/ipv4/tcp.c           | 145 +++-------------
 net/ipv4/tcp_ipv4.c      |  97 ++++++-----
 net/ipv4/tcp_minisocks.c |  21 ++-
 net/ipv4/tcp_sigpool.c   | 358 +++++++++++++++++++++++++++++++++++++++
 net/ipv6/tcp_ipv6.c      |  60 +++----
 8 files changed, 525 insertions(+), 211 deletions(-)
 create mode 100644 net/ipv4/tcp_sigpool.c

diff --git a/include/net/tcp.h b/include/net/tcp.h
index a6def0aab3ed3..9c3ec3200e27b 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1730,12 +1730,39 @@ union tcp_md5sum_block {
 #endif
 };
 
-/* - pool: digest algorithm, hash description and scratch buffer */
-struct tcp_md5sig_pool {
-	struct ahash_request	*md5_req;
-	void			*scratch;
+/*
+ * struct tcp_sigpool - per-CPU pool of ahash_requests
+ * @scratch: per-CPU temporary area, that can be used between
+ *	     tcp_sigpool_start() and tcp_sigpool_end() to perform
+ *	     crypto request
+ * @req: pre-allocated ahash request
+ */
+struct tcp_sigpool {
+	void *scratch;
+	struct ahash_request *req;
 };
 
+int tcp_sigpool_alloc_ahash(const char *alg, size_t scratch_size);
+void tcp_sigpool_get(unsigned int id);
+void tcp_sigpool_release(unsigned int id);
+int tcp_sigpool_hash_skb_data(struct tcp_sigpool *hp,
+			      const struct sk_buff *skb,
+			      unsigned int header_len);
+
+/**
+ * tcp_sigpool_start - disable bh and start using tcp_sigpool_ahash
+ * @id: tcp_sigpool that was previously allocated by tcp_sigpool_alloc_ahash()
+ * @c: returned tcp_sigpool for usage (uninitialized on failure)
+ *
+ * Returns 0 on success, error otherwise.
+ */
+int tcp_sigpool_start(unsigned int id, struct tcp_sigpool *c);
+/**
+ * tcp_sigpool_end - enable bh and stop using tcp_sigpool
+ * @c: tcp_sigpool context that was returned by tcp_sigpool_start()
+ */
+void tcp_sigpool_end(struct tcp_sigpool *c);
+size_t tcp_sigpool_algo(unsigned int id, char *buf, size_t buf_len);
 /* - functions */
 int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,
 			const struct sock *sk, const struct sk_buff *skb);
@@ -1791,17 +1818,12 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
 #define tcp_twsk_md5_key(twsk)	NULL
 #endif
 
-bool tcp_alloc_md5sig_pool(void);
-
-struct tcp_md5sig_pool *tcp_get_md5sig_pool(void);
-static inline void tcp_put_md5sig_pool(void)
-{
-	local_bh_enable();
-}
+int tcp_md5_alloc_sigpool(void);
+void tcp_md5_release_sigpool(void);
+void tcp_md5_add_sigpool(void);
+extern int tcp_md5_sigpool_id;
 
-int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, const struct sk_buff *,
-			  unsigned int header_len);
-int tcp_md5_hash_key(struct tcp_md5sig_pool *hp,
+int tcp_md5_hash_key(struct tcp_sigpool *hp,
 		     const struct tcp_md5sig_key *key);
 
 /* From tcp_fastopen.c */
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 2dfb12230f089..89e2ab023272f 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -741,10 +741,14 @@ config DEFAULT_TCP_CONG
 	default "bbr" if DEFAULT_BBR
 	default "cubic"
 
+config TCP_SIGPOOL
+	tristate
+
 config TCP_MD5SIG
 	bool "TCP: MD5 Signature Option support (RFC2385)"
 	select CRYPTO
 	select CRYPTO_MD5
+	select TCP_SIGPOOL
 	help
 	  RFC2385 specifies a method of giving MD5 protection to TCP sessions.
 	  Its main (only?) use is to protect BGP sessions between core routers
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index b18ba8ef93ad2..cd760793cfcba 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o
 obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o
 obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o
 obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
+obj-$(CONFIG_TCP_SIGPOOL) += tcp_sigpool.o
 obj-$(CONFIG_NET_SOCK_MSG) += tcp_bpf.o
 obj-$(CONFIG_BPF_SYSCALL) += udp_bpf.o
 obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 5b1fbb0ca2ff6..f05d1699683ff 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -4365,141 +4365,52 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
 EXPORT_SYMBOL(tcp_getsockopt);
 
 #ifdef CONFIG_TCP_MD5SIG
-static DEFINE_PER_CPU(struct tcp_md5sig_pool, tcp_md5sig_pool);
-static DEFINE_MUTEX(tcp_md5sig_mutex);
-static bool tcp_md5sig_pool_populated = false;
+int tcp_md5_sigpool_id = -1;
+EXPORT_SYMBOL_GPL(tcp_md5_sigpool_id);
 
-static void __tcp_alloc_md5sig_pool(void)
+int tcp_md5_alloc_sigpool(void)
 {
-	struct crypto_ahash *hash;
-	int cpu;
-
-	hash = crypto_alloc_ahash("md5", 0, CRYPTO_ALG_ASYNC);
-	if (IS_ERR(hash))
-		return;
-
-	for_each_possible_cpu(cpu) {
-		void *scratch = per_cpu(tcp_md5sig_pool, cpu).scratch;
-		struct ahash_request *req;
-
-		if (!scratch) {
-			scratch = kmalloc_node(sizeof(union tcp_md5sum_block) +
-					       sizeof(struct tcphdr),
-					       GFP_KERNEL,
-					       cpu_to_node(cpu));
-			if (!scratch)
-				return;
-			per_cpu(tcp_md5sig_pool, cpu).scratch = scratch;
-		}
-		if (per_cpu(tcp_md5sig_pool, cpu).md5_req)
-			continue;
-
-		req = ahash_request_alloc(hash, GFP_KERNEL);
-		if (!req)
-			return;
-
-		ahash_request_set_callback(req, 0, NULL, NULL);
-
-		per_cpu(tcp_md5sig_pool, cpu).md5_req = req;
-	}
-	/* before setting tcp_md5sig_pool_populated, we must commit all writes
-	 * to memory. See smp_rmb() in tcp_get_md5sig_pool()
-	 */
-	smp_wmb();
-	/* Paired with READ_ONCE() from tcp_alloc_md5sig_pool()
-	 * and tcp_get_md5sig_pool().
-	*/
-	WRITE_ONCE(tcp_md5sig_pool_populated, true);
-}
-
-bool tcp_alloc_md5sig_pool(void)
-{
-	/* Paired with WRITE_ONCE() from __tcp_alloc_md5sig_pool() */
-	if (unlikely(!READ_ONCE(tcp_md5sig_pool_populated))) {
-		mutex_lock(&tcp_md5sig_mutex);
-
-		if (!tcp_md5sig_pool_populated)
-			__tcp_alloc_md5sig_pool();
+	size_t scratch_size;
+	int ret;
 
-		mutex_unlock(&tcp_md5sig_mutex);
+	scratch_size = sizeof(union tcp_md5sum_block) + sizeof(struct tcphdr);
+	ret = tcp_sigpool_alloc_ahash("md5", scratch_size);
+	if (ret >= 0) {
+		/* As long as any md5 sigpool was allocated, the return
+		 * id would stay the same. Re-write the id only for the case
+		 * when previously all MD5 keys were deleted and this call
+		 * allocates the first MD5 key, which may return a different
+		 * sigpool id than was used previously.
+		 */
+		WRITE_ONCE(tcp_md5_sigpool_id, ret); /* Avoids the compiler potentially being smart here */
+		return 0;
 	}
-	/* Paired with WRITE_ONCE() from __tcp_alloc_md5sig_pool() */
-	return READ_ONCE(tcp_md5sig_pool_populated);
+	return ret;
 }
-EXPORT_SYMBOL(tcp_alloc_md5sig_pool);
-
 
-/**
- *	tcp_get_md5sig_pool - get md5sig_pool for this user
- *
- *	We use percpu structure, so if we succeed, we exit with preemption
- *	and BH disabled, to make sure another thread or softirq handling
- *	wont try to get same context.
- */
-struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)
+void tcp_md5_release_sigpool(void)
 {
-	local_bh_disable();
-
-	/* Paired with WRITE_ONCE() from __tcp_alloc_md5sig_pool() */
-	if (READ_ONCE(tcp_md5sig_pool_populated)) {
-		/* coupled with smp_wmb() in __tcp_alloc_md5sig_pool() */
-		smp_rmb();
-		return this_cpu_ptr(&tcp_md5sig_pool);
-	}
-	local_bh_enable();
-	return NULL;
+	tcp_sigpool_release(READ_ONCE(tcp_md5_sigpool_id));
 }
-EXPORT_SYMBOL(tcp_get_md5sig_pool);
 
-int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
-			  const struct sk_buff *skb, unsigned int header_len)
+void tcp_md5_add_sigpool(void)
 {
-	struct scatterlist sg;
-	const struct tcphdr *tp = tcp_hdr(skb);
-	struct ahash_request *req = hp->md5_req;
-	unsigned int i;
-	const unsigned int head_data_len = skb_headlen(skb) > header_len ?
-					   skb_headlen(skb) - header_len : 0;
-	const struct skb_shared_info *shi = skb_shinfo(skb);
-	struct sk_buff *frag_iter;
-
-	sg_init_table(&sg, 1);
-
-	sg_set_buf(&sg, ((u8 *) tp) + header_len, head_data_len);
-	ahash_request_set_crypt(req, &sg, NULL, head_data_len);
-	if (crypto_ahash_update(req))
-		return 1;
-
-	for (i = 0; i < shi->nr_frags; ++i) {
-		const skb_frag_t *f = &shi->frags[i];
-		unsigned int offset = skb_frag_off(f);
-		struct page *page = skb_frag_page(f) + (offset >> PAGE_SHIFT);
-
-		sg_set_page(&sg, page, skb_frag_size(f),
-			    offset_in_page(offset));
-		ahash_request_set_crypt(req, &sg, NULL, skb_frag_size(f));
-		if (crypto_ahash_update(req))
-			return 1;
-	}
-
-	skb_walk_frags(skb, frag_iter)
-		if (tcp_md5_hash_skb_data(hp, frag_iter, 0))
-			return 1;
-
-	return 0;
+	tcp_sigpool_get(READ_ONCE(tcp_md5_sigpool_id));
 }
-EXPORT_SYMBOL(tcp_md5_hash_skb_data);
 
-int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, const struct tcp_md5sig_key *key)
+int tcp_md5_hash_key(struct tcp_sigpool *hp,
+		     const struct tcp_md5sig_key *key)
 {
 	u8 keylen = READ_ONCE(key->keylen); /* paired with WRITE_ONCE() in tcp_md5_do_add */
 	struct scatterlist sg;
 
 	sg_init_one(&sg, key->key, keylen);
-	ahash_request_set_crypt(hp->md5_req, &sg, NULL, keylen);
+	ahash_request_set_crypt(hp->req, &sg, NULL, keylen);
 
-	/* We use data_race() because tcp_md5_do_add() might change key->key under us */
-	return data_race(crypto_ahash_update(hp->md5_req));
+	/* We use data_race() because tcp_md5_do_add() might change
+	 * key->key under us
+	 */
+	return data_race(crypto_ahash_update(hp->req));
 }
 EXPORT_SYMBOL(tcp_md5_hash_key);
 
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 868a593d63ad2..0255f149885eb 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1227,10 +1227,6 @@ static int __tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
 	key = sock_kmalloc(sk, sizeof(*key), gfp | __GFP_ZERO);
 	if (!key)
 		return -ENOMEM;
-	if (!tcp_alloc_md5sig_pool()) {
-		sock_kfree_s(sk, key, sizeof(*key));
-		return -ENOMEM;
-	}
 
 	memcpy(key->key, newkey, newkeylen);
 	key->keylen = newkeylen;
@@ -1252,8 +1248,13 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
 	struct tcp_sock *tp = tcp_sk(sk);
 
 	if (!rcu_dereference_protected(tp->md5sig_info, lockdep_sock_is_held(sk))) {
-		if (tcp_md5sig_info_add(sk, GFP_KERNEL))
+		if (tcp_md5_alloc_sigpool())
+			return -ENOMEM;
+
+		if (tcp_md5sig_info_add(sk, GFP_KERNEL)) {
+			tcp_md5_release_sigpool();
 			return -ENOMEM;
+		}
 
 		if (!static_branch_inc(&tcp_md5_needed.key)) {
 			struct tcp_md5sig_info *md5sig;
@@ -1261,6 +1262,7 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
 			md5sig = rcu_dereference_protected(tp->md5sig_info, lockdep_sock_is_held(sk));
 			rcu_assign_pointer(tp->md5sig_info, NULL);
 			kfree_rcu(md5sig, rcu);
+			tcp_md5_release_sigpool();
 			return -EUSERS;
 		}
 	}
@@ -1277,8 +1279,12 @@ int tcp_md5_key_copy(struct sock *sk, const union tcp_md5_addr *addr,
 	struct tcp_sock *tp = tcp_sk(sk);
 
 	if (!rcu_dereference_protected(tp->md5sig_info, lockdep_sock_is_held(sk))) {
-		if (tcp_md5sig_info_add(sk, sk_gfp_mask(sk, GFP_ATOMIC)))
+		tcp_md5_add_sigpool();
+
+		if (tcp_md5sig_info_add(sk, sk_gfp_mask(sk, GFP_ATOMIC))) {
+			tcp_md5_release_sigpool();
 			return -ENOMEM;
+		}
 
 		if (!static_key_fast_inc_not_disabled(&tcp_md5_needed.key.key)) {
 			struct tcp_md5sig_info *md5sig;
@@ -1287,6 +1293,7 @@ int tcp_md5_key_copy(struct sock *sk, const union tcp_md5_addr *addr,
 			net_warn_ratelimited("Too many TCP-MD5 keys in the system\n");
 			rcu_assign_pointer(tp->md5sig_info, NULL);
 			kfree_rcu(md5sig, rcu);
+			tcp_md5_release_sigpool();
 			return -EUSERS;
 		}
 	}
@@ -1386,7 +1393,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, int optname,
 			      cmd.tcpm_key, cmd.tcpm_keylen);
 }
 
-static int tcp_v4_md5_hash_headers(struct tcp_md5sig_pool *hp,
+static int tcp_v4_md5_hash_headers(struct tcp_sigpool *hp,
 				   __be32 daddr, __be32 saddr,
 				   const struct tcphdr *th, int nbytes)
 {
@@ -1406,38 +1413,35 @@ static int tcp_v4_md5_hash_headers(struct tcp_md5sig_pool *hp,
 	_th->check = 0;
 
 	sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th));
-	ahash_request_set_crypt(hp->md5_req, &sg, NULL,
+	ahash_request_set_crypt(hp->req, &sg, NULL,
 				sizeof(*bp) + sizeof(*th));
-	return crypto_ahash_update(hp->md5_req);
+	return crypto_ahash_update(hp->req);
 }
 
 static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
 			       __be32 daddr, __be32 saddr, const struct tcphdr *th)
 {
-	struct tcp_md5sig_pool *hp;
-	struct ahash_request *req;
+	struct tcp_sigpool hp;
 
-	hp = tcp_get_md5sig_pool();
-	if (!hp)
-		goto clear_hash_noput;
-	req = hp->md5_req;
+	if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp))
+		goto clear_hash_nostart;
 
-	if (crypto_ahash_init(req))
+	if (crypto_ahash_init(hp.req))
 		goto clear_hash;
-	if (tcp_v4_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2))
+	if (tcp_v4_md5_hash_headers(&hp, daddr, saddr, th, th->doff << 2))
 		goto clear_hash;
-	if (tcp_md5_hash_key(hp, key))
+	if (tcp_md5_hash_key(&hp, key))
 		goto clear_hash;
-	ahash_request_set_crypt(req, NULL, md5_hash, 0);
-	if (crypto_ahash_final(req))
+	ahash_request_set_crypt(hp.req, NULL, md5_hash, 0);
+	if (crypto_ahash_final(hp.req))
 		goto clear_hash;
 
-	tcp_put_md5sig_pool();
+	tcp_sigpool_end(&hp);
 	return 0;
 
 clear_hash:
-	tcp_put_md5sig_pool();
-clear_hash_noput:
+	tcp_sigpool_end(&hp);
+clear_hash_nostart:
 	memset(md5_hash, 0, 16);
 	return 1;
 }
@@ -1446,9 +1450,8 @@ int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,
 			const struct sock *sk,
 			const struct sk_buff *skb)
 {
-	struct tcp_md5sig_pool *hp;
-	struct ahash_request *req;
 	const struct tcphdr *th = tcp_hdr(skb);
+	struct tcp_sigpool hp;
 	__be32 saddr, daddr;
 
 	if (sk) { /* valid for establish/request sockets */
@@ -1460,30 +1463,28 @@ int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,
 		daddr = iph->daddr;
 	}
 
-	hp = tcp_get_md5sig_pool();
-	if (!hp)
-		goto clear_hash_noput;
-	req = hp->md5_req;
+	if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp))
+		goto clear_hash_nostart;
 
-	if (crypto_ahash_init(req))
+	if (crypto_ahash_init(hp.req))
 		goto clear_hash;
 
-	if (tcp_v4_md5_hash_headers(hp, daddr, saddr, th, skb->len))
+	if (tcp_v4_md5_hash_headers(&hp, daddr, saddr, th, skb->len))
 		goto clear_hash;
-	if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
+	if (tcp_sigpool_hash_skb_data(&hp, skb, th->doff << 2))
 		goto clear_hash;
-	if (tcp_md5_hash_key(hp, key))
+	if (tcp_md5_hash_key(&hp, key))
 		goto clear_hash;
-	ahash_request_set_crypt(req, NULL, md5_hash, 0);
-	if (crypto_ahash_final(req))
+	ahash_request_set_crypt(hp.req, NULL, md5_hash, 0);
+	if (crypto_ahash_final(hp.req))
 		goto clear_hash;
 
-	tcp_put_md5sig_pool();
+	tcp_sigpool_end(&hp);
 	return 0;
 
 clear_hash:
-	tcp_put_md5sig_pool();
-clear_hash_noput:
+	tcp_sigpool_end(&hp);
+clear_hash_nostart:
 	memset(md5_hash, 0, 16);
 	return 1;
 }
@@ -2311,6 +2312,18 @@ static int tcp_v4_init_sock(struct sock *sk)
 	return 0;
 }
 
+#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();
+}
+#endif
+
 void tcp_v4_destroy_sock(struct sock *sk)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
@@ -2335,10 +2348,12 @@ void tcp_v4_destroy_sock(struct sock *sk)
 #ifdef CONFIG_TCP_MD5SIG
 	/* Clean up the MD5 key list, if any */
 	if (tp->md5sig_info) {
+		struct tcp_md5sig_info *md5sig;
+
+		md5sig = rcu_dereference_protected(tp->md5sig_info, 1);
 		tcp_clear_md5_list(sk);
-		kfree_rcu(rcu_dereference_protected(tp->md5sig_info, 1), rcu);
-		tp->md5sig_info = NULL;
-		static_branch_slow_dec_deferred(&tcp_md5_needed);
+		call_rcu(&md5sig->rcu, tcp_md5sig_info_free_rcu);
+		rcu_assign_pointer(tp->md5sig_info, NULL);
 	}
 #endif
 
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 2eea9672ca01e..c3f5e4fc7b210 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -261,10 +261,9 @@ static void tcp_time_wait_init(struct sock *sk, struct tcp_timewait_sock *tcptw)
 		tcptw->tw_md5_key = kmemdup(key, sizeof(*key), GFP_ATOMIC);
 		if (!tcptw->tw_md5_key)
 			return;
-		if (!tcp_alloc_md5sig_pool())
-			goto out_free;
 		if (!static_key_fast_inc_not_disabled(&tcp_md5_needed.key.key))
 			goto out_free;
+		tcp_md5_add_sigpool();
 	}
 	return;
 out_free:
@@ -348,16 +347,26 @@ 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) {
-			kfree_rcu(twsk->tw_md5_key, rcu);
-			static_branch_slow_dec_deferred(&tcp_md5_needed);
-		}
+		if (twsk->tw_md5_key)
+			call_rcu(&twsk->tw_md5_key->rcu, tcp_md5_twsk_free_rcu);
 	}
 #endif
 }
diff --git a/net/ipv4/tcp_sigpool.c b/net/ipv4/tcp_sigpool.c
new file mode 100644
index 0000000000000..65a8eaae2fec6
--- /dev/null
+++ b/net/ipv4/tcp_sigpool.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <crypto/hash.h>
+#include <linux/cpu.h>
+#include <linux/kref.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/percpu.h>
+#include <linux/workqueue.h>
+#include <net/tcp.h>
+
+static size_t __scratch_size;
+static DEFINE_PER_CPU(void __rcu *, sigpool_scratch);
+
+struct sigpool_entry {
+	struct crypto_ahash	*hash;
+	const char		*alg;
+	struct kref		kref;
+	uint16_t		needs_key:1,
+				reserved:15;
+};
+
+#define CPOOL_SIZE (PAGE_SIZE / sizeof(struct sigpool_entry))
+static struct sigpool_entry cpool[CPOOL_SIZE];
+static unsigned int cpool_populated;
+static DEFINE_MUTEX(cpool_mutex);
+
+/* Slow-path */
+struct scratches_to_free {
+	struct rcu_head rcu;
+	unsigned int cnt;
+	void *scratches[];
+};
+
+static void free_old_scratches(struct rcu_head *head)
+{
+	struct scratches_to_free *stf;
+
+	stf = container_of(head, struct scratches_to_free, rcu);
+	while (stf->cnt--)
+		kfree(stf->scratches[stf->cnt]);
+	kfree(stf);
+}
+
+/**
+ * sigpool_reserve_scratch - re-allocates scratch buffer, slow-path
+ * @size: request size for the scratch/temp buffer
+ */
+static int sigpool_reserve_scratch(size_t size)
+{
+	struct scratches_to_free *stf;
+	size_t stf_sz = struct_size(stf, scratches, num_possible_cpus());
+	int cpu, err = 0;
+
+	lockdep_assert_held(&cpool_mutex);
+	if (__scratch_size >= size)
+		return 0;
+
+	stf = kmalloc(stf_sz, GFP_KERNEL);
+	if (!stf)
+		return -ENOMEM;
+	stf->cnt = 0;
+
+	size = max(size, __scratch_size);
+	cpus_read_lock();
+	for_each_possible_cpu(cpu) {
+		void *scratch, *old_scratch;
+
+		scratch = kmalloc_node(size, GFP_KERNEL, cpu_to_node(cpu));
+		if (!scratch) {
+			err = -ENOMEM;
+			break;
+		}
+
+		old_scratch = rcu_replace_pointer(per_cpu(sigpool_scratch, cpu),
+					scratch, lockdep_is_held(&cpool_mutex));
+		if (!cpu_online(cpu) || !old_scratch) {
+			kfree(old_scratch);
+			continue;
+		}
+		stf->scratches[stf->cnt++] = old_scratch;
+	}
+	cpus_read_unlock();
+	if (!err)
+		__scratch_size = size;
+
+	call_rcu(&stf->rcu, free_old_scratches);
+	return err;
+}
+
+static void sigpool_scratch_free(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu)
+		kfree(rcu_replace_pointer(per_cpu(sigpool_scratch, cpu),
+					  NULL, lockdep_is_held(&cpool_mutex)));
+	__scratch_size = 0;
+}
+
+static int __cpool_try_clone(struct crypto_ahash *hash)
+{
+	struct crypto_ahash *tmp;
+
+	tmp = crypto_clone_ahash(hash);
+	if (IS_ERR(tmp))
+		return PTR_ERR(tmp);
+
+	crypto_free_ahash(tmp);
+	return 0;
+}
+
+static int __cpool_alloc_ahash(struct sigpool_entry *e, const char *alg)
+{
+	struct crypto_ahash *cpu0_hash;
+	int ret;
+
+	e->alg = kstrdup(alg, GFP_KERNEL);
+	if (!e->alg)
+		return -ENOMEM;
+
+	cpu0_hash = crypto_alloc_ahash(alg, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(cpu0_hash)) {
+		ret = PTR_ERR(cpu0_hash);
+		goto out_free_alg;
+	}
+
+	e->needs_key = crypto_ahash_get_flags(cpu0_hash) & CRYPTO_TFM_NEED_KEY;
+
+	ret = __cpool_try_clone(cpu0_hash);
+	if (ret)
+		goto out_free_cpu0_hash;
+	e->hash = cpu0_hash;
+	kref_init(&e->kref);
+	return 0;
+
+out_free_cpu0_hash:
+	crypto_free_ahash(cpu0_hash);
+out_free_alg:
+	kfree(e->alg);
+	e->alg = NULL;
+	return ret;
+}
+
+/**
+ * tcp_sigpool_alloc_ahash - allocates pool for ahash requests
+ * @alg: name of async hash algorithm
+ * @scratch_size: reserve a tcp_sigpool::scratch buffer of this size
+ */
+int tcp_sigpool_alloc_ahash(const char *alg, size_t scratch_size)
+{
+	int i, ret;
+
+	/* slow-path */
+	mutex_lock(&cpool_mutex);
+	ret = sigpool_reserve_scratch(scratch_size);
+	if (ret)
+		goto out;
+	for (i = 0; i < cpool_populated; i++) {
+		if (!cpool[i].alg)
+			continue;
+		if (strcmp(cpool[i].alg, alg))
+			continue;
+
+		if (kref_read(&cpool[i].kref) > 0)
+			kref_get(&cpool[i].kref);
+		else
+			kref_init(&cpool[i].kref);
+		ret = i;
+		goto out;
+	}
+
+	for (i = 0; i < cpool_populated; i++) {
+		if (!cpool[i].alg)
+			break;
+	}
+	if (i >= CPOOL_SIZE) {
+		ret = -ENOSPC;
+		goto out;
+	}
+
+	ret = __cpool_alloc_ahash(&cpool[i], alg);
+	if (!ret) {
+		ret = i;
+		if (i == cpool_populated)
+			cpool_populated++;
+	}
+out:
+	mutex_unlock(&cpool_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tcp_sigpool_alloc_ahash);
+
+static void __cpool_free_entry(struct sigpool_entry *e)
+{
+	crypto_free_ahash(e->hash);
+	kfree(e->alg);
+	memset(e, 0, sizeof(*e));
+}
+
+static void cpool_cleanup_work_cb(struct work_struct *work)
+{
+	bool free_scratch = true;
+	unsigned int i;
+
+	mutex_lock(&cpool_mutex);
+	for (i = 0; i < cpool_populated; i++) {
+		if (kref_read(&cpool[i].kref) > 0) {
+			free_scratch = false;
+			continue;
+		}
+		if (!cpool[i].alg)
+			continue;
+		__cpool_free_entry(&cpool[i]);
+	}
+	if (free_scratch)
+		sigpool_scratch_free();
+	mutex_unlock(&cpool_mutex);
+}
+
+static DECLARE_WORK(cpool_cleanup_work, cpool_cleanup_work_cb);
+static void cpool_schedule_cleanup(struct kref *kref)
+{
+	schedule_work(&cpool_cleanup_work);
+}
+
+/**
+ * tcp_sigpool_release - decreases number of users for a pool. If it was
+ * the last user of the pool, releases any memory that was consumed.
+ * @id: tcp_sigpool that was previously allocated by tcp_sigpool_alloc_ahash()
+ */
+void tcp_sigpool_release(unsigned int id)
+{
+	if (WARN_ON_ONCE(id > cpool_populated || !cpool[id].alg))
+		return;
+
+	/* slow-path */
+	kref_put(&cpool[id].kref, cpool_schedule_cleanup);
+}
+EXPORT_SYMBOL_GPL(tcp_sigpool_release);
+
+/**
+ * tcp_sigpool_get - increases number of users (refcounter) for a pool
+ * @id: tcp_sigpool that was previously allocated by tcp_sigpool_alloc_ahash()
+ */
+void tcp_sigpool_get(unsigned int id)
+{
+	if (WARN_ON_ONCE(id > cpool_populated || !cpool[id].alg))
+		return;
+	kref_get(&cpool[id].kref);
+}
+EXPORT_SYMBOL_GPL(tcp_sigpool_get);
+
+int tcp_sigpool_start(unsigned int id, struct tcp_sigpool *c) __cond_acquires(RCU_BH)
+{
+	struct crypto_ahash *hash;
+
+	rcu_read_lock_bh();
+	if (WARN_ON_ONCE(id > cpool_populated || !cpool[id].alg)) {
+		rcu_read_unlock_bh();
+		return -EINVAL;
+	}
+
+	hash = crypto_clone_ahash(cpool[id].hash);
+	if (IS_ERR(hash)) {
+		rcu_read_unlock_bh();
+		return PTR_ERR(hash);
+	}
+
+	c->req = ahash_request_alloc(hash, GFP_ATOMIC);
+	if (!c->req) {
+		crypto_free_ahash(hash);
+		rcu_read_unlock_bh();
+		return -ENOMEM;
+	}
+	ahash_request_set_callback(c->req, 0, NULL, NULL);
+
+	/* Pairs with tcp_sigpool_reserve_scratch(), scratch area is
+	 * valid (allocated) until tcp_sigpool_end().
+	 */
+	c->scratch = rcu_dereference_bh(*this_cpu_ptr(&sigpool_scratch));
+	return 0;
+}
+EXPORT_SYMBOL_GPL(tcp_sigpool_start);
+
+void tcp_sigpool_end(struct tcp_sigpool *c) __releases(RCU_BH)
+{
+	struct crypto_ahash *hash = crypto_ahash_reqtfm(c->req);
+
+	rcu_read_unlock_bh();
+	ahash_request_free(c->req);
+	crypto_free_ahash(hash);
+}
+EXPORT_SYMBOL_GPL(tcp_sigpool_end);
+
+/**
+ * tcp_sigpool_algo - return algorithm of tcp_sigpool
+ * @id: tcp_sigpool that was previously allocated by tcp_sigpool_alloc_ahash()
+ * @buf: buffer to return name of algorithm
+ * @buf_len: size of @buf
+ */
+size_t tcp_sigpool_algo(unsigned int id, char *buf, size_t buf_len)
+{
+	if (WARN_ON_ONCE(id > cpool_populated || !cpool[id].alg))
+		return -EINVAL;
+
+	return strscpy(buf, cpool[id].alg, buf_len);
+}
+EXPORT_SYMBOL_GPL(tcp_sigpool_algo);
+
+/**
+ * tcp_sigpool_hash_skb_data - hash data in skb with initialized tcp_sigpool
+ * @hp: tcp_sigpool pointer
+ * @skb: buffer to add sign for
+ * @header_len: TCP header length for this segment
+ */
+int tcp_sigpool_hash_skb_data(struct tcp_sigpool *hp,
+			      const struct sk_buff *skb,
+			      unsigned int header_len)
+{
+	const unsigned int head_data_len = skb_headlen(skb) > header_len ?
+					   skb_headlen(skb) - header_len : 0;
+	const struct skb_shared_info *shi = skb_shinfo(skb);
+	const struct tcphdr *tp = tcp_hdr(skb);
+	struct ahash_request *req = hp->req;
+	struct sk_buff *frag_iter;
+	struct scatterlist sg;
+	unsigned int i;
+
+	sg_init_table(&sg, 1);
+
+	sg_set_buf(&sg, ((u8 *)tp) + header_len, head_data_len);
+	ahash_request_set_crypt(req, &sg, NULL, head_data_len);
+	if (crypto_ahash_update(req))
+		return 1;
+
+	for (i = 0; i < shi->nr_frags; ++i) {
+		const skb_frag_t *f = &shi->frags[i];
+		unsigned int offset = skb_frag_off(f);
+		struct page *page;
+
+		page = skb_frag_page(f) + (offset >> PAGE_SHIFT);
+		sg_set_page(&sg, page, skb_frag_size(f), offset_in_page(offset));
+		ahash_request_set_crypt(req, &sg, NULL, skb_frag_size(f));
+		if (crypto_ahash_update(req))
+			return 1;
+	}
+
+	skb_walk_frags(skb, frag_iter)
+		if (tcp_sigpool_hash_skb_data(hp, frag_iter, 0))
+			return 1;
+
+	return 0;
+}
+EXPORT_SYMBOL(tcp_sigpool_hash_skb_data);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Per-CPU pool of crypto requests");
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2c579868fe81f..689c0b383ebf9 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -665,7 +665,7 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
 			      cmd.tcpm_key, cmd.tcpm_keylen);
 }
 
-static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp,
+static int tcp_v6_md5_hash_headers(struct tcp_sigpool *hp,
 				   const struct in6_addr *daddr,
 				   const struct in6_addr *saddr,
 				   const struct tcphdr *th, int nbytes)
@@ -686,39 +686,36 @@ static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp,
 	_th->check = 0;
 
 	sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th));
-	ahash_request_set_crypt(hp->md5_req, &sg, NULL,
+	ahash_request_set_crypt(hp->req, &sg, NULL,
 				sizeof(*bp) + sizeof(*th));
-	return crypto_ahash_update(hp->md5_req);
+	return crypto_ahash_update(hp->req);
 }
 
 static int tcp_v6_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
 			       const struct in6_addr *daddr, struct in6_addr *saddr,
 			       const struct tcphdr *th)
 {
-	struct tcp_md5sig_pool *hp;
-	struct ahash_request *req;
+	struct tcp_sigpool hp;
 
-	hp = tcp_get_md5sig_pool();
-	if (!hp)
-		goto clear_hash_noput;
-	req = hp->md5_req;
+	if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp))
+		goto clear_hash_nostart;
 
-	if (crypto_ahash_init(req))
+	if (crypto_ahash_init(hp.req))
 		goto clear_hash;
-	if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2))
+	if (tcp_v6_md5_hash_headers(&hp, daddr, saddr, th, th->doff << 2))
 		goto clear_hash;
-	if (tcp_md5_hash_key(hp, key))
+	if (tcp_md5_hash_key(&hp, key))
 		goto clear_hash;
-	ahash_request_set_crypt(req, NULL, md5_hash, 0);
-	if (crypto_ahash_final(req))
+	ahash_request_set_crypt(hp.req, NULL, md5_hash, 0);
+	if (crypto_ahash_final(hp.req))
 		goto clear_hash;
 
-	tcp_put_md5sig_pool();
+	tcp_sigpool_end(&hp);
 	return 0;
 
 clear_hash:
-	tcp_put_md5sig_pool();
-clear_hash_noput:
+	tcp_sigpool_end(&hp);
+clear_hash_nostart:
 	memset(md5_hash, 0, 16);
 	return 1;
 }
@@ -728,10 +725,9 @@ static int tcp_v6_md5_hash_skb(char *md5_hash,
 			       const struct sock *sk,
 			       const struct sk_buff *skb)
 {
-	const struct in6_addr *saddr, *daddr;
-	struct tcp_md5sig_pool *hp;
-	struct ahash_request *req;
 	const struct tcphdr *th = tcp_hdr(skb);
+	const struct in6_addr *saddr, *daddr;
+	struct tcp_sigpool hp;
 
 	if (sk) { /* valid for establish/request sockets */
 		saddr = &sk->sk_v6_rcv_saddr;
@@ -742,30 +738,28 @@ static int tcp_v6_md5_hash_skb(char *md5_hash,
 		daddr = &ip6h->daddr;
 	}
 
-	hp = tcp_get_md5sig_pool();
-	if (!hp)
-		goto clear_hash_noput;
-	req = hp->md5_req;
+	if (tcp_sigpool_start(tcp_md5_sigpool_id, &hp))
+		goto clear_hash_nostart;
 
-	if (crypto_ahash_init(req))
+	if (crypto_ahash_init(hp.req))
 		goto clear_hash;
 
-	if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, skb->len))
+	if (tcp_v6_md5_hash_headers(&hp, daddr, saddr, th, skb->len))
 		goto clear_hash;
-	if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
+	if (tcp_sigpool_hash_skb_data(&hp, skb, th->doff << 2))
 		goto clear_hash;
-	if (tcp_md5_hash_key(hp, key))
+	if (tcp_md5_hash_key(&hp, key))
 		goto clear_hash;
-	ahash_request_set_crypt(req, NULL, md5_hash, 0);
-	if (crypto_ahash_final(req))
+	ahash_request_set_crypt(hp.req, NULL, md5_hash, 0);
+	if (crypto_ahash_final(hp.req))
 		goto clear_hash;
 
-	tcp_put_md5sig_pool();
+	tcp_sigpool_end(&hp);
 	return 0;
 
 clear_hash:
-	tcp_put_md5sig_pool();
-clear_hash_noput:
+	tcp_sigpool_end(&hp);
+clear_hash_nostart:
 	memset(md5_hash, 0, 16);
 	return 1;
 }
-- 
2.53.0




  parent reply	other threads:[~2026-08-17 14:54 UTC|newest]

Thread overview: 162+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-17 13:32 [PATCH 6.6 000/156] 6.6.152-rc1 review Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 001/156] mount: honour SB_NOUSER in the new mount API Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 002/156] selftests/bpf: Fail unbound UDP on sockmap update Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 003/156] s390/zcrypt: Fix missing mem scrub at clear key import in cca_clr2cipherkey() Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 004/156] NFS: Pin the struct nfs_server during a FREE_STATEID call Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 005/156] ARM: npcm: Fix OF node refcount leaks in SMP setup Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 006/156] ARM: dts: BCM5301X: fix PCIe controller 2 second interrupt Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 007/156] drm/bridge: ps8640: propagate AUX transfer register errors Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 008/156] Revert "net: thunderbolt: Enable end-to-end flow control also in transmit" Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 009/156] bonding: alb: re-check primary_is_promisc under RTNL in bond_alb_monitor Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 010/156] net/mlx5e: TC, Check if flow is PEER before acquiring devcom lock Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 011/156] netfilter: ipset: switch ext_size to atomic64_t Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 012/156] ipvs: avoid out-of-bounds write in ip_vs_nat_icmp Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 013/156] ipvs: return the csum validation for forward hook Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 014/156] btrfs: fix memory leak in btrfs_do_encoded_write() Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 015/156] bpf: Preserve pointer state for commuted arithmetic Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 016/156] net/smc: fix qentry overwrite for CONFIRM_LINK and ADD_LINK_CONT in smc_llc_event_handler() Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 017/156] net/sched: cls_route: fix fastmap use-after-free on filter Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 018/156] net: hisilicon: hix5hd2_gmac: remove redundant NAPI delete Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 019/156] devlink: fix net namespace reference leak in reload Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 020/156] net/mlx5: fw_tracer, return NULL on create error Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 021/156] counter: microchip-tcb-capture: Fix DT channel validation Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 022/156] bpf: tcp: Make mem flags configurable through bpf_iter_tcp_realloc_batch Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 023/156] bpf: tcp: Make sure iter->batch always contains a full bucket snapshot Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 024/156] bpf: tcp: Get rid of st_bucket_done Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 025/156] bpf: tcp: Use bpf_tcp_iter_batch_item for bpf_tcp_iter_state batch items Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 026/156] bpf: tcp: Avoid socket skips and repeats during iteration Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 027/156] bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch() Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 028/156] vhost/vdpa: reject overflowing PA map page counts on 32-bit Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 029/156] tcp: do not change rcv_ssthresh in tcp_measure_rcv_mss() Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 030/156] udp: fix potential use-after-free in tunnel segmentation Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 031/156] net/sched: sch_cake: drop WARN_ON(1) for malformed packets in ACK filter Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 032/156] net/openvswitch: check Ethernet header length in key_extract() Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 033/156] net: sched: cls_api: add skip_sw counter Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 034/156] net: sched: cls_api: add filter counter Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 035/156] net: sched: make skip_sw actually skip software Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 036/156] net: sched: cls_api: fix slab-use-after-free in fl_dump_key Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 037/156] net: sched: refine software bypass handling in tc_run Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 038/156] net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 039/156] hwmon: (nzxt-smart2) Check return value of init_device() in probe Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 040/156] hwmon: (lm25066) Use i2c_get_match_data() Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 041/156] hwmon: (pmbus/lm25066) Fix PMBus coefficient calculations Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 042/156] selftests/ftrace: refactor eprobes test to fix argument checks Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 043/156] bnxt_en: Do not set EOP on RX AGG BDs on 5760X chips Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 044/156] bnxt_en: Disable EOP for TPA on all chips to prevent data corruption Greg Kroah-Hartman
2026-08-17 13:32 ` [PATCH 6.6 045/156] bnxt_en: Fix PTP PPS setting bug Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 046/156] sctp: fix addip_serial increment on ASCONF_ACK allocation failure Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 047/156] tcp: fix TFO max_qlen accounting across reuseport migration Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 048/156] net/ncsi: fix heap OOB read in NCSI_CMD_SEND_CMD payload length Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 049/156] net: prestera: validate firmware header length Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 050/156] net: remove WARN_ON_ONCE() from sk_mc_loop() Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 051/156] net/smc: fix TOCTOU race between smc_listen_out() and listener close Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 052/156] net: thunderbolt: Tear down DMA paths before stopping the rings Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 053/156] ata: pata_sl82c105: fix bridge revision use-after-free Greg Kroah-Hartman
2026-08-17 13:33 ` Greg Kroah-Hartman [this message]
2026-08-17 13:33 ` [PATCH 6.6 055/156] net/tcp: Add TCP-AO config and structures Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 056/156] net/atm: fix slab-out-of-bounds read in vcc_setsockopt() Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 057/156] sctp: clear control chunk transport if it is being removed Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 058/156] tls: dont abort the connection on signal-interrupted sends Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 059/156] hwmon: (corsair-psu) fix possible out-of-bounds access on missing string termination Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 060/156] regulator: devres: add API for reference voltage supplies Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 061/156] hwmon: (ads7828) Fix external VREF regulator handling Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 062/156] net: fec: do not release NULL pages when RX buffer allocation fails Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 063/156] spi: spi-fsl-dspi: Avoid setup_accel logic for DMA transfers Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 064/156] Input: evdev - sanitize event type index when fetching event masks Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 065/156] ALSA: usb-audio: fix OOB write on Type II inbound URBs Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 066/156] usb: atm: cxacru: properly kill rcv_urb on error in cxacru_cm() Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 067/156] thunderbolt: icm: Preserve USB4 proxy data-valid bit Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 068/156] usb: cdnsp: fix incorrect endian conversions for APB timeout register Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 069/156] usb: gadget: f_ncm: Use unsigned int for ndp_index Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 070/156] net: usb: ax88179_178a: fix skb leak in ax88179_tx_fixup() Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 071/156] vt: add permission check for KDSKBMETA ioctl Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 072/156] vt: stabilize tty reference in kbd_keycode with tty_port_tty_get Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 073/156] Input: evdev - fix information leak in evdev_pass_values() Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 074/156] ima: fix out-of-bounds read in xattr_verify() Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 075/156] ipvs: stop estimator after disabled calc phase Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 076/156] ipvs: add totalconns for dest Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 077/156] ipvs: properly update the overload flag on dest edit Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 078/156] ipvs: clear IPv4 options after rebasing tunnel ICMP errors Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 079/156] packet: use consistent hard_header_len in non-ring send paths Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 080/156] packet: use consistent hard_header_len in TX_RING send path Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 081/156] net/packet: reset the MAC header on the packet-socket transmit path Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 082/156] packet: synchronize pressure clearing with ring reconfiguration Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 083/156] net: openvswitch: reallocate update replies for mismatched IDs Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 084/156] net/sched: reject overly deep qdisc hierarchies Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 085/156] net: octeontx2-pf: Fix UB in shift operation Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 086/156] net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 087/156] mac802154: fix netdev use-after-free in beacon worker Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 088/156] netfilter: ebt_nflog: pin the NFLOG backend Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 089/156] net: bridge: mrp: fix uninitialised bytes on the wire Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 090/156] KVM: s390: pci: Fix memory accounting for pinned/unpinned pages Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 091/156] KVM: s390: pci: Fix missing error codes and memory unaccounting Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 092/156] KVM: s390: pci: Fix resource leak on IRQ registration failure Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 093/156] KVM: s390: pci: Fix aisb calculation Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 094/156] dt-bindings: crypto: qcom,ice: Fix missing power-domain and iface clk Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 095/156] futex: Prevent robust futex exit race some more Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 096/156] fortify: refactor test_fortify Makefile to fix some build problems Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 097/156] fortify: Disable -Wstringop-overread in tests Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 098/156] pinctrl: renesas: rzg2l: Use -ENOTSUPP instead of -EOPNOTSUPP Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 099/156] fscrypt: Replace mk_users keyring with simple list Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 100/156] selftests/bpf: Adapt sockmap update error handling Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 101/156] ipv4: Fix fib_nlmsg_size() for RTA_VIA nexthops Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 102/156] ipv4: fix use-after-free in fib_nhc_update_mtu() Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 103/156] mei: pull kvfree out of spinlock Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 104/156] serial: 8250_dma: Clear stale RX state on shutdown Greg Kroah-Hartman
2026-08-17 13:33 ` [PATCH 6.6 105/156] staging: rtl8723bs: fix OOB read in rtw_get_wpa_ie() Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 106/156] staging: rtl8723bs: fix OOB read in WMM_param_handler() Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 107/156] staging: rtl8723bs: fix missing shared-key auth challenge length check Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 108/156] staging: rtl8723bs: validate monitor transmit frame lengths Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 109/156] misc: fastrpc: fix channel ctx ref leak when session alloc fails Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 110/156] misc: fastrpc: Remove buffer from list prior to unmap operation Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 111/156] misc: fastrpc: take fl->lock when moving mmaps on interrupted invoke Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 112/156] misc: fastrpc: fix memory leak in fastrpc_channel_ctx_free Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 113/156] ring-buffer: Fix crash passing ERR_PTR to kthread_stop() Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 114/156] ALSA: usb: Fix UAF at delayed release of MIDI2 EPs Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 115/156] ALSA: usx2y: bound the hwdep mmap fault offset Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 116/156] tracing: Fix race between update_event_fields and, event_define_fields Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 117/156] fbdev: bitblit: bound-check glyph index in bit_cursor() Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 118/156] net: smc: fix splice entry lifetime imbalance in smc_rx_splice Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 119/156] ipv6: prevent in6_dev_get() from resurrecting inet6_dev Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 120/156] netfilter: bridge: release template ct on non-IP path Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 121/156] netfilter: nf_conntrack: defer invalid log until after unlock Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 122/156] net: atlantic: free stranded TX buffers on ring deinit Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 123/156] net: atlantic: free RX pages of consumed but not refilled buffers Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 124/156] net/sched: act_ct: fix sk_buff leak when the header checks reject a packet Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 125/156] net/sched: act_gact, act_police: range check the fallback control action Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 126/156] ovl: dont warn when the mount is completed from another user namespace Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 127/156] Revert "drm/amdgpu: fix aperture mapping leak" Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 128/156] xdp: reject clones that overrun skb_shared_info tailroom Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 129/156] vxlan: do not arm the ageing timer on a device that is down Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 130/156] vsock/virtio: read virtqueues under worker locks Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 131/156] vsock/virtio: avoid refilling the RX queue after teardown Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 132/156] veth: fix skb length accounting after XDP frag adjustment Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 133/156] vhost: reset the vring metadata cache on vring reconfiguration Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 134/156] tls: dont leave a full plaintext sk_msg ring unpushed Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 135/156] tipc: read le->link under the node lock in tipc_node_link_down() Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 136/156] smb: client: Fix use-after-free in cifs_try_adding_channels() Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 137/156] KVM: x86/mmu: WARN and clear role.invalid when creating a child shadow page Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 138/156] eventfs: Fix use-after-free in eventfs_remove_rec() Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 139/156] eventfs: Use children field for rcu head and add memory barriers Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 140/156] Revert "thermal/drivers/hwmon: Cleanup coding style a bit" Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 141/156] ptp: ocp: Fix board ID over-read Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 142/156] ring-buffer: Use current_context for safe per-CPU buffer swap Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 143/156] ipv6: fix Route Information option length validation Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 144/156] ip6_tunnel: clear skb2->cb[] in ip6ip6_err() Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 145/156] fscrypt: use the mount idmap for the owner check in fscrypt_ioctl_set_policy() Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 146/156] sched/psi: Shut down rtpoll_timer in psi_cgroup_free() Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 147/156] bpf, sockmap: Fix sk_redir use-after-free in send verdict Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 148/156] scsi: scsi_debug: Negate wrapped memcmp() result Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 149/156] sctp: keep chunk->transport in step with the list it is queued on Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 150/156] sctp: fix use-after-free of cached ASCONF chunk Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 151/156] sctp: clear new_transport when removing a peer Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 152/156] thunderbolt: Bound the DROM dual link port number before indexing sw->ports Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 153/156] bpf: tcp: fix double sock release on batch realloc Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 154/156] net/tcp_sigpool: Fix some off by one bugs Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 155/156] net/tcp_sigpool: Use kref_get_unless_zero() Greg Kroah-Hartman
2026-08-17 13:34 ` [PATCH 6.6 156/156] regulator: devres: fix devm_regulator_get_enable_read_voltage() return Greg Kroah-Hartman
2026-08-17 17:54 ` [PATCH 6.6 000/156] 6.6.152-rc1 review Peter Schneider
2026-08-17 17:58 ` Pavel Machek
2026-08-17 21:07 ` Florian Fainelli
2026-08-17 21:19 ` Florian Fainelli
2026-08-18  1:53 ` Wentao Guan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260817132536.701376772@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=Steen.Hegelund@microchip.com \
    --cc=davem@davemloft.net \
    --cc=dima@arista.com \
    --cc=dsahern@kernel.org \
    --cc=patches@lists.linux.dev \
    --cc=sashal@kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.