--- /dev/null
+From 29f275c3a7c05d81c1b34dc36b9c6f2c1fdebfa8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:34:03 -0700
+Subject: crypto: af_alg - Remove zero-copy support from skcipher and aead
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit ffdd2bc378953b525aca61902534e753f1f8e734 upstream.
+
+The zero-copy support is one of the riskiest aspects of AF_ALG. It
+allows userspace to request cryptographic operations directly on
+pagecache pages of files like the 'su' binary. It also allows userspace
+to concurrently modify the memory which is being operated on, a recipe
+for TOCTOU vulnerabilities.
+
+While zero-copy support is more valuable in other areas of the kernel
+like the frequently used networking and file I/O code, it has far less
+value in AF_ALG, which is a niche UAPI. AF_ALG primarily just exists
+for backwards compatibility with a small set of userspace programs such
+as 'iwd' that haven't yet been fixed to use userspace crypto code.
+
+Originally AF_ALG was intended to be used to access hardware crypto
+accelerators. However, it isn't an efficient interface for that anyway,
+and it turned out to be rarely used in this way in practice.
+
+Thus, the risks of the zero-copy support in AF_ALG vastly outweigh its
+benefits. Let's just remove it.
+
+This commit removes it from the "skcipher" and "aead" algorithm types.
+"hash" will be handled separately.
+
+This is a soft break, not a hard break. Even after this commit, it
+still works to use splice() or sendfile() to transfer data to an AF_ALG
+request socket from a pipe or any file, respectively. What changes is
+just that the kernel now makes an internal, stable copy of the data
+before doing the crypto operation. So performance is slightly reduced,
+but the UAPI isn't broken. And, very importantly, it's much safer.
+
+Tested with libkcapi/test.sh. All its test cases still pass. I also
+verified that this would have prevented the copy.fail exploit as well.
+I also used a custom test program to verify that sendfile() still works.
+
+Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations")
+Fixes: 400c40cf78da ("crypto: algif - add AEAD support")
+Reported-by: Taeyang Lee <0wn@theori.io>
+Link: https://copy.fail/
+Reported-by: Feng Ning <feng@innora.ai>
+Closes: https://lore.kernel.org/r/afYcc-tZFwvZZo76@ans-MacBook-Pro.local
+Reviewed-by: Demi Marie Obenour <demiobenour@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/crypto/userspace-if.rst | 31 ++-------------
+ crypto/af_alg.c | 54 +++++----------------------
+ 2 files changed, 14 insertions(+), 71 deletions(-)
+
+diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst
+index b45dabbf69d685..90dbbd56c4e355 100644
+--- a/Documentation/crypto/userspace-if.rst
++++ b/Documentation/crypto/userspace-if.rst
+@@ -328,33 +328,10 @@ CRYPTO_USER_API_RNG_CAVP option:
+ Zero-Copy Interface
+ -------------------
+
+-In addition to the send/write/read/recv system call family, the AF_ALG
+-interface can be accessed with the zero-copy interface of
+-splice/vmsplice. As the name indicates, the kernel tries to avoid a copy
+-operation into kernel space.
+-
+-The zero-copy operation requires data to be aligned at the page
+-boundary. Non-aligned data can be used as well, but may require more
+-operations of the kernel which would defeat the speed gains obtained
+-from the zero-copy interface.
+-
+-The system-inherent limit for the size of one zero-copy operation is 16
+-pages. If more data is to be sent to AF_ALG, user space must slice the
+-input into segments with a maximum size of 16 pages.
+-
+-Zero-copy can be used with the following code example (a complete
+-working example is provided with libkcapi):
+-
+-::
+-
+- int pipes[2];
+-
+- pipe(pipes);
+- /* input data in iov */
+- vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT);
+- /* opfd is the file descriptor returned from accept() system call */
+- splice(pipes[0], NULL, opfd, NULL, ret, 0);
+- read(opfd, out, outlen);
++AF_ALG used to have zero-copy support, but it was removed due to it being a
++frequent source of vulnerabilities. For backwards compatibility the splice()
++and sendfile() system calls are still supported, but the kernel will make an
++internal copy of the data before passing it to the crypto code.
+
+
+ Setsockopt Interface
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index 6acee8e0041a42..4af79af8d2f1eb 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -972,53 +972,19 @@ EXPORT_SYMBOL_GPL(af_alg_sendmsg);
+ ssize_t af_alg_sendpage(struct socket *sock, struct page *page,
+ int offset, size_t size, int flags)
+ {
+- struct sock *sk = sock->sk;
+- struct alg_sock *ask = alg_sk(sk);
+- struct af_alg_ctx *ctx = ask->private;
+- struct af_alg_tsgl *sgl;
+- int err = -EINVAL;
++ struct bio_vec bvec;
++ struct msghdr msg = {
++ .msg_flags = flags,
++ };
+
+ if (flags & MSG_SENDPAGE_NOTLAST)
+- flags |= MSG_MORE;
+-
+- lock_sock(sk);
+- if (!ctx->more && ctx->used)
+- goto unlock;
+-
+- if (!size)
+- goto done;
+-
+- if (!af_alg_writable(sk)) {
+- err = af_alg_wait_for_wmem(sk, flags);
+- if (err)
+- goto unlock;
+- }
+-
+- err = af_alg_alloc_tsgl(sk);
+- if (err)
+- goto unlock;
+-
+- ctx->merge = 0;
+- sgl = list_entry(ctx->tsgl_list.prev, struct af_alg_tsgl, list);
+-
+- if (sgl->cur)
+- sg_unmark_end(sgl->sg + sgl->cur - 1);
+-
+- sg_mark_end(sgl->sg + sgl->cur);
+-
+- get_page(page);
+- sg_set_page(sgl->sg + sgl->cur, page, size, offset);
+- sgl->cur++;
+- ctx->used += size;
+-
+-done:
+- ctx->more = flags & MSG_MORE;
+-
+-unlock:
+- af_alg_data_wakeup(sk);
+- release_sock(sk);
++ msg.msg_flags |= MSG_MORE;
+
+- return err ?: size;
++ bvec.bv_page = page;
++ bvec.bv_len = size;
++ bvec.bv_offset = offset;
++ iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size);
++ return sock_sendmsg(sock, &msg);
+ }
+ EXPORT_SYMBOL_GPL(af_alg_sendpage);
+
+--
+2.53.0
+
sched-fair-only-update-stats-for-allowed-cpus-when-l.patch
crypto-algif_skcipher-force-synchronous-processing-o.patch
tools-mm-slabinfo-fix-total_objects-attribute-name.patch
+crypto-af_alg-remove-zero-copy-support-from-skcipher.patch
--- /dev/null
+From 2e37a8290326763845d58269349557f0ddbd5edd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:34:03 -0700
+Subject: crypto: af_alg - Remove zero-copy support from skcipher and aead
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit ffdd2bc378953b525aca61902534e753f1f8e734 upstream.
+
+The zero-copy support is one of the riskiest aspects of AF_ALG. It
+allows userspace to request cryptographic operations directly on
+pagecache pages of files like the 'su' binary. It also allows userspace
+to concurrently modify the memory which is being operated on, a recipe
+for TOCTOU vulnerabilities.
+
+While zero-copy support is more valuable in other areas of the kernel
+like the frequently used networking and file I/O code, it has far less
+value in AF_ALG, which is a niche UAPI. AF_ALG primarily just exists
+for backwards compatibility with a small set of userspace programs such
+as 'iwd' that haven't yet been fixed to use userspace crypto code.
+
+Originally AF_ALG was intended to be used to access hardware crypto
+accelerators. However, it isn't an efficient interface for that anyway,
+and it turned out to be rarely used in this way in practice.
+
+Thus, the risks of the zero-copy support in AF_ALG vastly outweigh its
+benefits. Let's just remove it.
+
+This commit removes it from the "skcipher" and "aead" algorithm types.
+"hash" will be handled separately.
+
+This is a soft break, not a hard break. Even after this commit, it
+still works to use splice() or sendfile() to transfer data to an AF_ALG
+request socket from a pipe or any file, respectively. What changes is
+just that the kernel now makes an internal, stable copy of the data
+before doing the crypto operation. So performance is slightly reduced,
+but the UAPI isn't broken. And, very importantly, it's much safer.
+
+Tested with libkcapi/test.sh. All its test cases still pass. I also
+verified that this would have prevented the copy.fail exploit as well.
+I also used a custom test program to verify that sendfile() still works.
+
+Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations")
+Fixes: 400c40cf78da ("crypto: algif - add AEAD support")
+Reported-by: Taeyang Lee <0wn@theori.io>
+Link: https://copy.fail/
+Reported-by: Feng Ning <feng@innora.ai>
+Closes: https://lore.kernel.org/r/afYcc-tZFwvZZo76@ans-MacBook-Pro.local
+Reviewed-by: Demi Marie Obenour <demiobenour@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/crypto/userspace-if.rst | 31 ++-------------
+ crypto/af_alg.c | 54 +++++----------------------
+ 2 files changed, 14 insertions(+), 71 deletions(-)
+
+diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst
+index b45dabbf69d685..90dbbd56c4e355 100644
+--- a/Documentation/crypto/userspace-if.rst
++++ b/Documentation/crypto/userspace-if.rst
+@@ -328,33 +328,10 @@ CRYPTO_USER_API_RNG_CAVP option:
+ Zero-Copy Interface
+ -------------------
+
+-In addition to the send/write/read/recv system call family, the AF_ALG
+-interface can be accessed with the zero-copy interface of
+-splice/vmsplice. As the name indicates, the kernel tries to avoid a copy
+-operation into kernel space.
+-
+-The zero-copy operation requires data to be aligned at the page
+-boundary. Non-aligned data can be used as well, but may require more
+-operations of the kernel which would defeat the speed gains obtained
+-from the zero-copy interface.
+-
+-The system-inherent limit for the size of one zero-copy operation is 16
+-pages. If more data is to be sent to AF_ALG, user space must slice the
+-input into segments with a maximum size of 16 pages.
+-
+-Zero-copy can be used with the following code example (a complete
+-working example is provided with libkcapi):
+-
+-::
+-
+- int pipes[2];
+-
+- pipe(pipes);
+- /* input data in iov */
+- vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT);
+- /* opfd is the file descriptor returned from accept() system call */
+- splice(pipes[0], NULL, opfd, NULL, ret, 0);
+- read(opfd, out, outlen);
++AF_ALG used to have zero-copy support, but it was removed due to it being a
++frequent source of vulnerabilities. For backwards compatibility the splice()
++and sendfile() system calls are still supported, but the kernel will make an
++internal copy of the data before passing it to the crypto code.
+
+
+ Setsockopt Interface
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index bbd47d04f89dc2..8dfb94aa99285b 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -972,53 +972,19 @@ EXPORT_SYMBOL_GPL(af_alg_sendmsg);
+ ssize_t af_alg_sendpage(struct socket *sock, struct page *page,
+ int offset, size_t size, int flags)
+ {
+- struct sock *sk = sock->sk;
+- struct alg_sock *ask = alg_sk(sk);
+- struct af_alg_ctx *ctx = ask->private;
+- struct af_alg_tsgl *sgl;
+- int err = -EINVAL;
++ struct bio_vec bvec;
++ struct msghdr msg = {
++ .msg_flags = flags,
++ };
+
+ if (flags & MSG_SENDPAGE_NOTLAST)
+- flags |= MSG_MORE;
+-
+- lock_sock(sk);
+- if (!ctx->more && ctx->used)
+- goto unlock;
+-
+- if (!size)
+- goto done;
+-
+- if (!af_alg_writable(sk)) {
+- err = af_alg_wait_for_wmem(sk, flags);
+- if (err)
+- goto unlock;
+- }
+-
+- err = af_alg_alloc_tsgl(sk);
+- if (err)
+- goto unlock;
+-
+- ctx->merge = 0;
+- sgl = list_entry(ctx->tsgl_list.prev, struct af_alg_tsgl, list);
+-
+- if (sgl->cur)
+- sg_unmark_end(sgl->sg + sgl->cur - 1);
+-
+- sg_mark_end(sgl->sg + sgl->cur);
+-
+- get_page(page);
+- sg_set_page(sgl->sg + sgl->cur, page, size, offset);
+- sgl->cur++;
+- ctx->used += size;
+-
+-done:
+- ctx->more = flags & MSG_MORE;
+-
+-unlock:
+- af_alg_data_wakeup(sk);
+- release_sock(sk);
++ msg.msg_flags |= MSG_MORE;
+
+- return err ?: size;
++ bvec.bv_page = page;
++ bvec.bv_len = size;
++ bvec.bv_offset = offset;
++ iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size);
++ return sock_sendmsg(sock, &msg);
+ }
+ EXPORT_SYMBOL_GPL(af_alg_sendpage);
+
+--
+2.53.0
+
--- /dev/null
+From 0718d9735384ebc3ddb4911f47722ad272ebd9d5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 19:44:02 -0700
+Subject: crypto: crypto4xx - Remove ahash-related code
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+commit 97855e7f1ccf4917f305baab199edb9f2595ff5b upstream.
+
+The hash implementation in crypto4xx has been disabled since 2009.
+As nobody has tried to fix this remove all the dead code.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/amcc/crypto4xx_alg.c | 106 ---------------------------
+ drivers/crypto/amcc/crypto4xx_core.c | 43 +----------
+ drivers/crypto/amcc/crypto4xx_core.h | 7 --
+ 3 files changed, 1 insertion(+), 155 deletions(-)
+
+diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c
+index ded73224273295..91cecec729f25e 100644
+--- a/drivers/crypto/amcc/crypto4xx_alg.c
++++ b/drivers/crypto/amcc/crypto4xx_alg.c
+@@ -12,9 +12,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/spinlock_types.h>
+ #include <linux/scatterlist.h>
+-#include <linux/crypto.h>
+-#include <linux/hash.h>
+-#include <crypto/internal/hash.h>
+ #include <linux/dma-mapping.h>
+ #include <crypto/algapi.h>
+ #include <crypto/aead.h>
+@@ -616,106 +613,3 @@ int crypto4xx_decrypt_aes_gcm(struct aead_request *req)
+ {
+ return crypto4xx_crypt_aes_gcm(req, true);
+ }
+-
+-/*
+- * HASH SHA1 Functions
+- */
+-static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
+- unsigned int sa_len,
+- unsigned char ha,
+- unsigned char hm)
+-{
+- struct crypto_alg *alg = tfm->__crt_alg;
+- struct crypto4xx_alg *my_alg;
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
+- struct dynamic_sa_hash160 *sa;
+- int rc;
+-
+- my_alg = container_of(__crypto_ahash_alg(alg), struct crypto4xx_alg,
+- alg.u.hash);
+- ctx->dev = my_alg->dev;
+-
+- /* Create SA */
+- if (ctx->sa_in || ctx->sa_out)
+- crypto4xx_free_sa(ctx);
+-
+- rc = crypto4xx_alloc_sa(ctx, sa_len);
+- if (rc)
+- return rc;
+-
+- crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+- sizeof(struct crypto4xx_ctx));
+- sa = (struct dynamic_sa_hash160 *)ctx->sa_in;
+- set_dynamic_sa_command_0(&sa->ctrl, SA_SAVE_HASH, SA_NOT_SAVE_IV,
+- SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
+- SA_NO_HEADER_PROC, ha, SA_CIPHER_ALG_NULL,
+- SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
+- SA_OPCODE_HASH, DIR_INBOUND);
+- set_dynamic_sa_command_1(&sa->ctrl, 0, SA_HASH_MODE_HASH,
+- CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
+- SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+- SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
+- SA_NOT_COPY_HDR);
+- /* Need to zero hash digest in SA */
+- memset(sa->inner_digest, 0, sizeof(sa->inner_digest));
+- memset(sa->outer_digest, 0, sizeof(sa->outer_digest));
+-
+- return 0;
+-}
+-
+-int crypto4xx_hash_init(struct ahash_request *req)
+-{
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- int ds;
+- struct dynamic_sa_ctl *sa;
+-
+- sa = ctx->sa_in;
+- ds = crypto_ahash_digestsize(
+- __crypto_ahash_cast(req->base.tfm));
+- sa->sa_command_0.bf.digest_len = ds >> 2;
+- sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA;
+-
+- return 0;
+-}
+-
+-int crypto4xx_hash_update(struct ahash_request *req)
+-{
+- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- struct scatterlist dst;
+- unsigned int ds = crypto_ahash_digestsize(ahash);
+-
+- sg_init_one(&dst, req->result, ds);
+-
+- return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
+- req->nbytes, NULL, 0, ctx->sa_in,
+- ctx->sa_len, 0, NULL);
+-}
+-
+-int crypto4xx_hash_final(struct ahash_request *req)
+-{
+- return 0;
+-}
+-
+-int crypto4xx_hash_digest(struct ahash_request *req)
+-{
+- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- struct scatterlist dst;
+- unsigned int ds = crypto_ahash_digestsize(ahash);
+-
+- sg_init_one(&dst, req->result, ds);
+-
+- return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
+- req->nbytes, NULL, 0, ctx->sa_in,
+- ctx->sa_len, 0, NULL);
+-}
+-
+-/*
+- * SHA1 Algorithm
+- */
+-int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm)
+-{
+- return crypto4xx_hash_alg_init(tfm, SA_HASH160_LEN, SA_HASH_ALG_SHA1,
+- SA_HASH_MODE_HASH);
+-}
+diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
+index e1556a3582a30e..eeb9546bfec9da 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.c
++++ b/drivers/crypto/amcc/crypto4xx_core.c
+@@ -485,18 +485,6 @@ static void crypto4xx_copy_pkt_to_dst(struct crypto4xx_device *dev,
+ }
+ }
+
+-static void crypto4xx_copy_digest_to_dst(void *dst,
+- struct pd_uinfo *pd_uinfo,
+- struct crypto4xx_ctx *ctx)
+-{
+- struct dynamic_sa_ctl *sa = (struct dynamic_sa_ctl *) ctx->sa_in;
+-
+- if (sa->sa_command_0.bf.hash_alg == SA_HASH_ALG_SHA1) {
+- memcpy(dst, pd_uinfo->sr_va->save_digest,
+- SA_HASH_ALG_SHA1_DIGEST_SIZE);
+- }
+-}
+-
+ static void crypto4xx_ret_sg_desc(struct crypto4xx_device *dev,
+ struct pd_uinfo *pd_uinfo)
+ {
+@@ -549,23 +537,6 @@ static void crypto4xx_cipher_done(struct crypto4xx_device *dev,
+ skcipher_request_complete(req, 0);
+ }
+
+-static void crypto4xx_ahash_done(struct crypto4xx_device *dev,
+- struct pd_uinfo *pd_uinfo)
+-{
+- struct crypto4xx_ctx *ctx;
+- struct ahash_request *ahash_req;
+-
+- ahash_req = ahash_request_cast(pd_uinfo->async_req);
+- ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(ahash_req));
+-
+- crypto4xx_copy_digest_to_dst(ahash_req->result, pd_uinfo, ctx);
+- crypto4xx_ret_sg_desc(dev, pd_uinfo);
+-
+- if (pd_uinfo->state & PD_ENTRY_BUSY)
+- ahash_request_complete(ahash_req, -EINPROGRESS);
+- ahash_request_complete(ahash_req, 0);
+-}
+-
+ static void crypto4xx_aead_done(struct crypto4xx_device *dev,
+ struct pd_uinfo *pd_uinfo,
+ struct ce_pd *pd)
+@@ -642,9 +613,6 @@ static void crypto4xx_pd_done(struct crypto4xx_device *dev, u32 idx)
+ case CRYPTO_ALG_TYPE_AEAD:
+ crypto4xx_aead_done(dev, pd_uinfo, pd);
+ break;
+- case CRYPTO_ALG_TYPE_AHASH:
+- crypto4xx_ahash_done(dev, pd_uinfo);
+- break;
+ }
+ }
+
+@@ -915,8 +883,7 @@ int crypto4xx_build_pd(struct crypto_async_request *req,
+ }
+
+ pd->pd_ctl.w = PD_CTL_HOST_READY |
+- ((crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AHASH) ||
+- (crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AEAD) ?
++ ((crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AEAD) ?
+ PD_CTL_HASH_FINAL : 0);
+ pd->pd_ctl_len.w = 0x00400000 | (assoclen + datalen);
+ pd_uinfo->state = PD_ENTRY_INUSE | (is_busy ? PD_ENTRY_BUSY : 0);
+@@ -1022,10 +989,6 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
+ rc = crypto_register_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_AHASH:
+- rc = crypto_register_ahash(&alg->alg.u.hash);
+- break;
+-
+ case CRYPTO_ALG_TYPE_RNG:
+ rc = crypto_register_rng(&alg->alg.u.rng);
+ break;
+@@ -1051,10 +1014,6 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
+ list_for_each_entry_safe(alg, tmp, &sec_dev->alg_list, entry) {
+ list_del(&alg->entry);
+ switch (alg->alg.type) {
+- case CRYPTO_ALG_TYPE_AHASH:
+- crypto_unregister_ahash(&alg->alg.u.hash);
+- break;
+-
+ case CRYPTO_ALG_TYPE_AEAD:
+ crypto_unregister_aead(&alg->alg.u.aead);
+ break;
+diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
+index 56c10668c0ab0a..0d83cde84cca9a 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.h
++++ b/drivers/crypto/amcc/crypto4xx_core.h
+@@ -16,7 +16,6 @@
+ #include <linux/ratelimit.h>
+ #include <linux/mutex.h>
+ #include <linux/scatterlist.h>
+-#include <crypto/internal/hash.h>
+ #include <crypto/internal/aead.h>
+ #include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+@@ -135,7 +134,6 @@ struct crypto4xx_alg_common {
+ u32 type;
+ union {
+ struct skcipher_alg cipher;
+- struct ahash_alg hash;
+ struct aead_alg aead;
+ struct rng_alg rng;
+ } u;
+@@ -182,11 +180,6 @@ int crypto4xx_encrypt_noiv_block(struct skcipher_request *req);
+ int crypto4xx_decrypt_noiv_block(struct skcipher_request *req);
+ int crypto4xx_rfc3686_encrypt(struct skcipher_request *req);
+ int crypto4xx_rfc3686_decrypt(struct skcipher_request *req);
+-int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm);
+-int crypto4xx_hash_digest(struct ahash_request *req);
+-int crypto4xx_hash_final(struct ahash_request *req);
+-int crypto4xx_hash_update(struct ahash_request *req);
+-int crypto4xx_hash_init(struct ahash_request *req);
+
+ /*
+ * Note: Only use this function to copy items that is word aligned.
+--
+2.53.0
+
--- /dev/null
+From 96395e918b3d29b44713f0625bcf65c7171ecbfe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 19:44:03 -0700
+Subject: crypto: crypto4xx - Remove insecure and unused rng_alg
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 7811ec9e973d2c9e465083699f0c8240b98cb8c4 upstream.
+
+Remove crypto4xx_rng, as it is insecure and unused:
+
+- It has only a 64-bit security strength, which is highly inadequate.
+ This can be seen by the fact that crypto4xx_hw_init() seeds it with
+ only 64 bits of entropy, and the fact that the original commit
+ mentions that it implements ANSI X9.17 Annex C.
+
+ Another issue was that this driver didn't implement the crypto_rng API
+ correctly, as crypto4xx_prng_generate() didn't return 0 on success.
+
+- No user of this code is known. It's usable only theoretically via the
+ "rng" algorithm type of AF_ALG. But userspace actually just uses the
+ actual Linux RNG (/dev/random etc) instead. And rng_algs don't
+ contribute entropy to the actual Linux RNG either. (This may have
+ been confused with hwrng, which does contribute entropy.)
+
+Fixes: d072bfa48853 ("crypto: crypto4xx - add prng crypto support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Acked-by: Christian Lamparter <chunkeey@gmail.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/amcc/crypto4xx_core.c | 87 -------------------------
+ drivers/crypto/amcc/crypto4xx_core.h | 4 --
+ drivers/crypto/amcc/crypto4xx_reg_def.h | 11 ----
+ 3 files changed, 102 deletions(-)
+
+diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
+index eeb9546bfec9da..420efe3ad6d812 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.c
++++ b/drivers/crypto/amcc/crypto4xx_core.c
+@@ -31,11 +31,9 @@
+ #include <crypto/ctr.h>
+ #include <crypto/gcm.h>
+ #include <crypto/sha1.h>
+-#include <crypto/rng.h>
+ #include <crypto/scatterwalk.h>
+ #include <crypto/skcipher.h>
+ #include <crypto/internal/aead.h>
+-#include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+ #include "crypto4xx_reg_def.h"
+ #include "crypto4xx_core.h"
+@@ -989,10 +987,6 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
+ rc = crypto_register_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_RNG:
+- rc = crypto_register_rng(&alg->alg.u.rng);
+- break;
+-
+ default:
+ rc = crypto_register_skcipher(&alg->alg.u.cipher);
+ break;
+@@ -1018,10 +1012,6 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
+ crypto_unregister_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&alg->alg.u.rng);
+- break;
+-
+ default:
+ crypto_unregister_skcipher(&alg->alg.u.cipher);
+ }
+@@ -1080,69 +1070,6 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
+ PPC4XX_TMO_ERR_INT);
+ }
+
+-static int ppc4xx_prng_data_read(struct crypto4xx_device *dev,
+- u8 *data, unsigned int max)
+-{
+- unsigned int i, curr = 0;
+- u32 val[2];
+-
+- do {
+- /* trigger PRN generation */
+- writel(PPC4XX_PRNG_CTRL_AUTO_EN,
+- dev->ce_base + CRYPTO4XX_PRNG_CTRL);
+-
+- for (i = 0; i < 1024; i++) {
+- /* usually 19 iterations are enough */
+- if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) &
+- CRYPTO4XX_PRNG_STAT_BUSY))
+- continue;
+-
+- val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0);
+- val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1);
+- break;
+- }
+- if (i == 1024)
+- return -ETIMEDOUT;
+-
+- if ((max - curr) >= 8) {
+- memcpy(data, &val, 8);
+- data += 8;
+- curr += 8;
+- } else {
+- /* copy only remaining bytes */
+- memcpy(data, &val, max - curr);
+- break;
+- }
+- } while (curr < max);
+-
+- return curr;
+-}
+-
+-static int crypto4xx_prng_generate(struct crypto_rng *tfm,
+- const u8 *src, unsigned int slen,
+- u8 *dstn, unsigned int dlen)
+-{
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+- struct crypto4xx_alg *amcc_alg;
+- struct crypto4xx_device *dev;
+- int ret;
+-
+- amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng);
+- dev = amcc_alg->dev;
+-
+- mutex_lock(&dev->core_dev->rng_lock);
+- ret = ppc4xx_prng_data_read(dev, dstn, dlen);
+- mutex_unlock(&dev->core_dev->rng_lock);
+- return ret;
+-}
+-
+-
+-static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- return 0;
+-}
+-
+ /*
+ * Supported Crypto Algorithms
+ */
+@@ -1312,18 +1239,6 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
+ .cra_module = THIS_MODULE,
+ },
+ } },
+- { .type = CRYPTO_ALG_TYPE_RNG, .u.rng = {
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "crypto4xx_rng",
+- .cra_priority = 300,
+- .cra_ctxsize = 0,
+- .cra_module = THIS_MODULE,
+- },
+- .generate = crypto4xx_prng_generate,
+- .seed = crypto4xx_prng_seed,
+- .seedsize = 0,
+- } },
+ };
+
+ /*
+@@ -1393,7 +1308,6 @@ static int crypto4xx_probe(struct platform_device *ofdev)
+ core_dev->dev->core_dev = core_dev;
+ core_dev->dev->is_revb = is_revb;
+ core_dev->device = dev;
+- mutex_init(&core_dev->rng_lock);
+ spin_lock_init(&core_dev->lock);
+ INIT_LIST_HEAD(&core_dev->dev->alg_list);
+ ratelimit_default_init(&core_dev->dev->aead_ratelimit);
+@@ -1471,7 +1385,6 @@ static int crypto4xx_remove(struct platform_device *ofdev)
+ tasklet_kill(&core_dev->tasklet);
+ /* Un-register with Linux CryptoAPI */
+ crypto4xx_unregister_alg(core_dev->dev);
+- mutex_destroy(&core_dev->rng_lock);
+ /* Free all allocated memory */
+ crypto4xx_stop_all(core_dev);
+
+diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
+index 0d83cde84cca9a..d8224bbe89ca27 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.h
++++ b/drivers/crypto/amcc/crypto4xx_core.h
+@@ -14,10 +14,8 @@
+ #define __CRYPTO4XX_CORE_H__
+
+ #include <linux/ratelimit.h>
+-#include <linux/mutex.h>
+ #include <linux/scatterlist.h>
+ #include <crypto/internal/aead.h>
+-#include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+ #include "crypto4xx_reg_def.h"
+ #include "crypto4xx_sa.h"
+@@ -111,7 +109,6 @@ struct crypto4xx_core_device {
+ u32 irq;
+ struct tasklet_struct tasklet;
+ spinlock_t lock;
+- struct mutex rng_lock;
+ };
+
+ struct crypto4xx_ctx {
+@@ -135,7 +132,6 @@ struct crypto4xx_alg_common {
+ union {
+ struct skcipher_alg cipher;
+ struct aead_alg aead;
+- struct rng_alg rng;
+ } u;
+ };
+
+diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
+index 1038061224da66..73d626308a8484 100644
+--- a/drivers/crypto/amcc/crypto4xx_reg_def.h
++++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
+@@ -90,20 +90,9 @@
+ #define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8
+ #define CRYPTO4XX_ENDIAN_CFG 0x000600d8
+
+-#define CRYPTO4XX_PRNG_STAT 0x00070000
+-#define CRYPTO4XX_PRNG_STAT_BUSY 0x1
+ #define CRYPTO4XX_PRNG_CTRL 0x00070004
+ #define CRYPTO4XX_PRNG_SEED_L 0x00070008
+ #define CRYPTO4XX_PRNG_SEED_H 0x0007000c
+-
+-#define CRYPTO4XX_PRNG_RES_0 0x00070020
+-#define CRYPTO4XX_PRNG_RES_1 0x00070024
+-#define CRYPTO4XX_PRNG_RES_2 0x00070028
+-#define CRYPTO4XX_PRNG_RES_3 0x0007002C
+-
+-#define CRYPTO4XX_PRNG_LFSR_L 0x00070030
+-#define CRYPTO4XX_PRNG_LFSR_H 0x00070034
+-
+ /*
+ * Initialize CRYPTO ENGINE registers, and memory bases.
+ */
+--
+2.53.0
+
--- /dev/null
+From 174413dd28cf0812cc8e11896f9a4c8f5c83e175 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:42:54 -0700
+Subject: crypto: hisi-trng - Remove crypto_rng interface
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 216a7795ec210bdabd5dad42323eee70bbfc8d90 upstream.
+
+drivers/crypto/hisilicon/trng/trng.c exposes the same hardware through
+two completely separate interfaces, crypto_rng and hwrng. However, the
+implementation of this is buggy because it permits generation operations
+from these interfaces to run concurrently with each other, accessing the
+same registers. That is, hisi_trng_generate() synchronizes with itself
+but not with hisi_trng_read(). This results in potential repetition of
+output from the RNG, output of non-random values, etc.
+
+Fortunately, there's actually no point in hardware RNG drivers
+implementing the crypto_rng interface. It's not actually used by
+anything besides the "rng" algorithm type of AF_ALG, which in turn is
+not actually used in practice. Other crypto_rng hardware drivers are
+likewise being phased out, leaving just the hwrng support.
+
+Thus, remove it to simplify the code and avoid conflict (and confusion)
+with the hwrng interface which is the one that actually matters.
+
+Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/hisilicon/Kconfig | 1 -
+ drivers/crypto/hisilicon/trng/trng.c | 298 +--------------------------
+ 2 files changed, 2 insertions(+), 297 deletions(-)
+
+diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig
+index e572f9982d4ef4..f52aebd75c30ed 100644
+--- a/drivers/crypto/hisilicon/Kconfig
++++ b/drivers/crypto/hisilicon/Kconfig
+@@ -78,6 +78,5 @@ config CRYPTO_DEV_HISI_TRNG
+ tristate "Support for HISI TRNG Driver"
+ depends on ARM64 && ACPI
+ select HW_RANDOM
+- select CRYPTO_RNG
+ help
+ Support for HiSilicon TRNG Driver.
+diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c
+index 687705ae50ab51..de1f86fc147cc5 100644
+--- a/drivers/crypto/hisilicon/trng/trng.c
++++ b/drivers/crypto/hisilicon/trng/trng.c
+@@ -1,234 +1,27 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /* Copyright (c) 2019 HiSilicon Limited. */
+
+-#include <crypto/internal/rng.h>
+ #include <linux/acpi.h>
+-#include <linux/crypto.h>
+ #include <linux/err.h>
+ #include <linux/hw_random.h>
+ #include <linux/io.h>
+ #include <linux/iopoll.h>
+ #include <linux/kernel.h>
+-#include <linux/list.h>
+ #include <linux/module.h>
+-#include <linux/mutex.h>
+ #include <linux/platform_device.h>
+ #include <linux/random.h>
+
+ #define HISI_TRNG_REG 0x00F0
+ #define HISI_TRNG_BYTES 4
+ #define HISI_TRNG_QUALITY 512
+-#define HISI_TRNG_VERSION 0x01B8
+-#define HISI_TRNG_VER_V1 GENMASK(31, 0)
+ #define SLEEP_US 10
+ #define TIMEOUT_US 10000
+-#define SW_DRBG_NUM_SHIFT 2
+-#define SW_DRBG_KEY_BASE 0x082C
+-#define SW_DRBG_SEED(n) (SW_DRBG_KEY_BASE - ((n) << SW_DRBG_NUM_SHIFT))
+-#define SW_DRBG_SEED_REGS_NUM 12
+-#define SW_DRBG_SEED_SIZE 48
+-#define SW_DRBG_BLOCKS 0x0830
+-#define SW_DRBG_INIT 0x0834
+-#define SW_DRBG_GEN 0x083c
+-#define SW_DRBG_STATUS 0x0840
+-#define SW_DRBG_BLOCKS_NUM 4095
+-#define SW_DRBG_DATA_BASE 0x0850
+-#define SW_DRBG_DATA_NUM 4
+-#define SW_DRBG_DATA(n) (SW_DRBG_DATA_BASE - ((n) << SW_DRBG_NUM_SHIFT))
+-#define SW_DRBG_BYTES 16
+-#define SW_DRBG_ENABLE_SHIFT 12
+-#define SEED_SHIFT_24 24
+-#define SEED_SHIFT_16 16
+-#define SEED_SHIFT_8 8
+-#define SW_MAX_RANDOM_BYTES 65520
+-
+-struct hisi_trng_list {
+- struct mutex lock;
+- struct list_head list;
+- bool is_init;
+-};
+
+ struct hisi_trng {
+ void __iomem *base;
+- struct hisi_trng_list *trng_list;
+- struct list_head list;
+ struct hwrng rng;
+- u32 ver;
+- u32 ctx_num;
+- /* The bytes of the random number generated since the last seeding. */
+- u32 random_bytes;
+- struct mutex lock;
+-};
+-
+-struct hisi_trng_ctx {
+- struct hisi_trng *trng;
+ };
+
+-static atomic_t trng_active_devs;
+-static struct hisi_trng_list trng_devices;
+-static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait);
+-
+-static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
+-{
+- u32 val, seed_reg, i;
+- int ret;
+-
+- writel(0x0, trng->base + SW_DRBG_BLOCKS);
+-
+- for (i = 0; i < SW_DRBG_SEED_SIZE;
+- i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) {
+- val = seed[i] << SEED_SHIFT_24;
+- val |= seed[i + 1UL] << SEED_SHIFT_16;
+- val |= seed[i + 2UL] << SEED_SHIFT_8;
+- val |= seed[i + 3UL];
+-
+- seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM;
+- writel(val, trng->base + SW_DRBG_SEED(seed_reg));
+- }
+-
+- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT),
+- trng->base + SW_DRBG_BLOCKS);
+- writel(0x1, trng->base + SW_DRBG_INIT);
+- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
+- val, val & BIT(0), SLEEP_US, TIMEOUT_US);
+- if (ret) {
+- pr_err("failed to init trng(%d)\n", ret);
+- return -EIO;
+- }
+-
+- trng->random_bytes = 0;
+-
+- return 0;
+-}
+-
+-static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
+- struct hisi_trng *trng = ctx->trng;
+- int ret;
+-
+- if (slen < SW_DRBG_SEED_SIZE) {
+- pr_err("slen(%u) is not matched with trng(%d)\n", slen,
+- SW_DRBG_SEED_SIZE);
+- return -EINVAL;
+- }
+-
+- mutex_lock(&trng->lock);
+- ret = hisi_trng_set_seed(trng, seed);
+- mutex_unlock(&trng->lock);
+-
+- return ret;
+-}
+-
+-static int hisi_trng_reseed(struct hisi_trng *trng)
+-{
+- u8 seed[SW_DRBG_SEED_SIZE];
+- int size;
+-
+- if (!trng->random_bytes)
+- return 0;
+-
+- size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false);
+- if (size != SW_DRBG_SEED_SIZE)
+- return -EIO;
+-
+- return hisi_trng_set_seed(trng, seed);
+-}
+-
+-static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen)
+-{
+- u32 data[SW_DRBG_DATA_NUM];
+- u32 currsize = 0;
+- u32 val = 0;
+- int ret;
+- u32 i;
+-
+- ret = hisi_trng_reseed(trng);
+- if (ret)
+- return ret;
+-
+- do {
+- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
+- val, val & BIT(1), SLEEP_US, TIMEOUT_US);
+- if (ret) {
+- pr_err("failed to generate random number(%d)!\n", ret);
+- break;
+- }
+-
+- for (i = 0; i < SW_DRBG_DATA_NUM; i++)
+- data[i] = readl(trng->base + SW_DRBG_DATA(i));
+-
+- if (dlen - currsize >= SW_DRBG_BYTES) {
+- memcpy(dstn + currsize, data, SW_DRBG_BYTES);
+- currsize += SW_DRBG_BYTES;
+- } else {
+- memcpy(dstn + currsize, data, dlen - currsize);
+- currsize = dlen;
+- }
+-
+- trng->random_bytes += SW_DRBG_BYTES;
+- writel(0x1, trng->base + SW_DRBG_GEN);
+- } while (currsize < dlen);
+-
+- return ret;
+-}
+-
+-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dstn, unsigned int dlen)
+-{
+- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
+- struct hisi_trng *trng = ctx->trng;
+- unsigned int currsize = 0;
+- unsigned int block_size;
+- int ret;
+-
+- if (!dstn || !dlen) {
+- pr_err("output is error, dlen %u!\n", dlen);
+- return -EINVAL;
+- }
+-
+- do {
+- block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES);
+- mutex_lock(&trng->lock);
+- ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size);
+- mutex_unlock(&trng->lock);
+- if (ret)
+- return ret;
+- currsize += block_size;
+- } while (currsize < dlen);
+-
+- return 0;
+-}
+-
+-static int hisi_trng_init(struct crypto_tfm *tfm)
+-{
+- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
+- struct hisi_trng *trng;
+- u32 ctx_num = ~0;
+-
+- mutex_lock(&trng_devices.lock);
+- list_for_each_entry(trng, &trng_devices.list, list) {
+- if (trng->ctx_num < ctx_num) {
+- ctx_num = trng->ctx_num;
+- ctx->trng = trng;
+- }
+- }
+- ctx->trng->ctx_num++;
+- mutex_unlock(&trng_devices.lock);
+-
+- return 0;
+-}
+-
+-static void hisi_trng_exit(struct crypto_tfm *tfm)
+-{
+- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
+-
+- mutex_lock(&trng_devices.lock);
+- ctx->trng->ctx_num--;
+- mutex_unlock(&trng_devices.lock);
+-}
+-
+ static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+ {
+ struct hisi_trng *trng;
+@@ -260,42 +53,6 @@ static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+ return currsize;
+ }
+
+-static struct rng_alg hisi_trng_alg = {
+- .generate = hisi_trng_generate,
+- .seed = hisi_trng_seed,
+- .seedsize = SW_DRBG_SEED_SIZE,
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "hisi_stdrng",
+- .cra_priority = 300,
+- .cra_ctxsize = sizeof(struct hisi_trng_ctx),
+- .cra_module = THIS_MODULE,
+- .cra_init = hisi_trng_init,
+- .cra_exit = hisi_trng_exit,
+- },
+-};
+-
+-static void hisi_trng_add_to_list(struct hisi_trng *trng)
+-{
+- mutex_lock(&trng_devices.lock);
+- list_add_tail(&trng->list, &trng_devices.list);
+- mutex_unlock(&trng_devices.lock);
+-}
+-
+-static int hisi_trng_del_from_list(struct hisi_trng *trng)
+-{
+- int ret = -EBUSY;
+-
+- mutex_lock(&trng_devices.lock);
+- if (!trng->ctx_num) {
+- list_del(&trng->list);
+- ret = 0;
+- }
+- mutex_unlock(&trng_devices.lock);
+-
+- return ret;
+-}
+-
+ static int hisi_trng_probe(struct platform_device *pdev)
+ {
+ struct hisi_trng *trng;
+@@ -305,70 +62,20 @@ static int hisi_trng_probe(struct platform_device *pdev)
+ if (!trng)
+ return -ENOMEM;
+
+- platform_set_drvdata(pdev, trng);
+-
+ trng->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(trng->base))
+ return PTR_ERR(trng->base);
+
+- trng->ctx_num = 0;
+- trng->random_bytes = SW_MAX_RANDOM_BYTES;
+- mutex_init(&trng->lock);
+- trng->ver = readl(trng->base + HISI_TRNG_VERSION);
+- if (!trng_devices.is_init) {
+- INIT_LIST_HEAD(&trng_devices.list);
+- mutex_init(&trng_devices.lock);
+- trng_devices.is_init = true;
+- }
+-
+- hisi_trng_add_to_list(trng);
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_inc_return(&trng_active_devs) == 1) {
+- ret = crypto_register_rng(&hisi_trng_alg);
+- if (ret) {
+- dev_err(&pdev->dev,
+- "failed to register crypto(%d)\n", ret);
+- atomic_dec_return(&trng_active_devs);
+- goto err_remove_from_list;
+- }
+- }
+-
+ trng->rng.name = pdev->name;
+ trng->rng.read = hisi_trng_read;
+ trng->rng.quality = HISI_TRNG_QUALITY;
++
+ ret = devm_hwrng_register(&pdev->dev, &trng->rng);
+- if (ret) {
++ if (ret)
+ dev_err(&pdev->dev, "failed to register hwrng: %d!\n", ret);
+- goto err_crypto_unregister;
+- }
+-
+- return ret;
+-
+-err_crypto_unregister:
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_dec_return(&trng_active_devs) == 0)
+- crypto_unregister_rng(&hisi_trng_alg);
+-
+-err_remove_from_list:
+- hisi_trng_del_from_list(trng);
+ return ret;
+ }
+
+-static int hisi_trng_remove(struct platform_device *pdev)
+-{
+- struct hisi_trng *trng = platform_get_drvdata(pdev);
+-
+- /* Wait until the task is finished */
+- while (hisi_trng_del_from_list(trng))
+- ;
+-
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_dec_return(&trng_active_devs) == 0)
+- crypto_unregister_rng(&hisi_trng_alg);
+-
+- return 0;
+-}
+-
+ static const struct acpi_device_id hisi_trng_acpi_match[] = {
+ { "HISI02B3", 0 },
+ { }
+@@ -377,7 +84,6 @@ MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi_match);
+
+ static struct platform_driver hisi_trng_driver = {
+ .probe = hisi_trng_probe,
+- .remove = hisi_trng_remove,
+ .driver = {
+ .name = "hisi-trng-v2",
+ .acpi_match_table = ACPI_PTR(hisi_trng_acpi_match),
+--
+2.53.0
+
--- /dev/null
+From 96a0b608f4d5b3dcc8f0ee6a89f112a826252177 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:52:28 -0700
+Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit b2c41fa9dd8fc740c489e060b199165771f268d1 upstream.
+
+Remove sun4i_ss_rng, as it is insecure and unused:
+
+- It has multiple vulnerabilities. sun4i_ss_prng_seed() is missing
+ locking and has a buffer overflow. sun4i_ss_prng_generate() fails to
+ fill the entire buffer with cryptographic random bytes, because it
+ rounds the destination length down and also doesn't actually wait for
+ the hardware to be ready before pulling bytes from it.
+
+- No user of this code is known. It's usable only theoretically via the
+ "rng" algorithm type of AF_ALG. But userspace actually just uses the
+ actual Linux RNG (/dev/random etc) instead. And rng_algs don't
+ contribute entropy to the actual Linux RNG either. (This may have
+ been confused with hwrng, which does contribute entropy.)
+
+The sun4i_ss_prng_seed() buffer overflow was reported by Tianchu Chen
+and discovered by Atuin - Automated Vulnerability Discovery Engine
+
+There's no point in fixing all these vulnerabilities individually when
+this is unused code, so let's just remove it.
+
+Fixes: b8ae5c7387ad ("crypto: sun4i-ss - support the Security System PRNG")
+Cc: stable@vger.kernel.org
+Reported-by: Tianchu Chen <flynnnchen@tencent.com>
+Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/
+Acked-by: Corentin LABBE <clabbe.montjoie@gmail.com>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/configs/sunxi_defconfig | 1 -
+ drivers/crypto/allwinner/Kconfig | 8 ---
+ drivers/crypto/allwinner/sun4i-ss/Makefile | 1 -
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-core.c | 36 ----------
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-prng.c | 69 -------------------
+ drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h | 20 ------
+ 6 files changed, 135 deletions(-)
+ delete mode 100644 drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+
+diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
+index a60c134c5e0466..5127c937b48531 100644
+--- a/arch/arm/configs/sunxi_defconfig
++++ b/arch/arm/configs/sunxi_defconfig
+@@ -168,7 +168,6 @@ CONFIG_ROOT_NFS=y
+ CONFIG_NLS_CODEPAGE_437=y
+ CONFIG_NLS_ISO8859_1=y
+ CONFIG_CRYPTO_DEV_SUN4I_SS=y
+-CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG=y
+ CONFIG_CRYPTO_DEV_SUN8I_CE=y
+ CONFIG_CRYPTO_DEV_SUN8I_SS=y
+ CONFIG_DMA_CMA=y
+diff --git a/drivers/crypto/allwinner/Kconfig b/drivers/crypto/allwinner/Kconfig
+index b8e75210a0e315..06ea0e9fe6f22f 100644
+--- a/drivers/crypto/allwinner/Kconfig
++++ b/drivers/crypto/allwinner/Kconfig
+@@ -24,14 +24,6 @@ config CRYPTO_DEV_SUN4I_SS
+ To compile this driver as a module, choose M here: the module
+ will be called sun4i-ss.
+
+-config CRYPTO_DEV_SUN4I_SS_PRNG
+- bool "Support for Allwinner Security System PRNG"
+- depends on CRYPTO_DEV_SUN4I_SS
+- select CRYPTO_RNG
+- help
+- Select this option if you want to provide kernel-side support for
+- the Pseudo-Random Number Generator found in the Security System.
+-
+ config CRYPTO_DEV_SUN4I_SS_DEBUG
+ bool "Enable sun4i-ss stats"
+ depends on CRYPTO_DEV_SUN4I_SS
+diff --git a/drivers/crypto/allwinner/sun4i-ss/Makefile b/drivers/crypto/allwinner/sun4i-ss/Makefile
+index c0a2797d316827..06a9ae81f9f808 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/Makefile
++++ b/drivers/crypto/allwinner/sun4i-ss/Makefile
+@@ -1,4 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sun4i-ss.o
+ sun4i-ss-y += sun4i-ss-core.o sun4i-ss-hash.o sun4i-ss-cipher.o
+-sun4i-ss-$(CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG) += sun4i-ss-prng.o
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+index 44b8fc4b786dc8..0520cc6447e2db 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+@@ -216,23 +216,6 @@ static struct sun4i_ss_alg_template ss_algs[] = {
+ }
+ }
+ },
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+-{
+- .type = CRYPTO_ALG_TYPE_RNG,
+- .alg.rng = {
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "sun4i_ss_rng",
+- .cra_priority = 300,
+- .cra_ctxsize = 0,
+- .cra_module = THIS_MODULE,
+- },
+- .generate = sun4i_ss_prng_generate,
+- .seed = sun4i_ss_prng_seed,
+- .seedsize = SS_SEED_LEN / BITS_PER_BYTE,
+- }
+-},
+-#endif
+ };
+
+ static int sun4i_ss_dbgfs_read(struct seq_file *seq, void *v)
+@@ -250,12 +233,6 @@ static int sun4i_ss_dbgfs_read(struct seq_file *seq, void *v)
+ ss_algs[i].stat_req, ss_algs[i].stat_opti, ss_algs[i].stat_fb,
+ ss_algs[i].stat_bytes);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",
+- ss_algs[i].alg.rng.base.cra_driver_name,
+- ss_algs[i].alg.rng.base.cra_name,
+- ss_algs[i].stat_req, ss_algs[i].stat_bytes);
+- break;
+ case CRYPTO_ALG_TYPE_AHASH:
+ seq_printf(seq, "%s %s reqs=%lu\n",
+ ss_algs[i].alg.hash.halg.base.cra_driver_name,
+@@ -486,13 +463,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ goto error_alg;
+ }
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- err = crypto_register_rng(&ss_algs[i].alg.rng);
+- if (err) {
+- dev_err(ss->dev, "Fail to register %s\n",
+- ss_algs[i].alg.rng.base.cra_name);
+- }
+- break;
+ }
+ }
+
+@@ -512,9 +482,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+ error_pm:
+@@ -535,9 +502,6 @@ static int sun4i_ss_remove(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+deleted file mode 100644
+index 491fcb7b81b40b..00000000000000
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
++++ /dev/null
+@@ -1,69 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-#include "sun4i-ss.h"
+-
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- memcpy(algt->ss->seed, seed, slen);
+-
+- return 0;
+-}
+-
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+- int i, err;
+- u32 v;
+- u32 *data = (u32 *)dst;
+- const u32 mode = SS_OP_PRNG | SS_PRNG_CONTINUE | SS_ENABLED;
+- size_t len;
+- struct sun4i_ss_ctx *ss;
+- unsigned int todo = (dlen / 4) * 4;
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- ss = algt->ss;
+-
+- err = pm_runtime_resume_and_get(ss->dev);
+- if (err < 0)
+- return err;
+-
+- if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) {
+- algt->stat_req++;
+- algt->stat_bytes += todo;
+- }
+-
+- spin_lock_bh(&ss->slock);
+-
+- writel(mode, ss->base + SS_CTL);
+-
+- while (todo > 0) {
+- /* write the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++)
+- writel(ss->seed[i], ss->base + SS_KEY0 + i * 4);
+-
+- /* Read the random data */
+- len = min_t(size_t, SS_DATA_LEN / BITS_PER_BYTE, todo);
+- readsl(ss->base + SS_TXFIFO, data, len / 4);
+- data += len / 4;
+- todo -= len;
+-
+- /* Update the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++) {
+- v = readl(ss->base + SS_KEY0 + i * 4);
+- ss->seed[i] = v;
+- }
+- }
+-
+- writel(0, ss->base + SS_CTL);
+- spin_unlock_bh(&ss->slock);
+-
+- pm_runtime_put(ss->dev);
+-
+- return 0;
+-}
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+index 0fee6f4e2d90dc..e1a849ce11b1cc 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+@@ -31,8 +31,6 @@
+ #include <crypto/internal/skcipher.h>
+ #include <crypto/aes.h>
+ #include <crypto/internal/des.h>
+-#include <crypto/internal/rng.h>
+-#include <crypto/rng.h>
+
+ #define SS_CTL 0x00
+ #define SS_KEY0 0x04
+@@ -62,10 +60,6 @@
+
+ /* SS_CTL configuration values */
+
+-/* PRNG generator mode - bit 15 */
+-#define SS_PRNG_ONESHOT (0 << 15)
+-#define SS_PRNG_CONTINUE (1 << 15)
+-
+ /* IV mode for hash */
+ #define SS_IV_ARBITRARY (1 << 14)
+
+@@ -94,14 +88,10 @@
+ #define SS_OP_3DES (2 << 4)
+ #define SS_OP_SHA1 (3 << 4)
+ #define SS_OP_MD5 (4 << 4)
+-#define SS_OP_PRNG (5 << 4)
+
+ /* Data end bit - bit 2 */
+ #define SS_DATA_END (1 << 2)
+
+-/* PRNG start bit - bit 1 */
+-#define SS_PRNG_START (1 << 1)
+-
+ /* SS Enable bit - bit 0 */
+ #define SS_DISABLED (0 << 0)
+ #define SS_ENABLED (1 << 0)
+@@ -128,9 +118,6 @@
+ #define SS_RXFIFO_EMP_INT_ENABLE (1 << 2)
+ #define SS_TXFIFO_AVA_INT_ENABLE (1 << 0)
+
+-#define SS_SEED_LEN 192
+-#define SS_DATA_LEN 160
+-
+ /*
+ * struct ss_variant - Describe SS hardware variant
+ * @sha1_in_be: The SHA1 digest is given by SS in BE, and so need to be inverted.
+@@ -151,9 +138,6 @@ struct sun4i_ss_ctx {
+ char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */
+ char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */
+ spinlock_t slock; /* control the use of the device */
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+- u32 seed[SS_SEED_LEN / BITS_PER_LONG];
+-#endif
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_stats;
+ };
+@@ -164,7 +148,6 @@ struct sun4i_ss_alg_template {
+ union {
+ struct skcipher_alg crypto;
+ struct ahash_alg hash;
+- struct rng_alg rng;
+ } alg;
+ struct sun4i_ss_ctx *ss;
+ unsigned long stat_req;
+@@ -230,6 +213,3 @@ int sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+ int sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen);
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen);
+--
+2.53.0
+
crypto-algif_skcipher-force-synchronous-processing-o.patch
tools-mm-slabinfo-fix-total_objects-attribute-name.patch
net-dsa-tag_ksz-do-not-rely-on-skb_mac_header-in-tx-.patch
+crypto-af_alg-remove-zero-copy-support-from-skcipher.patch
+crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
+crypto-crypto4xx-remove-ahash-related-code.patch
+crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch
+crypto-hisi-trng-remove-crypto_rng-interface.patch
--- /dev/null
+From 59ab8631c060e1bdf6a9d6d0f9f82e71a2410756 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:33:12 -0700
+Subject: crypto: af_alg - Remove zero-copy support from skcipher and aead
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit ffdd2bc378953b525aca61902534e753f1f8e734 upstream.
+
+The zero-copy support is one of the riskiest aspects of AF_ALG. It
+allows userspace to request cryptographic operations directly on
+pagecache pages of files like the 'su' binary. It also allows userspace
+to concurrently modify the memory which is being operated on, a recipe
+for TOCTOU vulnerabilities.
+
+While zero-copy support is more valuable in other areas of the kernel
+like the frequently used networking and file I/O code, it has far less
+value in AF_ALG, which is a niche UAPI. AF_ALG primarily just exists
+for backwards compatibility with a small set of userspace programs such
+as 'iwd' that haven't yet been fixed to use userspace crypto code.
+
+Originally AF_ALG was intended to be used to access hardware crypto
+accelerators. However, it isn't an efficient interface for that anyway,
+and it turned out to be rarely used in this way in practice.
+
+Thus, the risks of the zero-copy support in AF_ALG vastly outweigh its
+benefits. Let's just remove it.
+
+This commit removes it from the "skcipher" and "aead" algorithm types.
+"hash" will be handled separately.
+
+This is a soft break, not a hard break. Even after this commit, it
+still works to use splice() or sendfile() to transfer data to an AF_ALG
+request socket from a pipe or any file, respectively. What changes is
+just that the kernel now makes an internal, stable copy of the data
+before doing the crypto operation. So performance is slightly reduced,
+but the UAPI isn't broken. And, very importantly, it's much safer.
+
+Tested with libkcapi/test.sh. All its test cases still pass. I also
+verified that this would have prevented the copy.fail exploit as well.
+I also used a custom test program to verify that sendfile() still works.
+
+Fixes: 8ff590903d5f ("crypto: algif_skcipher - User-space interface for skcipher operations")
+Fixes: 400c40cf78da ("crypto: algif - add AEAD support")
+Reported-by: Taeyang Lee <0wn@theori.io>
+Link: https://copy.fail/
+Reported-by: Feng Ning <feng@innora.ai>
+Closes: https://lore.kernel.org/r/afYcc-tZFwvZZo76@ans-MacBook-Pro.local
+Reviewed-by: Demi Marie Obenour <demiobenour@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+[Backport-notes: this actually does nothing on 6.1, since zero-copy
+ support was already removed from skcipher and aead accidentally on 6.1.
+ Namely, a commit that changed af_alg_sendpage() to use MSG_SPLICE_PAGES
+ was backported, but the actual implementation of MSG_SPLICE_PAGES
+ wasn't backported. I'm including this commit anyway since people might
+ think this is missing on 6.1 if it's the only LTS kernel without this.]
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/crypto/userspace-if.rst | 31 ++++-----------------------
+ crypto/af_alg.c | 2 +-
+ 2 files changed, 5 insertions(+), 28 deletions(-)
+
+diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst
+index b45dabbf69d685..90dbbd56c4e355 100644
+--- a/Documentation/crypto/userspace-if.rst
++++ b/Documentation/crypto/userspace-if.rst
+@@ -328,33 +328,10 @@ CRYPTO_USER_API_RNG_CAVP option:
+ Zero-Copy Interface
+ -------------------
+
+-In addition to the send/write/read/recv system call family, the AF_ALG
+-interface can be accessed with the zero-copy interface of
+-splice/vmsplice. As the name indicates, the kernel tries to avoid a copy
+-operation into kernel space.
+-
+-The zero-copy operation requires data to be aligned at the page
+-boundary. Non-aligned data can be used as well, but may require more
+-operations of the kernel which would defeat the speed gains obtained
+-from the zero-copy interface.
+-
+-The system-inherent limit for the size of one zero-copy operation is 16
+-pages. If more data is to be sent to AF_ALG, user space must slice the
+-input into segments with a maximum size of 16 pages.
+-
+-Zero-copy can be used with the following code example (a complete
+-working example is provided with libkcapi):
+-
+-::
+-
+- int pipes[2];
+-
+- pipe(pipes);
+- /* input data in iov */
+- vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT);
+- /* opfd is the file descriptor returned from accept() system call */
+- splice(pipes[0], NULL, opfd, NULL, ret, 0);
+- read(opfd, out, outlen);
++AF_ALG used to have zero-copy support, but it was removed due to it being a
++frequent source of vulnerabilities. For backwards compatibility the splice()
++and sendfile() system calls are still supported, but the kernel will make an
++internal copy of the data before passing it to the crypto code.
+
+
+ Setsockopt Interface
+diff --git a/crypto/af_alg.c b/crypto/af_alg.c
+index ca54f29270636f..80a8d3a4a3cf73 100644
+--- a/crypto/af_alg.c
++++ b/crypto/af_alg.c
+@@ -977,7 +977,7 @@ ssize_t af_alg_sendpage(struct socket *sock, struct page *page,
+ {
+ struct bio_vec bvec;
+ struct msghdr msg = {
+- .msg_flags = flags | MSG_SPLICE_PAGES,
++ .msg_flags = flags,
+ };
+
+ if (flags & MSG_SENDPAGE_NOTLAST)
+--
+2.53.0
+
--- /dev/null
+From ab565e6498a241fd2d01f56eaf6b31358e99a6ed Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 19:44:02 -0700
+Subject: crypto: crypto4xx - Remove ahash-related code
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+commit 97855e7f1ccf4917f305baab199edb9f2595ff5b upstream.
+
+The hash implementation in crypto4xx has been disabled since 2009.
+As nobody has tried to fix this remove all the dead code.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/amcc/crypto4xx_alg.c | 106 ---------------------------
+ drivers/crypto/amcc/crypto4xx_core.c | 43 +----------
+ drivers/crypto/amcc/crypto4xx_core.h | 7 --
+ 3 files changed, 1 insertion(+), 155 deletions(-)
+
+diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c
+index ded73224273295..91cecec729f25e 100644
+--- a/drivers/crypto/amcc/crypto4xx_alg.c
++++ b/drivers/crypto/amcc/crypto4xx_alg.c
+@@ -12,9 +12,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/spinlock_types.h>
+ #include <linux/scatterlist.h>
+-#include <linux/crypto.h>
+-#include <linux/hash.h>
+-#include <crypto/internal/hash.h>
+ #include <linux/dma-mapping.h>
+ #include <crypto/algapi.h>
+ #include <crypto/aead.h>
+@@ -616,106 +613,3 @@ int crypto4xx_decrypt_aes_gcm(struct aead_request *req)
+ {
+ return crypto4xx_crypt_aes_gcm(req, true);
+ }
+-
+-/*
+- * HASH SHA1 Functions
+- */
+-static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
+- unsigned int sa_len,
+- unsigned char ha,
+- unsigned char hm)
+-{
+- struct crypto_alg *alg = tfm->__crt_alg;
+- struct crypto4xx_alg *my_alg;
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
+- struct dynamic_sa_hash160 *sa;
+- int rc;
+-
+- my_alg = container_of(__crypto_ahash_alg(alg), struct crypto4xx_alg,
+- alg.u.hash);
+- ctx->dev = my_alg->dev;
+-
+- /* Create SA */
+- if (ctx->sa_in || ctx->sa_out)
+- crypto4xx_free_sa(ctx);
+-
+- rc = crypto4xx_alloc_sa(ctx, sa_len);
+- if (rc)
+- return rc;
+-
+- crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+- sizeof(struct crypto4xx_ctx));
+- sa = (struct dynamic_sa_hash160 *)ctx->sa_in;
+- set_dynamic_sa_command_0(&sa->ctrl, SA_SAVE_HASH, SA_NOT_SAVE_IV,
+- SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
+- SA_NO_HEADER_PROC, ha, SA_CIPHER_ALG_NULL,
+- SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
+- SA_OPCODE_HASH, DIR_INBOUND);
+- set_dynamic_sa_command_1(&sa->ctrl, 0, SA_HASH_MODE_HASH,
+- CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
+- SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+- SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
+- SA_NOT_COPY_HDR);
+- /* Need to zero hash digest in SA */
+- memset(sa->inner_digest, 0, sizeof(sa->inner_digest));
+- memset(sa->outer_digest, 0, sizeof(sa->outer_digest));
+-
+- return 0;
+-}
+-
+-int crypto4xx_hash_init(struct ahash_request *req)
+-{
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- int ds;
+- struct dynamic_sa_ctl *sa;
+-
+- sa = ctx->sa_in;
+- ds = crypto_ahash_digestsize(
+- __crypto_ahash_cast(req->base.tfm));
+- sa->sa_command_0.bf.digest_len = ds >> 2;
+- sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA;
+-
+- return 0;
+-}
+-
+-int crypto4xx_hash_update(struct ahash_request *req)
+-{
+- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- struct scatterlist dst;
+- unsigned int ds = crypto_ahash_digestsize(ahash);
+-
+- sg_init_one(&dst, req->result, ds);
+-
+- return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
+- req->nbytes, NULL, 0, ctx->sa_in,
+- ctx->sa_len, 0, NULL);
+-}
+-
+-int crypto4xx_hash_final(struct ahash_request *req)
+-{
+- return 0;
+-}
+-
+-int crypto4xx_hash_digest(struct ahash_request *req)
+-{
+- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- struct scatterlist dst;
+- unsigned int ds = crypto_ahash_digestsize(ahash);
+-
+- sg_init_one(&dst, req->result, ds);
+-
+- return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
+- req->nbytes, NULL, 0, ctx->sa_in,
+- ctx->sa_len, 0, NULL);
+-}
+-
+-/*
+- * SHA1 Algorithm
+- */
+-int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm)
+-{
+- return crypto4xx_hash_alg_init(tfm, SA_HASH160_LEN, SA_HASH_ALG_SHA1,
+- SA_HASH_MODE_HASH);
+-}
+diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
+index 50dc783821b699..2b8052a7e44923 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.c
++++ b/drivers/crypto/amcc/crypto4xx_core.c
+@@ -485,18 +485,6 @@ static void crypto4xx_copy_pkt_to_dst(struct crypto4xx_device *dev,
+ }
+ }
+
+-static void crypto4xx_copy_digest_to_dst(void *dst,
+- struct pd_uinfo *pd_uinfo,
+- struct crypto4xx_ctx *ctx)
+-{
+- struct dynamic_sa_ctl *sa = (struct dynamic_sa_ctl *) ctx->sa_in;
+-
+- if (sa->sa_command_0.bf.hash_alg == SA_HASH_ALG_SHA1) {
+- memcpy(dst, pd_uinfo->sr_va->save_digest,
+- SA_HASH_ALG_SHA1_DIGEST_SIZE);
+- }
+-}
+-
+ static void crypto4xx_ret_sg_desc(struct crypto4xx_device *dev,
+ struct pd_uinfo *pd_uinfo)
+ {
+@@ -549,23 +537,6 @@ static void crypto4xx_cipher_done(struct crypto4xx_device *dev,
+ skcipher_request_complete(req, 0);
+ }
+
+-static void crypto4xx_ahash_done(struct crypto4xx_device *dev,
+- struct pd_uinfo *pd_uinfo)
+-{
+- struct crypto4xx_ctx *ctx;
+- struct ahash_request *ahash_req;
+-
+- ahash_req = ahash_request_cast(pd_uinfo->async_req);
+- ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(ahash_req));
+-
+- crypto4xx_copy_digest_to_dst(ahash_req->result, pd_uinfo, ctx);
+- crypto4xx_ret_sg_desc(dev, pd_uinfo);
+-
+- if (pd_uinfo->state & PD_ENTRY_BUSY)
+- ahash_request_complete(ahash_req, -EINPROGRESS);
+- ahash_request_complete(ahash_req, 0);
+-}
+-
+ static void crypto4xx_aead_done(struct crypto4xx_device *dev,
+ struct pd_uinfo *pd_uinfo,
+ struct ce_pd *pd)
+@@ -642,9 +613,6 @@ static void crypto4xx_pd_done(struct crypto4xx_device *dev, u32 idx)
+ case CRYPTO_ALG_TYPE_AEAD:
+ crypto4xx_aead_done(dev, pd_uinfo, pd);
+ break;
+- case CRYPTO_ALG_TYPE_AHASH:
+- crypto4xx_ahash_done(dev, pd_uinfo);
+- break;
+ }
+ }
+
+@@ -915,8 +883,7 @@ int crypto4xx_build_pd(struct crypto_async_request *req,
+ }
+
+ pd->pd_ctl.w = PD_CTL_HOST_READY |
+- ((crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AHASH) ||
+- (crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AEAD) ?
++ ((crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AEAD) ?
+ PD_CTL_HASH_FINAL : 0);
+ pd->pd_ctl_len.w = 0x00400000 | (assoclen + datalen);
+ pd_uinfo->state = PD_ENTRY_INUSE | (is_busy ? PD_ENTRY_BUSY : 0);
+@@ -1022,10 +989,6 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
+ rc = crypto_register_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_AHASH:
+- rc = crypto_register_ahash(&alg->alg.u.hash);
+- break;
+-
+ case CRYPTO_ALG_TYPE_RNG:
+ rc = crypto_register_rng(&alg->alg.u.rng);
+ break;
+@@ -1051,10 +1014,6 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
+ list_for_each_entry_safe(alg, tmp, &sec_dev->alg_list, entry) {
+ list_del(&alg->entry);
+ switch (alg->alg.type) {
+- case CRYPTO_ALG_TYPE_AHASH:
+- crypto_unregister_ahash(&alg->alg.u.hash);
+- break;
+-
+ case CRYPTO_ALG_TYPE_AEAD:
+ crypto_unregister_aead(&alg->alg.u.aead);
+ break;
+diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
+index 56c10668c0ab0a..0d83cde84cca9a 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.h
++++ b/drivers/crypto/amcc/crypto4xx_core.h
+@@ -16,7 +16,6 @@
+ #include <linux/ratelimit.h>
+ #include <linux/mutex.h>
+ #include <linux/scatterlist.h>
+-#include <crypto/internal/hash.h>
+ #include <crypto/internal/aead.h>
+ #include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+@@ -135,7 +134,6 @@ struct crypto4xx_alg_common {
+ u32 type;
+ union {
+ struct skcipher_alg cipher;
+- struct ahash_alg hash;
+ struct aead_alg aead;
+ struct rng_alg rng;
+ } u;
+@@ -182,11 +180,6 @@ int crypto4xx_encrypt_noiv_block(struct skcipher_request *req);
+ int crypto4xx_decrypt_noiv_block(struct skcipher_request *req);
+ int crypto4xx_rfc3686_encrypt(struct skcipher_request *req);
+ int crypto4xx_rfc3686_decrypt(struct skcipher_request *req);
+-int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm);
+-int crypto4xx_hash_digest(struct ahash_request *req);
+-int crypto4xx_hash_final(struct ahash_request *req);
+-int crypto4xx_hash_update(struct ahash_request *req);
+-int crypto4xx_hash_init(struct ahash_request *req);
+
+ /*
+ * Note: Only use this function to copy items that is word aligned.
+--
+2.53.0
+
--- /dev/null
+From d3f415a7be6398620138e72be0c204a73d3c206c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 19:44:03 -0700
+Subject: crypto: crypto4xx - Remove insecure and unused rng_alg
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 7811ec9e973d2c9e465083699f0c8240b98cb8c4 upstream.
+
+Remove crypto4xx_rng, as it is insecure and unused:
+
+- It has only a 64-bit security strength, which is highly inadequate.
+ This can be seen by the fact that crypto4xx_hw_init() seeds it with
+ only 64 bits of entropy, and the fact that the original commit
+ mentions that it implements ANSI X9.17 Annex C.
+
+ Another issue was that this driver didn't implement the crypto_rng API
+ correctly, as crypto4xx_prng_generate() didn't return 0 on success.
+
+- No user of this code is known. It's usable only theoretically via the
+ "rng" algorithm type of AF_ALG. But userspace actually just uses the
+ actual Linux RNG (/dev/random etc) instead. And rng_algs don't
+ contribute entropy to the actual Linux RNG either. (This may have
+ been confused with hwrng, which does contribute entropy.)
+
+Fixes: d072bfa48853 ("crypto: crypto4xx - add prng crypto support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Acked-by: Christian Lamparter <chunkeey@gmail.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/amcc/crypto4xx_core.c | 87 -------------------------
+ drivers/crypto/amcc/crypto4xx_core.h | 4 --
+ drivers/crypto/amcc/crypto4xx_reg_def.h | 11 ----
+ 3 files changed, 102 deletions(-)
+
+diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
+index 2b8052a7e44923..4a41b61ce23ca8 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.c
++++ b/drivers/crypto/amcc/crypto4xx_core.c
+@@ -31,11 +31,9 @@
+ #include <crypto/ctr.h>
+ #include <crypto/gcm.h>
+ #include <crypto/sha1.h>
+-#include <crypto/rng.h>
+ #include <crypto/scatterwalk.h>
+ #include <crypto/skcipher.h>
+ #include <crypto/internal/aead.h>
+-#include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+ #include "crypto4xx_reg_def.h"
+ #include "crypto4xx_core.h"
+@@ -989,10 +987,6 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
+ rc = crypto_register_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_RNG:
+- rc = crypto_register_rng(&alg->alg.u.rng);
+- break;
+-
+ default:
+ rc = crypto_register_skcipher(&alg->alg.u.cipher);
+ break;
+@@ -1018,10 +1012,6 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
+ crypto_unregister_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&alg->alg.u.rng);
+- break;
+-
+ default:
+ crypto_unregister_skcipher(&alg->alg.u.cipher);
+ }
+@@ -1080,69 +1070,6 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
+ PPC4XX_TMO_ERR_INT);
+ }
+
+-static int ppc4xx_prng_data_read(struct crypto4xx_device *dev,
+- u8 *data, unsigned int max)
+-{
+- unsigned int i, curr = 0;
+- u32 val[2];
+-
+- do {
+- /* trigger PRN generation */
+- writel(PPC4XX_PRNG_CTRL_AUTO_EN,
+- dev->ce_base + CRYPTO4XX_PRNG_CTRL);
+-
+- for (i = 0; i < 1024; i++) {
+- /* usually 19 iterations are enough */
+- if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) &
+- CRYPTO4XX_PRNG_STAT_BUSY))
+- continue;
+-
+- val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0);
+- val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1);
+- break;
+- }
+- if (i == 1024)
+- return -ETIMEDOUT;
+-
+- if ((max - curr) >= 8) {
+- memcpy(data, &val, 8);
+- data += 8;
+- curr += 8;
+- } else {
+- /* copy only remaining bytes */
+- memcpy(data, &val, max - curr);
+- break;
+- }
+- } while (curr < max);
+-
+- return curr;
+-}
+-
+-static int crypto4xx_prng_generate(struct crypto_rng *tfm,
+- const u8 *src, unsigned int slen,
+- u8 *dstn, unsigned int dlen)
+-{
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+- struct crypto4xx_alg *amcc_alg;
+- struct crypto4xx_device *dev;
+- int ret;
+-
+- amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng);
+- dev = amcc_alg->dev;
+-
+- mutex_lock(&dev->core_dev->rng_lock);
+- ret = ppc4xx_prng_data_read(dev, dstn, dlen);
+- mutex_unlock(&dev->core_dev->rng_lock);
+- return ret;
+-}
+-
+-
+-static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- return 0;
+-}
+-
+ /*
+ * Supported Crypto Algorithms
+ */
+@@ -1312,18 +1239,6 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
+ .cra_module = THIS_MODULE,
+ },
+ } },
+- { .type = CRYPTO_ALG_TYPE_RNG, .u.rng = {
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "crypto4xx_rng",
+- .cra_priority = 300,
+- .cra_ctxsize = 0,
+- .cra_module = THIS_MODULE,
+- },
+- .generate = crypto4xx_prng_generate,
+- .seed = crypto4xx_prng_seed,
+- .seedsize = 0,
+- } },
+ };
+
+ /*
+@@ -1401,7 +1316,6 @@ static int crypto4xx_probe(struct platform_device *ofdev)
+ core_dev->dev->core_dev = core_dev;
+ core_dev->dev->is_revb = is_revb;
+ core_dev->device = dev;
+- mutex_init(&core_dev->rng_lock);
+ spin_lock_init(&core_dev->lock);
+ INIT_LIST_HEAD(&core_dev->dev->alg_list);
+ ratelimit_default_init(&core_dev->dev->aead_ratelimit);
+@@ -1479,7 +1393,6 @@ static int crypto4xx_remove(struct platform_device *ofdev)
+ tasklet_kill(&core_dev->tasklet);
+ /* Un-register with Linux CryptoAPI */
+ crypto4xx_unregister_alg(core_dev->dev);
+- mutex_destroy(&core_dev->rng_lock);
+ /* Free all allocated memory */
+ crypto4xx_stop_all(core_dev);
+
+diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
+index 0d83cde84cca9a..d8224bbe89ca27 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.h
++++ b/drivers/crypto/amcc/crypto4xx_core.h
+@@ -14,10 +14,8 @@
+ #define __CRYPTO4XX_CORE_H__
+
+ #include <linux/ratelimit.h>
+-#include <linux/mutex.h>
+ #include <linux/scatterlist.h>
+ #include <crypto/internal/aead.h>
+-#include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+ #include "crypto4xx_reg_def.h"
+ #include "crypto4xx_sa.h"
+@@ -111,7 +109,6 @@ struct crypto4xx_core_device {
+ u32 irq;
+ struct tasklet_struct tasklet;
+ spinlock_t lock;
+- struct mutex rng_lock;
+ };
+
+ struct crypto4xx_ctx {
+@@ -135,7 +132,6 @@ struct crypto4xx_alg_common {
+ union {
+ struct skcipher_alg cipher;
+ struct aead_alg aead;
+- struct rng_alg rng;
+ } u;
+ };
+
+diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
+index 1038061224da66..73d626308a8484 100644
+--- a/drivers/crypto/amcc/crypto4xx_reg_def.h
++++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
+@@ -90,20 +90,9 @@
+ #define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8
+ #define CRYPTO4XX_ENDIAN_CFG 0x000600d8
+
+-#define CRYPTO4XX_PRNG_STAT 0x00070000
+-#define CRYPTO4XX_PRNG_STAT_BUSY 0x1
+ #define CRYPTO4XX_PRNG_CTRL 0x00070004
+ #define CRYPTO4XX_PRNG_SEED_L 0x00070008
+ #define CRYPTO4XX_PRNG_SEED_H 0x0007000c
+-
+-#define CRYPTO4XX_PRNG_RES_0 0x00070020
+-#define CRYPTO4XX_PRNG_RES_1 0x00070024
+-#define CRYPTO4XX_PRNG_RES_2 0x00070028
+-#define CRYPTO4XX_PRNG_RES_3 0x0007002C
+-
+-#define CRYPTO4XX_PRNG_LFSR_L 0x00070030
+-#define CRYPTO4XX_PRNG_LFSR_H 0x00070034
+-
+ /*
+ * Initialize CRYPTO ENGINE registers, and memory bases.
+ */
+--
+2.53.0
+
--- /dev/null
+From 5b9da4dfe92071ca9cc8931956375077495fce67 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:42:54 -0700
+Subject: crypto: hisi-trng - Remove crypto_rng interface
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 216a7795ec210bdabd5dad42323eee70bbfc8d90 upstream.
+
+drivers/crypto/hisilicon/trng/trng.c exposes the same hardware through
+two completely separate interfaces, crypto_rng and hwrng. However, the
+implementation of this is buggy because it permits generation operations
+from these interfaces to run concurrently with each other, accessing the
+same registers. That is, hisi_trng_generate() synchronizes with itself
+but not with hisi_trng_read(). This results in potential repetition of
+output from the RNG, output of non-random values, etc.
+
+Fortunately, there's actually no point in hardware RNG drivers
+implementing the crypto_rng interface. It's not actually used by
+anything besides the "rng" algorithm type of AF_ALG, which in turn is
+not actually used in practice. Other crypto_rng hardware drivers are
+likewise being phased out, leaving just the hwrng support.
+
+Thus, remove it to simplify the code and avoid conflict (and confusion)
+with the hwrng interface which is the one that actually matters.
+
+Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/hisilicon/Kconfig | 1 -
+ drivers/crypto/hisilicon/trng/trng.c | 298 +--------------------------
+ 2 files changed, 2 insertions(+), 297 deletions(-)
+
+diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig
+index 743ce4fc3158c6..861c71a876e51d 100644
+--- a/drivers/crypto/hisilicon/Kconfig
++++ b/drivers/crypto/hisilicon/Kconfig
+@@ -79,6 +79,5 @@ config CRYPTO_DEV_HISI_TRNG
+ tristate "Support for HISI TRNG Driver"
+ depends on ARM64 && ACPI
+ select HW_RANDOM
+- select CRYPTO_RNG
+ help
+ Support for HiSilicon TRNG Driver.
+diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c
+index b2d9b5310b784c..6584ed051e0997 100644
+--- a/drivers/crypto/hisilicon/trng/trng.c
++++ b/drivers/crypto/hisilicon/trng/trng.c
+@@ -1,234 +1,27 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /* Copyright (c) 2019 HiSilicon Limited. */
+
+-#include <crypto/internal/rng.h>
+ #include <linux/acpi.h>
+-#include <linux/crypto.h>
+ #include <linux/err.h>
+ #include <linux/hw_random.h>
+ #include <linux/io.h>
+ #include <linux/iopoll.h>
+ #include <linux/kernel.h>
+-#include <linux/list.h>
+ #include <linux/module.h>
+-#include <linux/mutex.h>
+ #include <linux/platform_device.h>
+ #include <linux/random.h>
+
+ #define HISI_TRNG_REG 0x00F0
+ #define HISI_TRNG_BYTES 4
+ #define HISI_TRNG_QUALITY 512
+-#define HISI_TRNG_VERSION 0x01B8
+-#define HISI_TRNG_VER_V1 GENMASK(31, 0)
+ #define SLEEP_US 10
+ #define TIMEOUT_US 10000
+-#define SW_DRBG_NUM_SHIFT 2
+-#define SW_DRBG_KEY_BASE 0x082C
+-#define SW_DRBG_SEED(n) (SW_DRBG_KEY_BASE - ((n) << SW_DRBG_NUM_SHIFT))
+-#define SW_DRBG_SEED_REGS_NUM 12
+-#define SW_DRBG_SEED_SIZE 48
+-#define SW_DRBG_BLOCKS 0x0830
+-#define SW_DRBG_INIT 0x0834
+-#define SW_DRBG_GEN 0x083c
+-#define SW_DRBG_STATUS 0x0840
+-#define SW_DRBG_BLOCKS_NUM 4095
+-#define SW_DRBG_DATA_BASE 0x0850
+-#define SW_DRBG_DATA_NUM 4
+-#define SW_DRBG_DATA(n) (SW_DRBG_DATA_BASE - ((n) << SW_DRBG_NUM_SHIFT))
+-#define SW_DRBG_BYTES 16
+-#define SW_DRBG_ENABLE_SHIFT 12
+-#define SEED_SHIFT_24 24
+-#define SEED_SHIFT_16 16
+-#define SEED_SHIFT_8 8
+-#define SW_MAX_RANDOM_BYTES 65520
+-
+-struct hisi_trng_list {
+- struct mutex lock;
+- struct list_head list;
+- bool is_init;
+-};
+
+ struct hisi_trng {
+ void __iomem *base;
+- struct hisi_trng_list *trng_list;
+- struct list_head list;
+ struct hwrng rng;
+- u32 ver;
+- u32 ctx_num;
+- /* The bytes of the random number generated since the last seeding. */
+- u32 random_bytes;
+- struct mutex lock;
+-};
+-
+-struct hisi_trng_ctx {
+- struct hisi_trng *trng;
+ };
+
+-static atomic_t trng_active_devs;
+-static struct hisi_trng_list trng_devices;
+-static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait);
+-
+-static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
+-{
+- u32 val, seed_reg, i;
+- int ret;
+-
+- writel(0x0, trng->base + SW_DRBG_BLOCKS);
+-
+- for (i = 0; i < SW_DRBG_SEED_SIZE;
+- i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) {
+- val = seed[i] << SEED_SHIFT_24;
+- val |= seed[i + 1UL] << SEED_SHIFT_16;
+- val |= seed[i + 2UL] << SEED_SHIFT_8;
+- val |= seed[i + 3UL];
+-
+- seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM;
+- writel(val, trng->base + SW_DRBG_SEED(seed_reg));
+- }
+-
+- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT),
+- trng->base + SW_DRBG_BLOCKS);
+- writel(0x1, trng->base + SW_DRBG_INIT);
+- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
+- val, val & BIT(0), SLEEP_US, TIMEOUT_US);
+- if (ret) {
+- pr_err("failed to init trng(%d)\n", ret);
+- return -EIO;
+- }
+-
+- trng->random_bytes = 0;
+-
+- return 0;
+-}
+-
+-static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
+- struct hisi_trng *trng = ctx->trng;
+- int ret;
+-
+- if (slen < SW_DRBG_SEED_SIZE) {
+- pr_err("slen(%u) is not matched with trng(%d)\n", slen,
+- SW_DRBG_SEED_SIZE);
+- return -EINVAL;
+- }
+-
+- mutex_lock(&trng->lock);
+- ret = hisi_trng_set_seed(trng, seed);
+- mutex_unlock(&trng->lock);
+-
+- return ret;
+-}
+-
+-static int hisi_trng_reseed(struct hisi_trng *trng)
+-{
+- u8 seed[SW_DRBG_SEED_SIZE];
+- int size;
+-
+- if (!trng->random_bytes)
+- return 0;
+-
+- size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false);
+- if (size != SW_DRBG_SEED_SIZE)
+- return -EIO;
+-
+- return hisi_trng_set_seed(trng, seed);
+-}
+-
+-static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen)
+-{
+- u32 data[SW_DRBG_DATA_NUM];
+- u32 currsize = 0;
+- u32 val = 0;
+- int ret;
+- u32 i;
+-
+- ret = hisi_trng_reseed(trng);
+- if (ret)
+- return ret;
+-
+- do {
+- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
+- val, val & BIT(1), SLEEP_US, TIMEOUT_US);
+- if (ret) {
+- pr_err("failed to generate random number(%d)!\n", ret);
+- break;
+- }
+-
+- for (i = 0; i < SW_DRBG_DATA_NUM; i++)
+- data[i] = readl(trng->base + SW_DRBG_DATA(i));
+-
+- if (dlen - currsize >= SW_DRBG_BYTES) {
+- memcpy(dstn + currsize, data, SW_DRBG_BYTES);
+- currsize += SW_DRBG_BYTES;
+- } else {
+- memcpy(dstn + currsize, data, dlen - currsize);
+- currsize = dlen;
+- }
+-
+- trng->random_bytes += SW_DRBG_BYTES;
+- writel(0x1, trng->base + SW_DRBG_GEN);
+- } while (currsize < dlen);
+-
+- return ret;
+-}
+-
+-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dstn, unsigned int dlen)
+-{
+- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
+- struct hisi_trng *trng = ctx->trng;
+- unsigned int currsize = 0;
+- unsigned int block_size;
+- int ret;
+-
+- if (!dstn || !dlen) {
+- pr_err("output is error, dlen %u!\n", dlen);
+- return -EINVAL;
+- }
+-
+- do {
+- block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES);
+- mutex_lock(&trng->lock);
+- ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size);
+- mutex_unlock(&trng->lock);
+- if (ret)
+- return ret;
+- currsize += block_size;
+- } while (currsize < dlen);
+-
+- return 0;
+-}
+-
+-static int hisi_trng_init(struct crypto_tfm *tfm)
+-{
+- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
+- struct hisi_trng *trng;
+- u32 ctx_num = ~0;
+-
+- mutex_lock(&trng_devices.lock);
+- list_for_each_entry(trng, &trng_devices.list, list) {
+- if (trng->ctx_num < ctx_num) {
+- ctx_num = trng->ctx_num;
+- ctx->trng = trng;
+- }
+- }
+- ctx->trng->ctx_num++;
+- mutex_unlock(&trng_devices.lock);
+-
+- return 0;
+-}
+-
+-static void hisi_trng_exit(struct crypto_tfm *tfm)
+-{
+- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
+-
+- mutex_lock(&trng_devices.lock);
+- ctx->trng->ctx_num--;
+- mutex_unlock(&trng_devices.lock);
+-}
+-
+ static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+ {
+ struct hisi_trng *trng;
+@@ -260,42 +53,6 @@ static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+ return currsize;
+ }
+
+-static struct rng_alg hisi_trng_alg = {
+- .generate = hisi_trng_generate,
+- .seed = hisi_trng_seed,
+- .seedsize = SW_DRBG_SEED_SIZE,
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "hisi_stdrng",
+- .cra_priority = 300,
+- .cra_ctxsize = sizeof(struct hisi_trng_ctx),
+- .cra_module = THIS_MODULE,
+- .cra_init = hisi_trng_init,
+- .cra_exit = hisi_trng_exit,
+- },
+-};
+-
+-static void hisi_trng_add_to_list(struct hisi_trng *trng)
+-{
+- mutex_lock(&trng_devices.lock);
+- list_add_tail(&trng->list, &trng_devices.list);
+- mutex_unlock(&trng_devices.lock);
+-}
+-
+-static int hisi_trng_del_from_list(struct hisi_trng *trng)
+-{
+- int ret = -EBUSY;
+-
+- mutex_lock(&trng_devices.lock);
+- if (!trng->ctx_num) {
+- list_del(&trng->list);
+- ret = 0;
+- }
+- mutex_unlock(&trng_devices.lock);
+-
+- return ret;
+-}
+-
+ static int hisi_trng_probe(struct platform_device *pdev)
+ {
+ struct hisi_trng *trng;
+@@ -305,70 +62,20 @@ static int hisi_trng_probe(struct platform_device *pdev)
+ if (!trng)
+ return -ENOMEM;
+
+- platform_set_drvdata(pdev, trng);
+-
+ trng->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(trng->base))
+ return PTR_ERR(trng->base);
+
+- trng->ctx_num = 0;
+- trng->random_bytes = SW_MAX_RANDOM_BYTES;
+- mutex_init(&trng->lock);
+- trng->ver = readl(trng->base + HISI_TRNG_VERSION);
+- if (!trng_devices.is_init) {
+- INIT_LIST_HEAD(&trng_devices.list);
+- mutex_init(&trng_devices.lock);
+- trng_devices.is_init = true;
+- }
+-
+- hisi_trng_add_to_list(trng);
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_inc_return(&trng_active_devs) == 1) {
+- ret = crypto_register_rng(&hisi_trng_alg);
+- if (ret) {
+- dev_err(&pdev->dev,
+- "failed to register crypto(%d)\n", ret);
+- atomic_dec_return(&trng_active_devs);
+- goto err_remove_from_list;
+- }
+- }
+-
+ trng->rng.name = pdev->name;
+ trng->rng.read = hisi_trng_read;
+ trng->rng.quality = HISI_TRNG_QUALITY;
++
+ ret = devm_hwrng_register(&pdev->dev, &trng->rng);
+- if (ret) {
++ if (ret)
+ dev_err(&pdev->dev, "failed to register hwrng: %d!\n", ret);
+- goto err_crypto_unregister;
+- }
+-
+- return ret;
+-
+-err_crypto_unregister:
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_dec_return(&trng_active_devs) == 0)
+- crypto_unregister_rng(&hisi_trng_alg);
+-
+-err_remove_from_list:
+- hisi_trng_del_from_list(trng);
+ return ret;
+ }
+
+-static int hisi_trng_remove(struct platform_device *pdev)
+-{
+- struct hisi_trng *trng = platform_get_drvdata(pdev);
+-
+- /* Wait until the task is finished */
+- while (hisi_trng_del_from_list(trng))
+- ;
+-
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_dec_return(&trng_active_devs) == 0)
+- crypto_unregister_rng(&hisi_trng_alg);
+-
+- return 0;
+-}
+-
+ static const struct acpi_device_id hisi_trng_acpi_match[] = {
+ { "HISI02B3", 0 },
+ { }
+@@ -377,7 +84,6 @@ MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi_match);
+
+ static struct platform_driver hisi_trng_driver = {
+ .probe = hisi_trng_probe,
+- .remove = hisi_trng_remove,
+ .driver = {
+ .name = "hisi-trng-v2",
+ .acpi_match_table = ACPI_PTR(hisi_trng_acpi_match),
+--
+2.53.0
+
--- /dev/null
+From 554317153efcfafd2222d23599e6b664f2001d73 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:50:58 -0700
+Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit b2c41fa9dd8fc740c489e060b199165771f268d1 upstream.
+
+Remove sun4i_ss_rng, as it is insecure and unused:
+
+- It has multiple vulnerabilities. sun4i_ss_prng_seed() is missing
+ locking and has a buffer overflow. sun4i_ss_prng_generate() fails to
+ fill the entire buffer with cryptographic random bytes, because it
+ rounds the destination length down and also doesn't actually wait for
+ the hardware to be ready before pulling bytes from it.
+
+- No user of this code is known. It's usable only theoretically via the
+ "rng" algorithm type of AF_ALG. But userspace actually just uses the
+ actual Linux RNG (/dev/random etc) instead. And rng_algs don't
+ contribute entropy to the actual Linux RNG either. (This may have
+ been confused with hwrng, which does contribute entropy.)
+
+The sun4i_ss_prng_seed() buffer overflow was reported by Tianchu Chen
+and discovered by Atuin - Automated Vulnerability Discovery Engine
+
+There's no point in fixing all these vulnerabilities individually when
+this is unused code, so let's just remove it.
+
+Fixes: b8ae5c7387ad ("crypto: sun4i-ss - support the Security System PRNG")
+Cc: stable@vger.kernel.org
+Reported-by: Tianchu Chen <flynnnchen@tencent.com>
+Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/
+Acked-by: Corentin LABBE <clabbe.montjoie@gmail.com>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/configs/sunxi_defconfig | 1 -
+ drivers/crypto/allwinner/Kconfig | 8 ---
+ drivers/crypto/allwinner/sun4i-ss/Makefile | 1 -
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-core.c | 36 ----------
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-prng.c | 69 -------------------
+ drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h | 20 ------
+ 6 files changed, 135 deletions(-)
+ delete mode 100644 drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+
+diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
+index a83d29fed17563..f4b8d8f7dbefbb 100644
+--- a/arch/arm/configs/sunxi_defconfig
++++ b/arch/arm/configs/sunxi_defconfig
+@@ -170,7 +170,6 @@ CONFIG_ROOT_NFS=y
+ CONFIG_NLS_CODEPAGE_437=y
+ CONFIG_NLS_ISO8859_1=y
+ CONFIG_CRYPTO_DEV_SUN4I_SS=y
+-CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG=y
+ CONFIG_CRYPTO_DEV_SUN8I_CE=y
+ CONFIG_CRYPTO_DEV_SUN8I_SS=y
+ CONFIG_DMA_CMA=y
+diff --git a/drivers/crypto/allwinner/Kconfig b/drivers/crypto/allwinner/Kconfig
+index b8e75210a0e315..06ea0e9fe6f22f 100644
+--- a/drivers/crypto/allwinner/Kconfig
++++ b/drivers/crypto/allwinner/Kconfig
+@@ -24,14 +24,6 @@ config CRYPTO_DEV_SUN4I_SS
+ To compile this driver as a module, choose M here: the module
+ will be called sun4i-ss.
+
+-config CRYPTO_DEV_SUN4I_SS_PRNG
+- bool "Support for Allwinner Security System PRNG"
+- depends on CRYPTO_DEV_SUN4I_SS
+- select CRYPTO_RNG
+- help
+- Select this option if you want to provide kernel-side support for
+- the Pseudo-Random Number Generator found in the Security System.
+-
+ config CRYPTO_DEV_SUN4I_SS_DEBUG
+ bool "Enable sun4i-ss stats"
+ depends on CRYPTO_DEV_SUN4I_SS
+diff --git a/drivers/crypto/allwinner/sun4i-ss/Makefile b/drivers/crypto/allwinner/sun4i-ss/Makefile
+index c0a2797d316827..06a9ae81f9f808 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/Makefile
++++ b/drivers/crypto/allwinner/sun4i-ss/Makefile
+@@ -1,4 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sun4i-ss.o
+ sun4i-ss-y += sun4i-ss-core.o sun4i-ss-hash.o sun4i-ss-cipher.o
+-sun4i-ss-$(CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG) += sun4i-ss-prng.o
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+index 006e40133c284b..761196d9899924 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+@@ -216,23 +216,6 @@ static struct sun4i_ss_alg_template ss_algs[] = {
+ }
+ }
+ },
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+-{
+- .type = CRYPTO_ALG_TYPE_RNG,
+- .alg.rng = {
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "sun4i_ss_rng",
+- .cra_priority = 300,
+- .cra_ctxsize = 0,
+- .cra_module = THIS_MODULE,
+- },
+- .generate = sun4i_ss_prng_generate,
+- .seed = sun4i_ss_prng_seed,
+- .seedsize = SS_SEED_LEN / BITS_PER_BYTE,
+- }
+-},
+-#endif
+ };
+
+ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
+@@ -250,12 +233,6 @@ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
+ ss_algs[i].stat_req, ss_algs[i].stat_opti, ss_algs[i].stat_fb,
+ ss_algs[i].stat_bytes);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",
+- ss_algs[i].alg.rng.base.cra_driver_name,
+- ss_algs[i].alg.rng.base.cra_name,
+- ss_algs[i].stat_req, ss_algs[i].stat_bytes);
+- break;
+ case CRYPTO_ALG_TYPE_AHASH:
+ seq_printf(seq, "%s %s reqs=%lu\n",
+ ss_algs[i].alg.hash.halg.base.cra_driver_name,
+@@ -474,13 +451,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ goto error_alg;
+ }
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- err = crypto_register_rng(&ss_algs[i].alg.rng);
+- if (err) {
+- dev_err(ss->dev, "Fail to register %s\n",
+- ss_algs[i].alg.rng.base.cra_name);
+- }
+- break;
+ }
+ }
+
+@@ -500,9 +470,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+ error_pm:
+@@ -523,9 +490,6 @@ static int sun4i_ss_remove(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+deleted file mode 100644
+index 491fcb7b81b40b..00000000000000
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
++++ /dev/null
+@@ -1,69 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-#include "sun4i-ss.h"
+-
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- memcpy(algt->ss->seed, seed, slen);
+-
+- return 0;
+-}
+-
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+- int i, err;
+- u32 v;
+- u32 *data = (u32 *)dst;
+- const u32 mode = SS_OP_PRNG | SS_PRNG_CONTINUE | SS_ENABLED;
+- size_t len;
+- struct sun4i_ss_ctx *ss;
+- unsigned int todo = (dlen / 4) * 4;
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- ss = algt->ss;
+-
+- err = pm_runtime_resume_and_get(ss->dev);
+- if (err < 0)
+- return err;
+-
+- if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) {
+- algt->stat_req++;
+- algt->stat_bytes += todo;
+- }
+-
+- spin_lock_bh(&ss->slock);
+-
+- writel(mode, ss->base + SS_CTL);
+-
+- while (todo > 0) {
+- /* write the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++)
+- writel(ss->seed[i], ss->base + SS_KEY0 + i * 4);
+-
+- /* Read the random data */
+- len = min_t(size_t, SS_DATA_LEN / BITS_PER_BYTE, todo);
+- readsl(ss->base + SS_TXFIFO, data, len / 4);
+- data += len / 4;
+- todo -= len;
+-
+- /* Update the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++) {
+- v = readl(ss->base + SS_KEY0 + i * 4);
+- ss->seed[i] = v;
+- }
+- }
+-
+- writel(0, ss->base + SS_CTL);
+- spin_unlock_bh(&ss->slock);
+-
+- pm_runtime_put(ss->dev);
+-
+- return 0;
+-}
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+index ba59c7a4882522..26196d20d7394d 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+@@ -31,8 +31,6 @@
+ #include <crypto/internal/skcipher.h>
+ #include <crypto/aes.h>
+ #include <crypto/internal/des.h>
+-#include <crypto/internal/rng.h>
+-#include <crypto/rng.h>
+
+ #define SS_CTL 0x00
+ #define SS_KEY0 0x04
+@@ -62,10 +60,6 @@
+
+ /* SS_CTL configuration values */
+
+-/* PRNG generator mode - bit 15 */
+-#define SS_PRNG_ONESHOT (0 << 15)
+-#define SS_PRNG_CONTINUE (1 << 15)
+-
+ /* IV mode for hash */
+ #define SS_IV_ARBITRARY (1 << 14)
+
+@@ -94,14 +88,10 @@
+ #define SS_OP_3DES (2 << 4)
+ #define SS_OP_SHA1 (3 << 4)
+ #define SS_OP_MD5 (4 << 4)
+-#define SS_OP_PRNG (5 << 4)
+
+ /* Data end bit - bit 2 */
+ #define SS_DATA_END (1 << 2)
+
+-/* PRNG start bit - bit 1 */
+-#define SS_PRNG_START (1 << 1)
+-
+ /* SS Enable bit - bit 0 */
+ #define SS_DISABLED (0 << 0)
+ #define SS_ENABLED (1 << 0)
+@@ -128,9 +118,6 @@
+ #define SS_RXFIFO_EMP_INT_ENABLE (1 << 2)
+ #define SS_TXFIFO_AVA_INT_ENABLE (1 << 0)
+
+-#define SS_SEED_LEN 192
+-#define SS_DATA_LEN 160
+-
+ /*
+ * struct ss_variant - Describe SS hardware variant
+ * @sha1_in_be: The SHA1 digest is given by SS in BE, and so need to be inverted.
+@@ -151,9 +138,6 @@ struct sun4i_ss_ctx {
+ char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */
+ char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */
+ spinlock_t slock; /* control the use of the device */
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+- u32 seed[SS_SEED_LEN / BITS_PER_LONG];
+-#endif
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_stats;
+ };
+@@ -164,7 +148,6 @@ struct sun4i_ss_alg_template {
+ union {
+ struct skcipher_alg crypto;
+ struct ahash_alg hash;
+- struct rng_alg rng;
+ } alg;
+ struct sun4i_ss_ctx *ss;
+ unsigned long stat_req;
+@@ -231,6 +214,3 @@ int sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+ int sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen);
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen);
+--
+2.53.0
+
net-dsa-tag_ksz-do-not-rely-on-skb_mac_header-in-tx-.patch
nvmet-tcp-check-init_failed-before-nvmet_req_uninit-in-digest-error-path.patch
nvmet-tcp-fix-potential-uaf-when-ddgst-mismatch.patch
+crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
+x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch
+crypto-crypto4xx-remove-ahash-related-code.patch
+crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch
+crypto-af_alg-remove-zero-copy-support-from-skcipher.patch
+crypto-hisi-trng-remove-crypto_rng-interface.patch
--- /dev/null
+From a2b9962b96dd02e316e920c871329de562a19af0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 12:04:30 -0400
+Subject: x86/mm: Fix check/use ordering in switch_mm_irqs_off()
+
+From: Stephen Dolan <sdolan@janestreet.com>
+
+This is a stable-specific fix. There is no single upstream commit to
+cherry-pick; the equivalent mainline fix is commit 83b0177a6c48
+("x86/mm: Fix SMP ordering in switch_mm_irqs_off()"), which is in
+v6.18 but does not apply to these trees because the surrounding code
+was refactored.
+
+The backports of commit fea4e317f9e7 ("x86/mm: Eliminate window where
+TLB flushes may be inadvertently skipped") -- the fix for
+CVE-2025-37964 -- to the 6.1, 6.6 and 6.12 trees ended up with two
+code blocks in the wrong order relative to mainline. The fix depends
+on setting cpu_tlbstate.loaded_mm to LOADED_MM_SWITCHING *before*
+reading tlb_gen, so that a concurrent TLB shootdown either sees
+LOADED_MM_SWITCHING and sends the IPI, or the switching CPU sees the
+updated tlb_gen. In the stable trees the write of LOADED_MM_SWITCHING
+was placed after the tlb_gen read, so the race window fea4e317f9e7 was
+meant to close is still open and CVE-2025-37964 is unfixed there:
+a process can be left running with stale TLB entries, which typically
+manifests as rare, hard-to-bisect memory corruption or segfaults.
+
+This has been confirmed by several independent parties:
+
+ - reproduced on 6.1.y/6.6.y/6.12.y with the test program in [1],
+ and confirmed fixed by this patch
+ - Seth Forshee saw segfaults on 6.12.y within ~30 minutes of running
+ a test workload; with this patch it ran 18 hours cleanly [2]
+ - Greg Thelen reports 6.6.y- and 6.12.y-based test failures fixed by
+ this patch [3]
+
+Dave Hansen acked the patch [4] and has no objection to it going into
+stable [5].
+
+The patch below is against 6.12.y; the identical change applies to
+6.1.y and 6.6.y. (The cpumask_test_cpu()/smp_mb() portion of the
+mainline fix is not needed here because commit 209954cbc7d0
+("x86/mm/tlb: Update mm_cpumask lazily") was never backported to these
+trees.)
+
+[1] https://lore.kernel.org/lkml/CAHDw0oGd0B4=uuv8NGqbUQ_ZVmSheU2bN70e4QhFXWvuAZdt2w@mail.gmail.com/
+[2] https://lore.kernel.org/lkml/aZYWXe739XUJrBld@do-x1carbon/
+[3] https://lore.kernel.org/lkml/CAHH2K0brx9omC9QYyB6Lio3t_1Lf8v=VaFoiaG23UgQ-aec89Q@mail.gmail.com/
+[4] https://lore.kernel.org/lkml/281e8018-5506-4a79-8775-e0de7e58b95f@intel.com/
+[5] https://lore.kernel.org/lkml/86421ee5-5332-46c2-bb48-d40310b818be@intel.com/
+
+Fixes: fea4e317f9e7 ("x86/mm: Eliminate window where TLB flushes may be inadvertently skipped") # 6.1.y/6.6.y/6.12.y backports
+Acked-by: Dave Hansen <dave.hansen@intel.com>
+Tested-by: Seth Forshee <sforshee@kernel.org>
+Tested-by: Eric Hagberg <ehagberg@janestreet.com>
+Signed-off-by: Stephen Dolan <sdolan@janestreet.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/mm/tlb.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
+index 4918268d20074d..63620648f92d74 100644
+--- a/arch/x86/mm/tlb.c
++++ b/arch/x86/mm/tlb.c
+@@ -597,6 +597,14 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
+ */
+ cond_mitigation(tsk);
+
++ /*
++ * Indicate that CR3 is about to change. nmi_uaccess_okay()
++ * and others are sensitive to the window where mm_cpumask(),
++ * CR3 and cpu_tlbstate.loaded_mm are not all in sync.
++ */
++ this_cpu_write(cpu_tlbstate.loaded_mm, LOADED_MM_SWITCHING);
++ barrier();
++
+ /*
+ * Stop remote flushes for the previous mm.
+ * Skip kernel threads; we never send init_mm TLB flushing IPIs,
+@@ -616,14 +624,6 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
+ next_tlb_gen = atomic64_read(&next->context.tlb_gen);
+
+ choose_new_asid(next, next_tlb_gen, &new_asid, &need_flush);
+-
+- /*
+- * Indicate that CR3 is about to change. nmi_uaccess_okay()
+- * and others are sensitive to the window where mm_cpumask(),
+- * CR3 and cpu_tlbstate.loaded_mm are not all in sync.
+- */
+- this_cpu_write(cpu_tlbstate.loaded_mm, LOADED_MM_SWITCHING);
+- barrier();
+ }
+
+ if (need_flush) {
+--
+2.53.0
+
--- /dev/null
+From 1dc25d36dd60d94844a53f31401e3557b73b06c2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 19:29:20 +0200
+Subject: af_unix: Don't check SOCK_DEAD in unix_stream_read_skb().
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit 772f01049c4b722b28b3f7025b4996379f127ebf ]
+
+unix_stream_read_skb() checks SOCK_DEAD only when the dequeued skb is
+OOB skb.
+
+unix_stream_read_skb() is called for a SOCK_STREAM socket in SOCKMAP
+when data is sent to it.
+
+The function is invoked via sk_psock_verdict_data_ready(), which is
+set to sk->sk_data_ready().
+
+During sendmsg(), we check if the receiver has SOCK_DEAD, so there
+is no point in checking it again later in ->read_skb().
+
+Also, unix_read_skb() for SOCK_DGRAM does not have the test either.
+
+Let's remove the SOCK_DEAD test in unix_stream_read_skb().
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://patch.msgid.link/20250702223606.1054680-3-kuniyu@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/unix/af_unix.c | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index f50049ea54a5a4..a18a4b0229707f 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -2737,14 +2737,6 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
+ if (unlikely(skb == READ_ONCE(u->oob_skb))) {
+ bool drop = false;
+
+- unix_state_lock(sk);
+-
+- if (sock_flag(sk, SOCK_DEAD)) {
+- unix_state_unlock(sk);
+- kfree_skb_reason(skb, SKB_DROP_REASON_SOCKET_CLOSE);
+- return -ECONNRESET;
+- }
+-
+ spin_lock(&sk->sk_receive_queue.lock);
+ if (likely(skb == u->oob_skb)) {
+ WRITE_ONCE(u->oob_skb, NULL);
+@@ -2752,8 +2744,6 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
+ }
+ spin_unlock(&sk->sk_receive_queue.lock);
+
+- unix_state_unlock(sk);
+-
+ if (drop) {
+ kfree_skb_reason(skb, SKB_DROP_REASON_UNIX_SKIP_OOB);
+ return -EAGAIN;
+--
+2.53.0
+
--- /dev/null
+From f71d457b4a0a913b683e633c3711847d15d54b3b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 19:29:19 +0200
+Subject: af_unix: Don't hold unix_state_lock() in __unix_dgram_recvmsg().
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit b429a5ad19cb4efe63d18388a2a4deebcba742c6 ]
+
+When __skb_try_recv_datagram() returns NULL in __unix_dgram_recvmsg(),
+we hold unix_state_lock() unconditionally.
+
+This is because SOCK_SEQPACKET sk needs to return EOF in case its peer
+has been close()d concurrently.
+
+This behaviour totally depends on the timing of the peer's close() and
+reading sk->sk_shutdown, and taking the lock does not play a role.
+
+Let's drop the lock from __unix_dgram_recvmsg() and use READ_ONCE().
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Link: https://patch.msgid.link/20250702223606.1054680-2-kuniyu@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/unix/af_unix.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index c64d8ee0ede435..f50049ea54a5a4 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -2463,12 +2463,10 @@ int __unix_dgram_recvmsg(struct sock *sk, struct msghdr *msg, size_t size,
+ &err, &timeo, last));
+
+ if (!skb) { /* implies iolock unlocked */
+- unix_state_lock(sk);
+ /* Signal EOF on disconnected non-blocking SEQPACKET socket. */
+ if (sk->sk_type == SOCK_SEQPACKET && err == -EAGAIN &&
+- (sk->sk_shutdown & RCV_SHUTDOWN))
++ (READ_ONCE(sk->sk_shutdown) & RCV_SHUTDOWN))
+ err = 0;
+- unix_state_unlock(sk);
+ goto out;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From e5b6125d20982675dafda33db0e9b73759272ed9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 19:29:21 +0200
+Subject: af_unix: Don't use skb_recv_datagram() in unix_stream_read_skb().
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit d0aac85449dec992bb8dc2503f2cb9e94ef436db ]
+
+unix_stream_read_skb() calls skb_recv_datagram() with MSG_DONTWAIT,
+which is mostly equivalent to sock_error(sk) + skb_dequeue().
+
+In the following patch, we will add a new field to cache the number
+of bytes in the receive queue. Then, we want to avoid introducing
+atomic ops in the fast path, so we will reuse the receive queue lock.
+
+As a preparation for the change, let's not use skb_recv_datagram()
+in unix_stream_read_skb().
+
+Note that sock_error() is now moved out of the u->iolock mutex as
+the mutex does not synchronise the peer's close() at all.
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://patch.msgid.link/20250702223606.1054680-4-kuniyu@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/unix/af_unix.c | 39 ++++++++++++++++++++++-----------------
+ 1 file changed, 22 insertions(+), 17 deletions(-)
+
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index a18a4b0229707f..f1e81843c1b0bc 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -2720,6 +2720,7 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,
+
+ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
+ {
++ struct sk_buff_head *queue = &sk->sk_receive_queue;
+ struct unix_sock *u = unix_sk(sk);
+ struct sk_buff *skb;
+ int err;
+@@ -2727,30 +2728,34 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
+ if (unlikely(READ_ONCE(sk->sk_state) != TCP_ESTABLISHED))
+ return -ENOTCONN;
+
+- mutex_lock(&u->iolock);
+- skb = skb_recv_datagram(sk, MSG_DONTWAIT, &err);
+- mutex_unlock(&u->iolock);
+- if (!skb)
++ err = sock_error(sk);
++ if (err)
+ return err;
+
+-#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
+- if (unlikely(skb == READ_ONCE(u->oob_skb))) {
+- bool drop = false;
++ mutex_lock(&u->iolock);
++ spin_lock(&queue->lock);
+
+- spin_lock(&sk->sk_receive_queue.lock);
+- if (likely(skb == u->oob_skb)) {
+- WRITE_ONCE(u->oob_skb, NULL);
+- drop = true;
+- }
+- spin_unlock(&sk->sk_receive_queue.lock);
++ skb = __skb_dequeue(queue);
++ if (!skb) {
++ spin_unlock(&queue->lock);
++ mutex_unlock(&u->iolock);
++ return -EAGAIN;
++ }
+
+- if (drop) {
+- kfree_skb_reason(skb, SKB_DROP_REASON_UNIX_SKIP_OOB);
+- return -EAGAIN;
+- }
++#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
++ if (skb == u->oob_skb) {
++ WRITE_ONCE(u->oob_skb, NULL);
++ spin_unlock(&queue->lock);
++ mutex_unlock(&u->iolock);
++
++ kfree_skb_reason(skb, SKB_DROP_REASON_UNIX_SKIP_OOB);
++ return -EAGAIN;
+ }
+ #endif
+
++ spin_unlock(&queue->lock);
++ mutex_unlock(&u->iolock);
++
+ return recv_actor(sk, skb);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From f15c5996e25b5ea3d3a65a3b05aa2757bea462e4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 19:29:22 +0200
+Subject: af_unix: Drop all SCM attributes for SOCKMAP.
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit 965dc93481d1b80d341bdd16c27b16fe197175ee ]
+
+SOCKMAP can hide inflight fd from AF_UNIX GC.
+
+When a socket in SOCKMAP receives skb with inflight fd,
+sk_psock_verdict_data_ready() looks up the mapped socket and
+enqueue skb to its psock->ingress_skb.
+
+Since neither the old nor the new GC can inspect the psock
+queue, the hidden skb leaks the inflight sockets. Note that
+this cannot be detected via kmemleak because inflight sockets
+are linked to a global list.
+
+In addition, SOCKMAP redirect breaks the Tarjan-based GC's
+assumption that unix_edge.successor is always alive, which
+is no longer true once skb is redirected, resulting in
+use-after-free below. [0]
+
+Moreover, SOCKMAP does not call scm_stat_del() properly,
+so unix_show_fdinfo() could report an incorrect fd count.
+
+sk_msg_recvmsg() does not support any SCM attributes in the
+first place.
+
+Let's drop all SCM attributes before passing skb to the
+SOCKMAP layer.
+
+[0]:
+BUG: KASAN: slab-use-after-free in unix_del_edges (net/unix/garbage.c:118 net/unix/garbage.c:181 net/unix/garbage.c:251)
+Read of size 8 at addr ffff888125362670 by task kworker/56:1/496
+
+CPU: 56 UID: 0 PID: 496 Comm: kworker/56:1 Not tainted 7.0.0-rc7-00263-gb9d8b856689d #3 PREEMPT(lazy)
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
+Workqueue: events sk_psock_backlog
+Call Trace:
+ <TASK>
+ dump_stack_lvl (lib/dump_stack.c:122)
+ print_report (mm/kasan/report.c:379)
+ kasan_report (mm/kasan/report.c:597)
+ unix_del_edges (net/unix/garbage.c:118 net/unix/garbage.c:181 net/unix/garbage.c:251)
+ unix_destroy_fpl (net/unix/garbage.c:317)
+ unix_destruct_scm (./include/net/scm.h:80 ./include/net/scm.h:86 net/unix/af_unix.c:1976)
+ sk_psock_backlog (./include/linux/skbuff.h:?)
+ process_scheduled_works (kernel/workqueue.c:?)
+ worker_thread (kernel/workqueue.c:?)
+ kthread (kernel/kthread.c:438)
+ ret_from_fork (arch/x86/kernel/process.c:164)
+ ret_from_fork_asm (arch/x86/entry/entry_64.S:258)
+ </TASK>
+
+Allocated by task 955:
+ kasan_save_track (mm/kasan/common.c:58 mm/kasan/common.c:78)
+ __kasan_slab_alloc (mm/kasan/common.c:369)
+ kmem_cache_alloc_noprof (mm/slub.c:4539)
+ sk_prot_alloc (net/core/sock.c:2240)
+ sk_alloc (net/core/sock.c:2301)
+ unix_create1 (net/unix/af_unix.c:1099)
+ unix_create (net/unix/af_unix.c:1169)
+ __sock_create (net/socket.c:1606)
+ __sys_socketpair (net/socket.c:1811)
+ __x64_sys_socketpair (net/socket.c:1863 net/socket.c:1860 net/socket.c:1860)
+ do_syscall_64 (arch/x86/entry/syscall_64.c:?)
+ entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
+
+Freed by task 496:
+ kasan_save_track (mm/kasan/common.c:58 mm/kasan/common.c:78)
+ kasan_save_free_info (mm/kasan/generic.c:587)
+ __kasan_slab_free (mm/kasan/common.c:287)
+ kmem_cache_free (mm/slub.c:6165)
+ __sk_destruct (net/core/sock.c:2282 net/core/sock.c:2384)
+ sk_psock_destroy (./include/net/sock.h:?)
+ process_scheduled_works (kernel/workqueue.c:?)
+ worker_thread (kernel/workqueue.c:?)
+ kthread (kernel/kthread.c:438)
+ ret_from_fork (arch/x86/kernel/process.c:164)
+ ret_from_fork_asm (arch/x86/entry/entry_64.S:258)
+
+Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()")
+Fixes: 77462de14a43 ("af_unix: Add read_sock for stream socket types")
+Reported-by: Xingyu Jin <xingyuj@google.com>
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://patch.msgid.link/20260415184830.3988432-1-kuniyu@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/unix/af_unix.c | 35 +++++++++++++++++++++++++++--------
+ 1 file changed, 27 insertions(+), 8 deletions(-)
+
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index f1e81843c1b0bc..23d94a08e48157 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -1884,16 +1884,19 @@ static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)
+
+ static void unix_destruct_scm(struct sk_buff *skb)
+ {
+- struct scm_cookie scm;
++ struct scm_cookie scm = {};
++
++ swap(scm.pid, UNIXCB(skb).pid);
+
+- memset(&scm, 0, sizeof(scm));
+- scm.pid = UNIXCB(skb).pid;
+ if (UNIXCB(skb).fp)
+ unix_detach_fds(&scm, skb);
+
+- /* Alas, it calls VFS */
+- /* So fscking what? fput() had been SMP-safe since the last Summer */
+ scm_destroy(&scm);
++}
++
++static void unix_wfree(struct sk_buff *skb)
++{
++ unix_destruct_scm(skb);
+ sock_wfree(skb);
+ }
+
+@@ -1909,7 +1912,7 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
+ if (scm->fp && send_fds)
+ err = unix_attach_fds(scm, skb);
+
+- skb->destructor = unix_destruct_scm;
++ skb->destructor = unix_wfree;
+ return err;
+ }
+
+@@ -1970,6 +1973,13 @@ static void scm_stat_del(struct sock *sk, struct sk_buff *skb)
+ }
+ }
+
++static void unix_orphan_scm(struct sock *sk, struct sk_buff *skb)
++{
++ scm_stat_del(sk, skb);
++ unix_destruct_scm(skb);
++ skb->destructor = sock_wfree;
++}
++
+ /*
+ * Send AF_UNIX data.
+ */
+@@ -2556,10 +2566,16 @@ static int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
+ int err;
+
+ mutex_lock(&u->iolock);
++
+ skb = skb_recv_datagram(sk, MSG_DONTWAIT, &err);
+- mutex_unlock(&u->iolock);
+- if (!skb)
++ if (!skb) {
++ mutex_unlock(&u->iolock);
+ return err;
++ }
++
++ unix_orphan_scm(sk, skb);
++
++ mutex_unlock(&u->iolock);
+
+ return recv_actor(sk, skb);
+ }
+@@ -2754,6 +2770,9 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
+ #endif
+
+ spin_unlock(&queue->lock);
++
++ unix_orphan_scm(sk, skb);
++
+ mutex_unlock(&u->iolock);
+
+ return recv_actor(sk, skb);
+--
+2.53.0
+
--- /dev/null
+From 87d0eb85095af94f60d0625df2ffe6d3eb407ac8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 19:29:18 +0200
+Subject: af_unix/scm: fix whitespace errors
+
+From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
+
+[ Upstream commit 2b9996417e4ec231c91818f9ea8107ae62ef75ad ]
+
+Fix whitespace/formatting errors.
+
+Cc: linux-kernel@vger.kernel.org
+Cc: netdev@vger.kernel.org
+Cc: David S. Miller <davem@davemloft.net>
+Cc: Eric Dumazet <edumazet@google.com>
+Cc: Jakub Kicinski <kuba@kernel.org>
+Cc: Paolo Abeni <pabeni@redhat.com>
+Cc: Simon Horman <horms@kernel.org>
+Cc: Leon Romanovsky <leon@kernel.org>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Christian Brauner <brauner@kernel.org>
+Cc: Kuniyuki Iwashima <kuniyu@google.com>
+Cc: Lennart Poettering <mzxreary@0pointer.de>
+Cc: Luca Boccassi <bluca@debian.org>
+Cc: David Rheinsberg <david@readahead.eu>
+Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
+Link: https://lore.kernel.org/20250703222314.309967-5-aleksandr.mikhalitsyn@canonical.com
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/scm.h | 4 ++--
+ net/unix/af_unix.c | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/include/net/scm.h b/include/net/scm.h
+index 0d35c7c77a74c3..ea85f7427a1930 100644
+--- a/include/net/scm.h
++++ b/include/net/scm.h
+@@ -69,7 +69,7 @@ static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_co
+ static __inline__ void scm_set_cred(struct scm_cookie *scm,
+ struct pid *pid, kuid_t uid, kgid_t gid)
+ {
+- scm->pid = get_pid(pid);
++ scm->pid = get_pid(pid);
+ scm->creds.pid = pid_vnr(pid);
+ scm->creds.uid = uid;
+ scm->creds.gid = gid;
+@@ -78,7 +78,7 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
+ static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
+ {
+ put_pid(scm->pid);
+- scm->pid = NULL;
++ scm->pid = NULL;
+ }
+
+ static __inline__ void scm_destroy(struct scm_cookie *scm)
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index 1d426f5b2580d5..c64d8ee0ede435 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -1887,7 +1887,7 @@ static void unix_destruct_scm(struct sk_buff *skb)
+ struct scm_cookie scm;
+
+ memset(&scm, 0, sizeof(scm));
+- scm.pid = UNIXCB(skb).pid;
++ scm.pid = UNIXCB(skb).pid;
+ if (UNIXCB(skb).fp)
+ unix_detach_fds(&scm, skb);
+
+--
+2.53.0
+
--- /dev/null
+From e7b28c778b4c2e2eae8afcf895d3ddf04b0dd2c6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 19:29:16 +0200
+Subject: af_unix: Set drop reason in manage_oob().
+
+From: Kuniyuki Iwashima <kuniyu@amazon.com>
+
+[ Upstream commit 533643b091dd6e246d57caf81e6892fa9cbb1cc9 ]
+
+AF_UNIX SOCK_STREAM socket supports MSG_OOB.
+
+When OOB data is sent to a socket, recv() will break at that point.
+
+If the next recv() does not have MSG_OOB, the normal data following
+the OOB data is returned.
+
+Then, the OOB skb is dropped.
+
+Let's define a new drop reason for that case in manage_oob().
+
+ # echo 1 > /sys/kernel/tracing/events/skb/kfree_skb/enable
+
+ # python3
+ >>> from socket import *
+ >>> s1, s2 = socketpair(AF_UNIX)
+ >>> s1.send(b'a', MSG_OOB)
+ >>> s1.send(b'b')
+ >>> s2.recv(2)
+ b'b'
+
+ # cat /sys/kernel/tracing/trace_pipe
+ ...
+ python3-223 ... kfree_skb: ... location=unix_stream_read_generic+0x59e/0xc20 reason: UNIX_SKIP_OOB
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250116053441.5758-6-kuniyu@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/dropreason-core.h | 6 ++++++
+ net/unix/af_unix.c | 2 +-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h
+index 06912797712a69..07826c85d31ca0 100644
+--- a/include/net/dropreason-core.h
++++ b/include/net/dropreason-core.h
+@@ -9,6 +9,7 @@
+ FN(SOCKET_CLOSE) \
+ FN(SOCKET_FILTER) \
+ FN(SOCKET_RCVBUFF) \
++ FN(UNIX_SKIP_OOB) \
+ FN(PKT_TOO_SMALL) \
+ FN(TCP_CSUM) \
+ FN(UDP_CSUM) \
+@@ -131,6 +132,11 @@ enum skb_drop_reason {
+ SKB_DROP_REASON_SOCKET_FILTER,
+ /** @SKB_DROP_REASON_SOCKET_RCVBUFF: socket receive buff is full */
+ SKB_DROP_REASON_SOCKET_RCVBUFF,
++ /**
++ * @SKB_DROP_REASON_UNIX_SKIP_OOB: Out-Of-Band data is skipped by
++ * recv() without MSG_OOB so dropped.
++ */
++ SKB_DROP_REASON_UNIX_SKIP_OOB,
+ /** @SKB_DROP_REASON_PKT_TOO_SMALL: packet size is too small */
+ SKB_DROP_REASON_PKT_TOO_SMALL,
+ /** @SKB_DROP_REASON_TCP_CSUM: TCP checksum error */
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index 4caff11068c380..e0f5a93821490a 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -2714,7 +2714,7 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,
+ spin_unlock(&sk->sk_receive_queue.lock);
+
+ consume_skb(read_skb);
+- kfree_skb(unread_skb);
++ kfree_skb_reason(unread_skb, SKB_DROP_REASON_UNIX_SKIP_OOB);
+
+ return skb;
+ }
+--
+2.53.0
+
--- /dev/null
+From 7481c982ea9c600faf01bb9be36c2e7a737e426c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 19:29:15 +0200
+Subject: af_unix: Set drop reason in unix_release_sock().
+
+From: Kuniyuki Iwashima <kuniyu@amazon.com>
+
+[ Upstream commit c32f0bd7d4838982c6724fca0da92353f27c6f88 ]
+
+unix_release_sock() is called when the last refcnt of struct file
+is released.
+
+Let's define a new drop reason SKB_DROP_REASON_SOCKET_CLOSE and
+set it for kfree_skb() in unix_release_sock().
+
+ # echo 1 > /sys/kernel/tracing/events/skb/kfree_skb/enable
+
+ # python3
+ >>> from socket import *
+ >>> s1, s2 = socketpair(AF_UNIX)
+ >>> s1.send(b'hello world')
+ >>> s2.close()
+
+ # cat /sys/kernel/tracing/trace_pipe
+ ...
+ python3-280 ... kfree_skb: ... protocol=0 location=unix_release_sock+0x260/0x420 reason: SOCKET_CLOSE
+
+To be precise, unix_release_sock() is also called for a new child
+socket in unix_stream_connect() when something fails, but the new
+sk does not have skb in the recv queue then and no event is logged.
+
+Note that only tcp_inbound_ao_hash() uses a similar drop reason,
+SKB_DROP_REASON_TCP_CLOSE, and this can be generalised later.
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250116053441.5758-3-kuniyu@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/dropreason-core.h | 3 +++
+ net/unix/af_unix.c | 4 ++--
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h
+index 76311b3ebfc890..06912797712a69 100644
+--- a/include/net/dropreason-core.h
++++ b/include/net/dropreason-core.h
+@@ -6,6 +6,7 @@
+ #define DEFINE_DROP_REASON(FN, FNe) \
+ FN(NOT_SPECIFIED) \
+ FN(NO_SOCKET) \
++ FN(SOCKET_CLOSE) \
+ FN(SOCKET_FILTER) \
+ FN(SOCKET_RCVBUFF) \
+ FN(PKT_TOO_SMALL) \
+@@ -124,6 +125,8 @@ enum skb_drop_reason {
+ * 3) no valid child socket during 3WHS process
+ */
+ SKB_DROP_REASON_NO_SOCKET,
++ /** @SKB_DROP_REASON_SOCKET_CLOSE: socket is close()d */
++ SKB_DROP_REASON_SOCKET_CLOSE,
+ /** @SKB_DROP_REASON_SOCKET_FILTER: dropped by socket filter */
+ SKB_DROP_REASON_SOCKET_FILTER,
+ /** @SKB_DROP_REASON_SOCKET_RCVBUFF: socket receive buff is full */
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index 4682cc59b7a7aa..4caff11068c380 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -731,8 +731,8 @@ static void unix_release_sock(struct sock *sk, int embrion)
+ if (state == TCP_LISTEN)
+ unix_release_sock(skb->sk, 1);
+
+- /* passed fds are erased in the kfree_skb hook */
+- kfree_skb(skb);
++ /* passed fds are erased in the kfree_skb hook */
++ kfree_skb_reason(skb, SKB_DROP_REASON_SOCKET_CLOSE);
+ }
+
+ if (path.dentry)
+--
+2.53.0
+
--- /dev/null
+From 886edfbb011bdeb86e01984f71eb05019e8269c3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 19:29:17 +0200
+Subject: af_unix: Set drop reason in unix_stream_read_skb().
+
+From: Kuniyuki Iwashima <kuniyu@amazon.com>
+
+[ Upstream commit bace4b468049a558295a0f59460fcb51e28f8fde ]
+
+unix_stream_read_skb() is called when BPF SOCKMAP reads some data
+from a socket in the map.
+
+SOCKMAP does not support MSG_OOB, and reading OOB results in a drop.
+
+Let's set drop reasons respectively.
+
+ * SOCKET_CLOSE : the socket in SOCKMAP was close()d
+ * UNIX_SKIP_OOB : OOB was read from the socket in SOCKMAP
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250116053441.5758-7-kuniyu@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/unix/af_unix.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index e0f5a93821490a..1d426f5b2580d5 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -2743,7 +2743,7 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
+
+ if (sock_flag(sk, SOCK_DEAD)) {
+ unix_state_unlock(sk);
+- kfree_skb(skb);
++ kfree_skb_reason(skb, SKB_DROP_REASON_SOCKET_CLOSE);
+ return -ECONNRESET;
+ }
+
+@@ -2757,7 +2757,7 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
+ unix_state_unlock(sk);
+
+ if (drop) {
+- kfree_skb(skb);
++ kfree_skb_reason(skb, SKB_DROP_REASON_UNIX_SKIP_OOB);
+ return -EAGAIN;
+ }
+ }
+--
+2.53.0
+
--- /dev/null
+From 5ada1a17fdc2d98c1925346f80730095d978f0ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 19:44:02 -0700
+Subject: crypto: crypto4xx - Remove ahash-related code
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+commit 97855e7f1ccf4917f305baab199edb9f2595ff5b upstream.
+
+The hash implementation in crypto4xx has been disabled since 2009.
+As nobody has tried to fix this remove all the dead code.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/amcc/crypto4xx_alg.c | 106 ---------------------------
+ drivers/crypto/amcc/crypto4xx_core.c | 43 +----------
+ drivers/crypto/amcc/crypto4xx_core.h | 7 --
+ 3 files changed, 1 insertion(+), 155 deletions(-)
+
+diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c
+index e0af611a95d88f..04a68622ec09a8 100644
+--- a/drivers/crypto/amcc/crypto4xx_alg.c
++++ b/drivers/crypto/amcc/crypto4xx_alg.c
+@@ -12,9 +12,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/spinlock_types.h>
+ #include <linux/scatterlist.h>
+-#include <linux/crypto.h>
+-#include <linux/hash.h>
+-#include <crypto/internal/hash.h>
+ #include <linux/dma-mapping.h>
+ #include <crypto/algapi.h>
+ #include <crypto/aead.h>
+@@ -602,106 +599,3 @@ int crypto4xx_decrypt_aes_gcm(struct aead_request *req)
+ {
+ return crypto4xx_crypt_aes_gcm(req, true);
+ }
+-
+-/*
+- * HASH SHA1 Functions
+- */
+-static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
+- unsigned int sa_len,
+- unsigned char ha,
+- unsigned char hm)
+-{
+- struct crypto_alg *alg = tfm->__crt_alg;
+- struct crypto4xx_alg *my_alg;
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
+- struct dynamic_sa_hash160 *sa;
+- int rc;
+-
+- my_alg = container_of(__crypto_ahash_alg(alg), struct crypto4xx_alg,
+- alg.u.hash);
+- ctx->dev = my_alg->dev;
+-
+- /* Create SA */
+- if (ctx->sa_in || ctx->sa_out)
+- crypto4xx_free_sa(ctx);
+-
+- rc = crypto4xx_alloc_sa(ctx, sa_len);
+- if (rc)
+- return rc;
+-
+- crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+- sizeof(struct crypto4xx_ctx));
+- sa = (struct dynamic_sa_hash160 *)ctx->sa_in;
+- set_dynamic_sa_command_0(&sa->ctrl, SA_SAVE_HASH, SA_NOT_SAVE_IV,
+- SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
+- SA_NO_HEADER_PROC, ha, SA_CIPHER_ALG_NULL,
+- SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
+- SA_OPCODE_HASH, DIR_INBOUND);
+- set_dynamic_sa_command_1(&sa->ctrl, 0, SA_HASH_MODE_HASH,
+- CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
+- SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+- SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
+- SA_NOT_COPY_HDR);
+- /* Need to zero hash digest in SA */
+- memset(sa->inner_digest, 0, sizeof(sa->inner_digest));
+- memset(sa->outer_digest, 0, sizeof(sa->outer_digest));
+-
+- return 0;
+-}
+-
+-int crypto4xx_hash_init(struct ahash_request *req)
+-{
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- int ds;
+- struct dynamic_sa_ctl *sa;
+-
+- sa = ctx->sa_in;
+- ds = crypto_ahash_digestsize(
+- __crypto_ahash_cast(req->base.tfm));
+- sa->sa_command_0.bf.digest_len = ds >> 2;
+- sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA;
+-
+- return 0;
+-}
+-
+-int crypto4xx_hash_update(struct ahash_request *req)
+-{
+- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- struct scatterlist dst;
+- unsigned int ds = crypto_ahash_digestsize(ahash);
+-
+- sg_init_one(&dst, req->result, ds);
+-
+- return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
+- req->nbytes, NULL, 0, ctx->sa_in,
+- ctx->sa_len, 0, NULL);
+-}
+-
+-int crypto4xx_hash_final(struct ahash_request *req)
+-{
+- return 0;
+-}
+-
+-int crypto4xx_hash_digest(struct ahash_request *req)
+-{
+- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- struct scatterlist dst;
+- unsigned int ds = crypto_ahash_digestsize(ahash);
+-
+- sg_init_one(&dst, req->result, ds);
+-
+- return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
+- req->nbytes, NULL, 0, ctx->sa_in,
+- ctx->sa_len, 0, NULL);
+-}
+-
+-/*
+- * SHA1 Algorithm
+- */
+-int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm)
+-{
+- return crypto4xx_hash_alg_init(tfm, SA_HASH160_LEN, SA_HASH_ALG_SHA1,
+- SA_HASH_MODE_HASH);
+-}
+diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
+index 6006703fb6d767..0795ced8ba2c2d 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.c
++++ b/drivers/crypto/amcc/crypto4xx_core.c
+@@ -485,18 +485,6 @@ static void crypto4xx_copy_pkt_to_dst(struct crypto4xx_device *dev,
+ }
+ }
+
+-static void crypto4xx_copy_digest_to_dst(void *dst,
+- struct pd_uinfo *pd_uinfo,
+- struct crypto4xx_ctx *ctx)
+-{
+- struct dynamic_sa_ctl *sa = (struct dynamic_sa_ctl *) ctx->sa_in;
+-
+- if (sa->sa_command_0.bf.hash_alg == SA_HASH_ALG_SHA1) {
+- memcpy(dst, pd_uinfo->sr_va->save_digest,
+- SA_HASH_ALG_SHA1_DIGEST_SIZE);
+- }
+-}
+-
+ static void crypto4xx_ret_sg_desc(struct crypto4xx_device *dev,
+ struct pd_uinfo *pd_uinfo)
+ {
+@@ -549,23 +537,6 @@ static void crypto4xx_cipher_done(struct crypto4xx_device *dev,
+ skcipher_request_complete(req, 0);
+ }
+
+-static void crypto4xx_ahash_done(struct crypto4xx_device *dev,
+- struct pd_uinfo *pd_uinfo)
+-{
+- struct crypto4xx_ctx *ctx;
+- struct ahash_request *ahash_req;
+-
+- ahash_req = ahash_request_cast(pd_uinfo->async_req);
+- ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(ahash_req));
+-
+- crypto4xx_copy_digest_to_dst(ahash_req->result, pd_uinfo, ctx);
+- crypto4xx_ret_sg_desc(dev, pd_uinfo);
+-
+- if (pd_uinfo->state & PD_ENTRY_BUSY)
+- ahash_request_complete(ahash_req, -EINPROGRESS);
+- ahash_request_complete(ahash_req, 0);
+-}
+-
+ static void crypto4xx_aead_done(struct crypto4xx_device *dev,
+ struct pd_uinfo *pd_uinfo,
+ struct ce_pd *pd)
+@@ -642,9 +613,6 @@ static void crypto4xx_pd_done(struct crypto4xx_device *dev, u32 idx)
+ case CRYPTO_ALG_TYPE_AEAD:
+ crypto4xx_aead_done(dev, pd_uinfo, pd);
+ break;
+- case CRYPTO_ALG_TYPE_AHASH:
+- crypto4xx_ahash_done(dev, pd_uinfo);
+- break;
+ }
+ }
+
+@@ -915,8 +883,7 @@ int crypto4xx_build_pd(struct crypto_async_request *req,
+ }
+
+ pd->pd_ctl.w = PD_CTL_HOST_READY |
+- ((crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AHASH) ||
+- (crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AEAD) ?
++ ((crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AEAD) ?
+ PD_CTL_HASH_FINAL : 0);
+ pd->pd_ctl_len.w = 0x00400000 | (assoclen + datalen);
+ pd_uinfo->state = PD_ENTRY_INUSE | (is_busy ? PD_ENTRY_BUSY : 0);
+@@ -1022,10 +989,6 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
+ rc = crypto_register_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_AHASH:
+- rc = crypto_register_ahash(&alg->alg.u.hash);
+- break;
+-
+ case CRYPTO_ALG_TYPE_RNG:
+ rc = crypto_register_rng(&alg->alg.u.rng);
+ break;
+@@ -1051,10 +1014,6 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
+ list_for_each_entry_safe(alg, tmp, &sec_dev->alg_list, entry) {
+ list_del(&alg->entry);
+ switch (alg->alg.type) {
+- case CRYPTO_ALG_TYPE_AHASH:
+- crypto_unregister_ahash(&alg->alg.u.hash);
+- break;
+-
+ case CRYPTO_ALG_TYPE_AEAD:
+ crypto_unregister_aead(&alg->alg.u.aead);
+ break;
+diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
+index 3adcc5e6569421..0cafce828aacce 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.h
++++ b/drivers/crypto/amcc/crypto4xx_core.h
+@@ -16,7 +16,6 @@
+ #include <linux/ratelimit.h>
+ #include <linux/mutex.h>
+ #include <linux/scatterlist.h>
+-#include <crypto/internal/hash.h>
+ #include <crypto/internal/aead.h>
+ #include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+@@ -135,7 +134,6 @@ struct crypto4xx_alg_common {
+ u32 type;
+ union {
+ struct skcipher_alg cipher;
+- struct ahash_alg hash;
+ struct aead_alg aead;
+ struct rng_alg rng;
+ } u;
+@@ -177,11 +175,6 @@ int crypto4xx_encrypt_noiv_block(struct skcipher_request *req);
+ int crypto4xx_decrypt_noiv_block(struct skcipher_request *req);
+ int crypto4xx_rfc3686_encrypt(struct skcipher_request *req);
+ int crypto4xx_rfc3686_decrypt(struct skcipher_request *req);
+-int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm);
+-int crypto4xx_hash_digest(struct ahash_request *req);
+-int crypto4xx_hash_final(struct ahash_request *req);
+-int crypto4xx_hash_update(struct ahash_request *req);
+-int crypto4xx_hash_init(struct ahash_request *req);
+
+ /*
+ * Note: Only use this function to copy items that is word aligned.
+--
+2.53.0
+
--- /dev/null
+From 7018150c83466d055aecb362de0fc918822b74a9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 19:44:03 -0700
+Subject: crypto: crypto4xx - Remove insecure and unused rng_alg
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 7811ec9e973d2c9e465083699f0c8240b98cb8c4 upstream.
+
+Remove crypto4xx_rng, as it is insecure and unused:
+
+- It has only a 64-bit security strength, which is highly inadequate.
+ This can be seen by the fact that crypto4xx_hw_init() seeds it with
+ only 64 bits of entropy, and the fact that the original commit
+ mentions that it implements ANSI X9.17 Annex C.
+
+ Another issue was that this driver didn't implement the crypto_rng API
+ correctly, as crypto4xx_prng_generate() didn't return 0 on success.
+
+- No user of this code is known. It's usable only theoretically via the
+ "rng" algorithm type of AF_ALG. But userspace actually just uses the
+ actual Linux RNG (/dev/random etc) instead. And rng_algs don't
+ contribute entropy to the actual Linux RNG either. (This may have
+ been confused with hwrng, which does contribute entropy.)
+
+Fixes: d072bfa48853 ("crypto: crypto4xx - add prng crypto support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Acked-by: Christian Lamparter <chunkeey@gmail.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/amcc/crypto4xx_core.c | 87 -------------------------
+ drivers/crypto/amcc/crypto4xx_core.h | 4 --
+ drivers/crypto/amcc/crypto4xx_reg_def.h | 11 ----
+ 3 files changed, 102 deletions(-)
+
+diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
+index 0795ced8ba2c2d..ab3ab130eeee45 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.c
++++ b/drivers/crypto/amcc/crypto4xx_core.c
+@@ -31,11 +31,9 @@
+ #include <crypto/ctr.h>
+ #include <crypto/gcm.h>
+ #include <crypto/sha1.h>
+-#include <crypto/rng.h>
+ #include <crypto/scatterwalk.h>
+ #include <crypto/skcipher.h>
+ #include <crypto/internal/aead.h>
+-#include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+ #include "crypto4xx_reg_def.h"
+ #include "crypto4xx_core.h"
+@@ -989,10 +987,6 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
+ rc = crypto_register_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_RNG:
+- rc = crypto_register_rng(&alg->alg.u.rng);
+- break;
+-
+ default:
+ rc = crypto_register_skcipher(&alg->alg.u.cipher);
+ break;
+@@ -1018,10 +1012,6 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
+ crypto_unregister_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&alg->alg.u.rng);
+- break;
+-
+ default:
+ crypto_unregister_skcipher(&alg->alg.u.cipher);
+ }
+@@ -1080,69 +1070,6 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
+ PPC4XX_TMO_ERR_INT);
+ }
+
+-static int ppc4xx_prng_data_read(struct crypto4xx_device *dev,
+- u8 *data, unsigned int max)
+-{
+- unsigned int i, curr = 0;
+- u32 val[2];
+-
+- do {
+- /* trigger PRN generation */
+- writel(PPC4XX_PRNG_CTRL_AUTO_EN,
+- dev->ce_base + CRYPTO4XX_PRNG_CTRL);
+-
+- for (i = 0; i < 1024; i++) {
+- /* usually 19 iterations are enough */
+- if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) &
+- CRYPTO4XX_PRNG_STAT_BUSY))
+- continue;
+-
+- val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0);
+- val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1);
+- break;
+- }
+- if (i == 1024)
+- return -ETIMEDOUT;
+-
+- if ((max - curr) >= 8) {
+- memcpy(data, &val, 8);
+- data += 8;
+- curr += 8;
+- } else {
+- /* copy only remaining bytes */
+- memcpy(data, &val, max - curr);
+- break;
+- }
+- } while (curr < max);
+-
+- return curr;
+-}
+-
+-static int crypto4xx_prng_generate(struct crypto_rng *tfm,
+- const u8 *src, unsigned int slen,
+- u8 *dstn, unsigned int dlen)
+-{
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+- struct crypto4xx_alg *amcc_alg;
+- struct crypto4xx_device *dev;
+- int ret;
+-
+- amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng);
+- dev = amcc_alg->dev;
+-
+- mutex_lock(&dev->core_dev->rng_lock);
+- ret = ppc4xx_prng_data_read(dev, dstn, dlen);
+- mutex_unlock(&dev->core_dev->rng_lock);
+- return ret;
+-}
+-
+-
+-static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- return 0;
+-}
+-
+ /*
+ * Supported Crypto Algorithms
+ */
+@@ -1272,18 +1199,6 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
+ .cra_module = THIS_MODULE,
+ },
+ } },
+- { .type = CRYPTO_ALG_TYPE_RNG, .u.rng = {
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "crypto4xx_rng",
+- .cra_priority = 300,
+- .cra_ctxsize = 0,
+- .cra_module = THIS_MODULE,
+- },
+- .generate = crypto4xx_prng_generate,
+- .seed = crypto4xx_prng_seed,
+- .seedsize = 0,
+- } },
+ };
+
+ /*
+@@ -1361,7 +1276,6 @@ static int crypto4xx_probe(struct platform_device *ofdev)
+ core_dev->dev->core_dev = core_dev;
+ core_dev->dev->is_revb = is_revb;
+ core_dev->device = dev;
+- mutex_init(&core_dev->rng_lock);
+ spin_lock_init(&core_dev->lock);
+ INIT_LIST_HEAD(&core_dev->dev->alg_list);
+ ratelimit_default_init(&core_dev->dev->aead_ratelimit);
+@@ -1439,7 +1353,6 @@ static void crypto4xx_remove(struct platform_device *ofdev)
+ tasklet_kill(&core_dev->tasklet);
+ /* Un-register with Linux CryptoAPI */
+ crypto4xx_unregister_alg(core_dev->dev);
+- mutex_destroy(&core_dev->rng_lock);
+ /* Free all allocated memory */
+ crypto4xx_stop_all(core_dev);
+ }
+diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
+index 0cafce828aacce..d6a6a5699b4177 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.h
++++ b/drivers/crypto/amcc/crypto4xx_core.h
+@@ -14,10 +14,8 @@
+ #define __CRYPTO4XX_CORE_H__
+
+ #include <linux/ratelimit.h>
+-#include <linux/mutex.h>
+ #include <linux/scatterlist.h>
+ #include <crypto/internal/aead.h>
+-#include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+ #include "crypto4xx_reg_def.h"
+ #include "crypto4xx_sa.h"
+@@ -111,7 +109,6 @@ struct crypto4xx_core_device {
+ u32 irq;
+ struct tasklet_struct tasklet;
+ spinlock_t lock;
+- struct mutex rng_lock;
+ };
+
+ struct crypto4xx_ctx {
+@@ -135,7 +132,6 @@ struct crypto4xx_alg_common {
+ union {
+ struct skcipher_alg cipher;
+ struct aead_alg aead;
+- struct rng_alg rng;
+ } u;
+ };
+
+diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
+index 1038061224da66..73d626308a8484 100644
+--- a/drivers/crypto/amcc/crypto4xx_reg_def.h
++++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
+@@ -90,20 +90,9 @@
+ #define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8
+ #define CRYPTO4XX_ENDIAN_CFG 0x000600d8
+
+-#define CRYPTO4XX_PRNG_STAT 0x00070000
+-#define CRYPTO4XX_PRNG_STAT_BUSY 0x1
+ #define CRYPTO4XX_PRNG_CTRL 0x00070004
+ #define CRYPTO4XX_PRNG_SEED_L 0x00070008
+ #define CRYPTO4XX_PRNG_SEED_H 0x0007000c
+-
+-#define CRYPTO4XX_PRNG_RES_0 0x00070020
+-#define CRYPTO4XX_PRNG_RES_1 0x00070024
+-#define CRYPTO4XX_PRNG_RES_2 0x00070028
+-#define CRYPTO4XX_PRNG_RES_3 0x0007002C
+-
+-#define CRYPTO4XX_PRNG_LFSR_L 0x00070030
+-#define CRYPTO4XX_PRNG_LFSR_H 0x00070034
+-
+ /*
+ * Initialize CRYPTO ENGINE registers, and memory bases.
+ */
+--
+2.53.0
+
--- /dev/null
+From 7e09bb70f1d85203470334bec6c6155536f65f41 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:39:07 -0700
+Subject: crypto: hisi-trng - Remove crypto_rng interface
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 216a7795ec210bdabd5dad42323eee70bbfc8d90 upstream.
+
+drivers/crypto/hisilicon/trng/trng.c exposes the same hardware through
+two completely separate interfaces, crypto_rng and hwrng. However, the
+implementation of this is buggy because it permits generation operations
+from these interfaces to run concurrently with each other, accessing the
+same registers. That is, hisi_trng_generate() synchronizes with itself
+but not with hisi_trng_read(). This results in potential repetition of
+output from the RNG, output of non-random values, etc.
+
+Fortunately, there's actually no point in hardware RNG drivers
+implementing the crypto_rng interface. It's not actually used by
+anything besides the "rng" algorithm type of AF_ALG, which in turn is
+not actually used in practice. Other crypto_rng hardware drivers are
+likewise being phased out, leaving just the hwrng support.
+
+Thus, remove it to simplify the code and avoid conflict (and confusion)
+with the hwrng interface which is the one that actually matters.
+
+Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/hisilicon/Kconfig | 1 -
+ drivers/crypto/hisilicon/trng/trng.c | 296 +--------------------------
+ 2 files changed, 2 insertions(+), 295 deletions(-)
+
+diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig
+index 4137a8bf131f0c..107bfffaead2bd 100644
+--- a/drivers/crypto/hisilicon/Kconfig
++++ b/drivers/crypto/hisilicon/Kconfig
+@@ -79,6 +79,5 @@ config CRYPTO_DEV_HISI_TRNG
+ tristate "Support for HISI TRNG Driver"
+ depends on ARM64 && ACPI
+ select HW_RANDOM
+- select CRYPTO_RNG
+ help
+ Support for HiSilicon TRNG Driver.
+diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c
+index 85a4b99f9055ae..6584ed051e0997 100644
+--- a/drivers/crypto/hisilicon/trng/trng.c
++++ b/drivers/crypto/hisilicon/trng/trng.c
+@@ -1,234 +1,27 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /* Copyright (c) 2019 HiSilicon Limited. */
+
+-#include <crypto/internal/rng.h>
+ #include <linux/acpi.h>
+-#include <linux/crypto.h>
+ #include <linux/err.h>
+ #include <linux/hw_random.h>
+ #include <linux/io.h>
+ #include <linux/iopoll.h>
+ #include <linux/kernel.h>
+-#include <linux/list.h>
+ #include <linux/module.h>
+-#include <linux/mutex.h>
+ #include <linux/platform_device.h>
+ #include <linux/random.h>
+
+ #define HISI_TRNG_REG 0x00F0
+ #define HISI_TRNG_BYTES 4
+ #define HISI_TRNG_QUALITY 512
+-#define HISI_TRNG_VERSION 0x01B8
+-#define HISI_TRNG_VER_V1 GENMASK(31, 0)
+ #define SLEEP_US 10
+ #define TIMEOUT_US 10000
+-#define SW_DRBG_NUM_SHIFT 2
+-#define SW_DRBG_KEY_BASE 0x082C
+-#define SW_DRBG_SEED(n) (SW_DRBG_KEY_BASE - ((n) << SW_DRBG_NUM_SHIFT))
+-#define SW_DRBG_SEED_REGS_NUM 12
+-#define SW_DRBG_SEED_SIZE 48
+-#define SW_DRBG_BLOCKS 0x0830
+-#define SW_DRBG_INIT 0x0834
+-#define SW_DRBG_GEN 0x083c
+-#define SW_DRBG_STATUS 0x0840
+-#define SW_DRBG_BLOCKS_NUM 4095
+-#define SW_DRBG_DATA_BASE 0x0850
+-#define SW_DRBG_DATA_NUM 4
+-#define SW_DRBG_DATA(n) (SW_DRBG_DATA_BASE - ((n) << SW_DRBG_NUM_SHIFT))
+-#define SW_DRBG_BYTES 16
+-#define SW_DRBG_ENABLE_SHIFT 12
+-#define SEED_SHIFT_24 24
+-#define SEED_SHIFT_16 16
+-#define SEED_SHIFT_8 8
+-#define SW_MAX_RANDOM_BYTES 65520
+-
+-struct hisi_trng_list {
+- struct mutex lock;
+- struct list_head list;
+- bool is_init;
+-};
+
+ struct hisi_trng {
+ void __iomem *base;
+- struct hisi_trng_list *trng_list;
+- struct list_head list;
+ struct hwrng rng;
+- u32 ver;
+- u32 ctx_num;
+- /* The bytes of the random number generated since the last seeding. */
+- u32 random_bytes;
+- struct mutex lock;
+-};
+-
+-struct hisi_trng_ctx {
+- struct hisi_trng *trng;
+ };
+
+-static atomic_t trng_active_devs;
+-static struct hisi_trng_list trng_devices;
+-static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait);
+-
+-static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
+-{
+- u32 val, seed_reg, i;
+- int ret;
+-
+- writel(0x0, trng->base + SW_DRBG_BLOCKS);
+-
+- for (i = 0; i < SW_DRBG_SEED_SIZE;
+- i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) {
+- val = seed[i] << SEED_SHIFT_24;
+- val |= seed[i + 1UL] << SEED_SHIFT_16;
+- val |= seed[i + 2UL] << SEED_SHIFT_8;
+- val |= seed[i + 3UL];
+-
+- seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM;
+- writel(val, trng->base + SW_DRBG_SEED(seed_reg));
+- }
+-
+- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT),
+- trng->base + SW_DRBG_BLOCKS);
+- writel(0x1, trng->base + SW_DRBG_INIT);
+- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
+- val, val & BIT(0), SLEEP_US, TIMEOUT_US);
+- if (ret) {
+- pr_err("failed to init trng(%d)\n", ret);
+- return -EIO;
+- }
+-
+- trng->random_bytes = 0;
+-
+- return 0;
+-}
+-
+-static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
+- struct hisi_trng *trng = ctx->trng;
+- int ret;
+-
+- if (slen < SW_DRBG_SEED_SIZE) {
+- pr_err("slen(%u) is not matched with trng(%d)\n", slen,
+- SW_DRBG_SEED_SIZE);
+- return -EINVAL;
+- }
+-
+- mutex_lock(&trng->lock);
+- ret = hisi_trng_set_seed(trng, seed);
+- mutex_unlock(&trng->lock);
+-
+- return ret;
+-}
+-
+-static int hisi_trng_reseed(struct hisi_trng *trng)
+-{
+- u8 seed[SW_DRBG_SEED_SIZE];
+- int size;
+-
+- if (!trng->random_bytes)
+- return 0;
+-
+- size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false);
+- if (size != SW_DRBG_SEED_SIZE)
+- return -EIO;
+-
+- return hisi_trng_set_seed(trng, seed);
+-}
+-
+-static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen)
+-{
+- u32 data[SW_DRBG_DATA_NUM];
+- u32 currsize = 0;
+- u32 val = 0;
+- int ret;
+- u32 i;
+-
+- ret = hisi_trng_reseed(trng);
+- if (ret)
+- return ret;
+-
+- do {
+- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
+- val, val & BIT(1), SLEEP_US, TIMEOUT_US);
+- if (ret) {
+- pr_err("failed to generate random number(%d)!\n", ret);
+- break;
+- }
+-
+- for (i = 0; i < SW_DRBG_DATA_NUM; i++)
+- data[i] = readl(trng->base + SW_DRBG_DATA(i));
+-
+- if (dlen - currsize >= SW_DRBG_BYTES) {
+- memcpy(dstn + currsize, data, SW_DRBG_BYTES);
+- currsize += SW_DRBG_BYTES;
+- } else {
+- memcpy(dstn + currsize, data, dlen - currsize);
+- currsize = dlen;
+- }
+-
+- trng->random_bytes += SW_DRBG_BYTES;
+- writel(0x1, trng->base + SW_DRBG_GEN);
+- } while (currsize < dlen);
+-
+- return ret;
+-}
+-
+-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dstn, unsigned int dlen)
+-{
+- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
+- struct hisi_trng *trng = ctx->trng;
+- unsigned int currsize = 0;
+- unsigned int block_size;
+- int ret;
+-
+- if (!dstn || !dlen) {
+- pr_err("output is error, dlen %u!\n", dlen);
+- return -EINVAL;
+- }
+-
+- do {
+- block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES);
+- mutex_lock(&trng->lock);
+- ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size);
+- mutex_unlock(&trng->lock);
+- if (ret)
+- return ret;
+- currsize += block_size;
+- } while (currsize < dlen);
+-
+- return 0;
+-}
+-
+-static int hisi_trng_init(struct crypto_tfm *tfm)
+-{
+- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
+- struct hisi_trng *trng;
+- u32 ctx_num = ~0;
+-
+- mutex_lock(&trng_devices.lock);
+- list_for_each_entry(trng, &trng_devices.list, list) {
+- if (trng->ctx_num < ctx_num) {
+- ctx_num = trng->ctx_num;
+- ctx->trng = trng;
+- }
+- }
+- ctx->trng->ctx_num++;
+- mutex_unlock(&trng_devices.lock);
+-
+- return 0;
+-}
+-
+-static void hisi_trng_exit(struct crypto_tfm *tfm)
+-{
+- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
+-
+- mutex_lock(&trng_devices.lock);
+- ctx->trng->ctx_num--;
+- mutex_unlock(&trng_devices.lock);
+-}
+-
+ static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+ {
+ struct hisi_trng *trng;
+@@ -260,42 +53,6 @@ static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+ return currsize;
+ }
+
+-static struct rng_alg hisi_trng_alg = {
+- .generate = hisi_trng_generate,
+- .seed = hisi_trng_seed,
+- .seedsize = SW_DRBG_SEED_SIZE,
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "hisi_stdrng",
+- .cra_priority = 300,
+- .cra_ctxsize = sizeof(struct hisi_trng_ctx),
+- .cra_module = THIS_MODULE,
+- .cra_init = hisi_trng_init,
+- .cra_exit = hisi_trng_exit,
+- },
+-};
+-
+-static void hisi_trng_add_to_list(struct hisi_trng *trng)
+-{
+- mutex_lock(&trng_devices.lock);
+- list_add_tail(&trng->list, &trng_devices.list);
+- mutex_unlock(&trng_devices.lock);
+-}
+-
+-static int hisi_trng_del_from_list(struct hisi_trng *trng)
+-{
+- int ret = -EBUSY;
+-
+- mutex_lock(&trng_devices.lock);
+- if (!trng->ctx_num) {
+- list_del(&trng->list);
+- ret = 0;
+- }
+- mutex_unlock(&trng_devices.lock);
+-
+- return ret;
+-}
+-
+ static int hisi_trng_probe(struct platform_device *pdev)
+ {
+ struct hisi_trng *trng;
+@@ -305,68 +62,20 @@ static int hisi_trng_probe(struct platform_device *pdev)
+ if (!trng)
+ return -ENOMEM;
+
+- platform_set_drvdata(pdev, trng);
+-
+ trng->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(trng->base))
+ return PTR_ERR(trng->base);
+
+- trng->ctx_num = 0;
+- trng->random_bytes = SW_MAX_RANDOM_BYTES;
+- mutex_init(&trng->lock);
+- trng->ver = readl(trng->base + HISI_TRNG_VERSION);
+- if (!trng_devices.is_init) {
+- INIT_LIST_HEAD(&trng_devices.list);
+- mutex_init(&trng_devices.lock);
+- trng_devices.is_init = true;
+- }
+-
+- hisi_trng_add_to_list(trng);
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_inc_return(&trng_active_devs) == 1) {
+- ret = crypto_register_rng(&hisi_trng_alg);
+- if (ret) {
+- dev_err(&pdev->dev,
+- "failed to register crypto(%d)\n", ret);
+- atomic_dec_return(&trng_active_devs);
+- goto err_remove_from_list;
+- }
+- }
+-
+ trng->rng.name = pdev->name;
+ trng->rng.read = hisi_trng_read;
+ trng->rng.quality = HISI_TRNG_QUALITY;
++
+ ret = devm_hwrng_register(&pdev->dev, &trng->rng);
+- if (ret) {
++ if (ret)
+ dev_err(&pdev->dev, "failed to register hwrng: %d!\n", ret);
+- goto err_crypto_unregister;
+- }
+-
+- return ret;
+-
+-err_crypto_unregister:
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_dec_return(&trng_active_devs) == 0)
+- crypto_unregister_rng(&hisi_trng_alg);
+-
+-err_remove_from_list:
+- hisi_trng_del_from_list(trng);
+ return ret;
+ }
+
+-static void hisi_trng_remove(struct platform_device *pdev)
+-{
+- struct hisi_trng *trng = platform_get_drvdata(pdev);
+-
+- /* Wait until the task is finished */
+- while (hisi_trng_del_from_list(trng))
+- ;
+-
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_dec_return(&trng_active_devs) == 0)
+- crypto_unregister_rng(&hisi_trng_alg);
+-}
+-
+ static const struct acpi_device_id hisi_trng_acpi_match[] = {
+ { "HISI02B3", 0 },
+ { }
+@@ -375,7 +84,6 @@ MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi_match);
+
+ static struct platform_driver hisi_trng_driver = {
+ .probe = hisi_trng_probe,
+- .remove_new = hisi_trng_remove,
+ .driver = {
+ .name = "hisi-trng-v2",
+ .acpi_match_table = ACPI_PTR(hisi_trng_acpi_match),
+--
+2.53.0
+
--- /dev/null
+From 4b94a416450ad97d9f3684429b91bbdf5f96646e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:50:58 -0700
+Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit b2c41fa9dd8fc740c489e060b199165771f268d1 upstream.
+
+Remove sun4i_ss_rng, as it is insecure and unused:
+
+- It has multiple vulnerabilities. sun4i_ss_prng_seed() is missing
+ locking and has a buffer overflow. sun4i_ss_prng_generate() fails to
+ fill the entire buffer with cryptographic random bytes, because it
+ rounds the destination length down and also doesn't actually wait for
+ the hardware to be ready before pulling bytes from it.
+
+- No user of this code is known. It's usable only theoretically via the
+ "rng" algorithm type of AF_ALG. But userspace actually just uses the
+ actual Linux RNG (/dev/random etc) instead. And rng_algs don't
+ contribute entropy to the actual Linux RNG either. (This may have
+ been confused with hwrng, which does contribute entropy.)
+
+The sun4i_ss_prng_seed() buffer overflow was reported by Tianchu Chen
+and discovered by Atuin - Automated Vulnerability Discovery Engine
+
+There's no point in fixing all these vulnerabilities individually when
+this is unused code, so let's just remove it.
+
+Fixes: b8ae5c7387ad ("crypto: sun4i-ss - support the Security System PRNG")
+Cc: stable@vger.kernel.org
+Reported-by: Tianchu Chen <flynnnchen@tencent.com>
+Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/
+Acked-by: Corentin LABBE <clabbe.montjoie@gmail.com>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/configs/sunxi_defconfig | 1 -
+ drivers/crypto/allwinner/Kconfig | 8 ---
+ drivers/crypto/allwinner/sun4i-ss/Makefile | 1 -
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-core.c | 36 ----------
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-prng.c | 69 -------------------
+ drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h | 20 ------
+ 6 files changed, 135 deletions(-)
+ delete mode 100644 drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+
+diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
+index a83d29fed17563..f4b8d8f7dbefbb 100644
+--- a/arch/arm/configs/sunxi_defconfig
++++ b/arch/arm/configs/sunxi_defconfig
+@@ -170,7 +170,6 @@ CONFIG_ROOT_NFS=y
+ CONFIG_NLS_CODEPAGE_437=y
+ CONFIG_NLS_ISO8859_1=y
+ CONFIG_CRYPTO_DEV_SUN4I_SS=y
+-CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG=y
+ CONFIG_CRYPTO_DEV_SUN8I_CE=y
+ CONFIG_CRYPTO_DEV_SUN8I_SS=y
+ CONFIG_DMA_CMA=y
+diff --git a/drivers/crypto/allwinner/Kconfig b/drivers/crypto/allwinner/Kconfig
+index b8e75210a0e315..06ea0e9fe6f22f 100644
+--- a/drivers/crypto/allwinner/Kconfig
++++ b/drivers/crypto/allwinner/Kconfig
+@@ -24,14 +24,6 @@ config CRYPTO_DEV_SUN4I_SS
+ To compile this driver as a module, choose M here: the module
+ will be called sun4i-ss.
+
+-config CRYPTO_DEV_SUN4I_SS_PRNG
+- bool "Support for Allwinner Security System PRNG"
+- depends on CRYPTO_DEV_SUN4I_SS
+- select CRYPTO_RNG
+- help
+- Select this option if you want to provide kernel-side support for
+- the Pseudo-Random Number Generator found in the Security System.
+-
+ config CRYPTO_DEV_SUN4I_SS_DEBUG
+ bool "Enable sun4i-ss stats"
+ depends on CRYPTO_DEV_SUN4I_SS
+diff --git a/drivers/crypto/allwinner/sun4i-ss/Makefile b/drivers/crypto/allwinner/sun4i-ss/Makefile
+index c0a2797d316827..06a9ae81f9f808 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/Makefile
++++ b/drivers/crypto/allwinner/sun4i-ss/Makefile
+@@ -1,4 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sun4i-ss.o
+ sun4i-ss-y += sun4i-ss-core.o sun4i-ss-hash.o sun4i-ss-cipher.o
+-sun4i-ss-$(CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG) += sun4i-ss-prng.o
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+index 890664bd5f0f13..cc34600f4a4e49 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+@@ -213,23 +213,6 @@ static struct sun4i_ss_alg_template ss_algs[] = {
+ }
+ }
+ },
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+-{
+- .type = CRYPTO_ALG_TYPE_RNG,
+- .alg.rng = {
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "sun4i_ss_rng",
+- .cra_priority = 300,
+- .cra_ctxsize = 0,
+- .cra_module = THIS_MODULE,
+- },
+- .generate = sun4i_ss_prng_generate,
+- .seed = sun4i_ss_prng_seed,
+- .seedsize = SS_SEED_LEN / BITS_PER_BYTE,
+- }
+-},
+-#endif
+ };
+
+ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
+@@ -247,12 +230,6 @@ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
+ ss_algs[i].stat_req, ss_algs[i].stat_opti, ss_algs[i].stat_fb,
+ ss_algs[i].stat_bytes);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",
+- ss_algs[i].alg.rng.base.cra_driver_name,
+- ss_algs[i].alg.rng.base.cra_name,
+- ss_algs[i].stat_req, ss_algs[i].stat_bytes);
+- break;
+ case CRYPTO_ALG_TYPE_AHASH:
+ seq_printf(seq, "%s %s reqs=%lu\n",
+ ss_algs[i].alg.hash.halg.base.cra_driver_name,
+@@ -471,13 +448,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ goto error_alg;
+ }
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- err = crypto_register_rng(&ss_algs[i].alg.rng);
+- if (err) {
+- dev_err(ss->dev, "Fail to register %s\n",
+- ss_algs[i].alg.rng.base.cra_name);
+- }
+- break;
+ }
+ }
+
+@@ -497,9 +467,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+ error_pm:
+@@ -520,9 +487,6 @@ static void sun4i_ss_remove(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+deleted file mode 100644
+index 491fcb7b81b40b..00000000000000
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
++++ /dev/null
+@@ -1,69 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-#include "sun4i-ss.h"
+-
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- memcpy(algt->ss->seed, seed, slen);
+-
+- return 0;
+-}
+-
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+- int i, err;
+- u32 v;
+- u32 *data = (u32 *)dst;
+- const u32 mode = SS_OP_PRNG | SS_PRNG_CONTINUE | SS_ENABLED;
+- size_t len;
+- struct sun4i_ss_ctx *ss;
+- unsigned int todo = (dlen / 4) * 4;
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- ss = algt->ss;
+-
+- err = pm_runtime_resume_and_get(ss->dev);
+- if (err < 0)
+- return err;
+-
+- if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) {
+- algt->stat_req++;
+- algt->stat_bytes += todo;
+- }
+-
+- spin_lock_bh(&ss->slock);
+-
+- writel(mode, ss->base + SS_CTL);
+-
+- while (todo > 0) {
+- /* write the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++)
+- writel(ss->seed[i], ss->base + SS_KEY0 + i * 4);
+-
+- /* Read the random data */
+- len = min_t(size_t, SS_DATA_LEN / BITS_PER_BYTE, todo);
+- readsl(ss->base + SS_TXFIFO, data, len / 4);
+- data += len / 4;
+- todo -= len;
+-
+- /* Update the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++) {
+- v = readl(ss->base + SS_KEY0 + i * 4);
+- ss->seed[i] = v;
+- }
+- }
+-
+- writel(0, ss->base + SS_CTL);
+- spin_unlock_bh(&ss->slock);
+-
+- pm_runtime_put(ss->dev);
+-
+- return 0;
+-}
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+index 6c5d4aa6453c7f..f7d1c79ac677d8 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+@@ -31,8 +31,6 @@
+ #include <crypto/internal/skcipher.h>
+ #include <crypto/aes.h>
+ #include <crypto/internal/des.h>
+-#include <crypto/internal/rng.h>
+-#include <crypto/rng.h>
+
+ #define SS_CTL 0x00
+ #define SS_KEY0 0x04
+@@ -62,10 +60,6 @@
+
+ /* SS_CTL configuration values */
+
+-/* PRNG generator mode - bit 15 */
+-#define SS_PRNG_ONESHOT (0 << 15)
+-#define SS_PRNG_CONTINUE (1 << 15)
+-
+ /* IV mode for hash */
+ #define SS_IV_ARBITRARY (1 << 14)
+
+@@ -94,14 +88,10 @@
+ #define SS_OP_3DES (2 << 4)
+ #define SS_OP_SHA1 (3 << 4)
+ #define SS_OP_MD5 (4 << 4)
+-#define SS_OP_PRNG (5 << 4)
+
+ /* Data end bit - bit 2 */
+ #define SS_DATA_END (1 << 2)
+
+-/* PRNG start bit - bit 1 */
+-#define SS_PRNG_START (1 << 1)
+-
+ /* SS Enable bit - bit 0 */
+ #define SS_DISABLED (0 << 0)
+ #define SS_ENABLED (1 << 0)
+@@ -128,9 +118,6 @@
+ #define SS_RXFIFO_EMP_INT_ENABLE (1 << 2)
+ #define SS_TXFIFO_AVA_INT_ENABLE (1 << 0)
+
+-#define SS_SEED_LEN 192
+-#define SS_DATA_LEN 160
+-
+ /*
+ * struct ss_variant - Describe SS hardware variant
+ * @sha1_in_be: The SHA1 digest is given by SS in BE, and so need to be inverted.
+@@ -151,9 +138,6 @@ struct sun4i_ss_ctx {
+ char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */
+ char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */
+ spinlock_t slock; /* control the use of the device */
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+- u32 seed[SS_SEED_LEN / BITS_PER_LONG];
+-#endif
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_stats;
+ };
+@@ -164,7 +148,6 @@ struct sun4i_ss_alg_template {
+ union {
+ struct skcipher_alg crypto;
+ struct ahash_alg hash;
+- struct rng_alg rng;
+ } alg;
+ struct sun4i_ss_ctx *ss;
+ unsigned long stat_req;
+@@ -231,6 +214,3 @@ int sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+ int sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen);
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen);
+--
+2.53.0
+
--- /dev/null
+From 3af17077d7caa49d66f29e81d90e9a1920d62647 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 10:49:08 +0000
+Subject: iommu/amd: Use maximum Event log buffer size when SNP is enabled on
+ Family 0x19
+
+From: Vasant Hegde <vasant.hegde@amd.com>
+
+commit 58c0ac6125d89bf6ec65a521eaeb52a0e8e20a9f upstream.
+
+Due to CVE-2023-20585, the Event log buffer must use the maximum supported
+size (512K) on Milan/Genoa (Family 0x19) systems when SNP is enabled,
+to mitigate a potential security vulnerability. All other systems continue to
+use the default Event log buffer size (8K).
+
+Apply the errata fix by making the following changes:
+
+* Introduce new global variable (amd_iommu_evtlog_size) to have event log
+ buffer size. Adjust variable size for family 0x19.
+
+* Since 'iommu_snp_enable()' must be called after the core IOMMU subsystem
+ is initialized, it cannot be moved to the early init stage. The SNP errata
+ must also be applied after the 'iommu_snp_enable()' check. Therefore,
+ 'alloc_event_buffer()' and 'iommu_enable_event_buffer()' are now called
+ in the IOMMU_ENABLED state, after the errata is applied.
+
+* Adjust alloc_event_buffer() and iommu_enable_event_buffer() to handle
+ all IOMMU instances.
+
+* Also rename EVT_* macros to make it more readable.
+
+Link: https://www.amd.com/en/resources/product-security/bulletin/amd-sb-3016.html
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+Cc: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
+Tested-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava@amd.com>
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+(cherry picked from commit 58c0ac6125d89bf6ec65a521eaeb52a0e8e20a9f)
+Conflicts:
+ drivers/iommu/amd/init.c
+[ Conflicts in alloc_event_buffer() and iommu_enable_event_buffer()
+ due to lack of upstream AMD IOMMU kdump buffer reuse code.
+ Similarly, do not add a kdump check when allocating an
+ event log buffer in state_next(). ]
+Signed-off-by: Liam Merwick <liam.merwick@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd/amd_iommu.h | 2 +
+ drivers/iommu/amd/amd_iommu_types.h | 10 ++--
+ drivers/iommu/amd/init.c | 77 +++++++++++++++++++++--------
+ drivers/iommu/amd/iommu.c | 2 +-
+ 4 files changed, 67 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
+index 27eedfb47d8b69..36cd610104e3f8 100644
+--- a/drivers/iommu/amd/amd_iommu.h
++++ b/drivers/iommu/amd/amd_iommu.h
+@@ -11,6 +11,8 @@
+
+ #include "amd_iommu_types.h"
+
++extern int amd_iommu_evtlog_size;
++
+ irqreturn_t amd_iommu_int_thread(int irq, void *data);
+ irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data);
+ irqreturn_t amd_iommu_int_thread_pprlog(int irq, void *data);
+diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
+index 7f13b314abbcef..d622fa0091a5a3 100644
+--- a/drivers/iommu/amd/amd_iommu_types.h
++++ b/drivers/iommu/amd/amd_iommu_types.h
+@@ -15,6 +15,7 @@
+ #include <linux/mutex.h>
+ #include <linux/msi.h>
+ #include <linux/list.h>
++#include <linux/sizes.h>
+ #include <linux/spinlock.h>
+ #include <linux/pci.h>
+ #include <linux/irqreturn.h>
+@@ -132,7 +133,6 @@
+ #define MMIO_STATUS_GALOG_INT_MASK BIT(10)
+
+ /* event logging constants */
+-#define EVENT_ENTRY_SIZE 0x10
+ #define EVENT_TYPE_SHIFT 28
+ #define EVENT_TYPE_MASK 0xf
+ #define EVENT_TYPE_ILL_DEV 0x1
+@@ -240,8 +240,12 @@
+ #define MMIO_CMD_SIZE_512 (0x9ULL << MMIO_CMD_SIZE_SHIFT)
+
+ /* constants for event buffer handling */
+-#define EVT_BUFFER_SIZE 8192 /* 512 entries */
+-#define EVT_LEN_MASK (0x9ULL << 56)
++#define EVTLOG_ENTRY_SIZE 0x10
++#define EVTLOG_SIZE_SHIFT 56
++#define EVTLOG_SIZE_DEF SZ_8K /* 512 entries */
++#define EVTLOG_LEN_MASK_DEF (0x9ULL << EVTLOG_SIZE_SHIFT)
++#define EVTLOG_SIZE_MAX SZ_512K /* 32K entries */
++#define EVTLOG_LEN_MASK_MAX (0xFULL << EVTLOG_SIZE_SHIFT)
+
+ /* Constants for PPR Log handling */
+ #define PPR_LOG_ENTRIES 512
+diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
+index 78e9ceda2338f3..570471e1058655 100644
+--- a/drivers/iommu/amd/init.c
++++ b/drivers/iommu/amd/init.c
+@@ -133,6 +133,8 @@ struct ivhd_entry {
+ u8 uid;
+ } __attribute__((packed));
+
++int amd_iommu_evtlog_size = EVTLOG_SIZE_DEF;
++
+ /*
+ * An AMD IOMMU memory definition structure. It defines things like exclusion
+ * ranges for devices and regions that should be unity mapped.
+@@ -855,30 +857,41 @@ void *__init iommu_alloc_4k_pages(struct amd_iommu *iommu, gfp_t gfp,
+ }
+
+ /* allocates the memory where the IOMMU will log its events to */
+-static int __init alloc_event_buffer(struct amd_iommu *iommu)
++static int __init alloc_event_buffer(void)
+ {
+- iommu->evt_buf = iommu_alloc_4k_pages(iommu, GFP_KERNEL,
+- EVT_BUFFER_SIZE);
++ struct amd_iommu *iommu;
+
+- return iommu->evt_buf ? 0 : -ENOMEM;
++ for_each_iommu(iommu) {
++ iommu->evt_buf = iommu_alloc_4k_pages(iommu, GFP_KERNEL,
++ amd_iommu_evtlog_size);
++ if (!iommu->evt_buf)
++ return -ENOMEM;
++ }
++
++ return 0;
+ }
+
+-static void iommu_enable_event_buffer(struct amd_iommu *iommu)
++static void iommu_enable_event_buffer(void)
+ {
++ struct amd_iommu *iommu;
+ u64 entry;
+
+- BUG_ON(iommu->evt_buf == NULL);
++ for_each_iommu(iommu) {
++ BUG_ON(iommu->evt_buf == NULL);
+
+- entry = iommu_virt_to_phys(iommu->evt_buf) | EVT_LEN_MASK;
++ entry = iommu_virt_to_phys(iommu->evt_buf);
++ entry |= (amd_iommu_evtlog_size == EVTLOG_SIZE_DEF) ?
++ EVTLOG_LEN_MASK_DEF : EVTLOG_LEN_MASK_MAX;
+
+- memcpy_toio(iommu->mmio_base + MMIO_EVT_BUF_OFFSET,
+- &entry, sizeof(entry));
++ memcpy_toio(iommu->mmio_base + MMIO_EVT_BUF_OFFSET,
++ &entry, sizeof(entry));
+
+- /* set head and tail to zero manually */
+- writel(0x00, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
+- writel(0x00, iommu->mmio_base + MMIO_EVT_TAIL_OFFSET);
++ /* set head and tail to zero manually */
++ writel(0x00, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
++ writel(0x00, iommu->mmio_base + MMIO_EVT_TAIL_OFFSET);
+
+- iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
++ iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
++ }
+ }
+
+ /*
+@@ -891,7 +904,7 @@ static void iommu_disable_event_buffer(struct amd_iommu *iommu)
+
+ static void __init free_event_buffer(struct amd_iommu *iommu)
+ {
+- iommu_free_pages(iommu->evt_buf, get_order(EVT_BUFFER_SIZE));
++ iommu_free_pages(iommu->evt_buf, get_order(amd_iommu_evtlog_size));
+ }
+
+ static void free_ga_log(struct amd_iommu *iommu)
+@@ -1828,9 +1841,6 @@ static int __init init_iommu_one_late(struct amd_iommu *iommu)
+ if (alloc_command_buffer(iommu))
+ return -ENOMEM;
+
+- if (alloc_event_buffer(iommu))
+- return -ENOMEM;
+-
+ iommu->int_enabled = false;
+
+ init_translation_status(iommu);
+@@ -2754,7 +2764,6 @@ static void early_enable_iommu(struct amd_iommu *iommu)
+ iommu_init_flags(iommu);
+ iommu_set_device_table(iommu);
+ iommu_enable_command_buffer(iommu);
+- iommu_enable_event_buffer(iommu);
+ iommu_set_exclusion_range(iommu);
+ iommu_enable_gt(iommu);
+ iommu_enable_ga(iommu);
+@@ -2812,7 +2821,6 @@ static void early_enable_iommus(void)
+ iommu_disable_event_buffer(iommu);
+ iommu_disable_irtcachedis(iommu);
+ iommu_enable_command_buffer(iommu);
+- iommu_enable_event_buffer(iommu);
+ iommu_enable_ga(iommu);
+ iommu_enable_xt(iommu);
+ iommu_enable_irtcachedis(iommu);
+@@ -2928,6 +2936,7 @@ static void amd_iommu_resume(void)
+ /* re-load the hardware */
+ enable_iommus();
+
++ iommu_enable_event_buffer();
+ amd_iommu_enable_interrupts();
+ }
+
+@@ -3242,6 +3251,23 @@ static void iommu_snp_enable(void)
+ #endif
+ }
+
++static void amd_iommu_apply_erratum_snp(void)
++{
++#ifdef CONFIG_KVM_AMD_SEV
++ if (!amd_iommu_snp_en)
++ return;
++
++ /* Errata fix for Family 0x19 */
++ if (boot_cpu_data.x86 != 0x19)
++ return;
++
++ /* Set event log buffer size to max */
++ amd_iommu_evtlog_size = EVTLOG_SIZE_MAX;
++ pr_info("Applying erratum: Increase Event log size to 0x%x\n",
++ amd_iommu_evtlog_size);
++#endif
++}
++
+ /****************************************************************************
+ *
+ * AMD IOMMU Initialization State Machine
+@@ -3278,6 +3304,17 @@ static int __init state_next(void)
+ case IOMMU_ENABLED:
+ register_syscore_ops(&amd_iommu_syscore_ops);
+ iommu_snp_enable();
++
++ amd_iommu_apply_erratum_snp();
++
++ /* Allocate/enable event log buffer */
++ ret = alloc_event_buffer();
++ if (ret) {
++ init_state = IOMMU_INIT_ERROR;
++ break;
++ }
++ iommu_enable_event_buffer();
++
+ ret = amd_iommu_init_pci();
+ init_state = ret ? IOMMU_INIT_ERROR : IOMMU_PCI_INIT;
+ break;
+@@ -3865,7 +3902,7 @@ int amd_iommu_snp_disable(void)
+ return 0;
+
+ for_each_iommu(iommu) {
+- ret = iommu_make_shared(iommu->evt_buf, EVT_BUFFER_SIZE);
++ ret = iommu_make_shared(iommu->evt_buf, amd_iommu_evtlog_size);
+ if (ret)
+ return ret;
+
+diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
+index 5ea0d9eb0ccc54..b4052fa9cc76bc 100644
+--- a/drivers/iommu/amd/iommu.c
++++ b/drivers/iommu/amd/iommu.c
+@@ -1003,7 +1003,7 @@ static void iommu_poll_events(struct amd_iommu *iommu)
+ iommu_print_event(iommu, iommu->evt_buf + head);
+
+ /* Update head pointer of hardware ring-buffer */
+- head = (head + EVENT_ENTRY_SIZE) % EVT_BUFFER_SIZE;
++ head = (head + EVTLOG_ENTRY_SIZE) % amd_iommu_evtlog_size;
+ writel(head, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From d98101ff66d81b332e60156f95b85e54f0d25564 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 10:49:09 +0000
+Subject: iommu/amd: Use maximum PPR log buffer size when SNP is enabled on
+ Family 0x19
+
+From: Vasant Hegde <vasant.hegde@amd.com>
+
+commit 1f44aab79bac31f459422dfb213e907bb386509c upstream.
+
+Due to CVE-2023-20585, the PPR log buffer must use the maximum supported
+size (512K) on Genoa (Family 0x19, model >= 0x10) systems when SNP is
+enabled, to mitigate a potential security vulnerability. Note that Family
+0x19 models below 0x10 (Milan) do not support PPR when SNP is enabled.
+Hence the PPR log size increase is only applied for model >= 0x10.
+All other systems continue to use the default PPR log buffer size (8K).
+
+Apply the errata fix by making the following changes:
+
+- Introduce global new variable (amd_iommu_pprlog_size) to have PPR log buffer
+ size. Adjust variable size for Genoa family.
+
+- Extend 'amd_iommu_apply_erratum_snp()' to also set the PPR log buffer
+ size to maximum for Family 0x19 model >= 0x10 when SNP is enabled.
+
+- Rename PPR_* macros to make it more readable.
+
+Link: https://www.amd.com/en/resources/product-security/bulletin/amd-sb-3016.html
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+Cc: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
+Tested-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava@amd.com>
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+(cherry picked from commit 1f44aab79bac31f459422dfb213e907bb386509c)
+[ Modify amd_iommu_free_ppr_log() due to different iommu_free_pages() API. ]
+Signed-off-by: Liam Merwick <liam.merwick@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd/amd_iommu.h | 1 +
+ drivers/iommu/amd/amd_iommu_types.h | 11 ++++++-----
+ drivers/iommu/amd/init.c | 13 ++++++++++++-
+ drivers/iommu/amd/ppr.c | 10 ++++++----
+ 4 files changed, 25 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
+index 36cd610104e3f8..8be6b4514dd51a 100644
+--- a/drivers/iommu/amd/amd_iommu.h
++++ b/drivers/iommu/amd/amd_iommu.h
+@@ -12,6 +12,7 @@
+ #include "amd_iommu_types.h"
+
+ extern int amd_iommu_evtlog_size;
++extern int amd_iommu_pprlog_size;
+
+ irqreturn_t amd_iommu_int_thread(int irq, void *data);
+ irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data);
+diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
+index d622fa0091a5a3..09131d067a8a54 100644
+--- a/drivers/iommu/amd/amd_iommu_types.h
++++ b/drivers/iommu/amd/amd_iommu_types.h
+@@ -248,11 +248,12 @@
+ #define EVTLOG_LEN_MASK_MAX (0xFULL << EVTLOG_SIZE_SHIFT)
+
+ /* Constants for PPR Log handling */
+-#define PPR_LOG_ENTRIES 512
+-#define PPR_LOG_SIZE_SHIFT 56
+-#define PPR_LOG_SIZE_512 (0x9ULL << PPR_LOG_SIZE_SHIFT)
+-#define PPR_ENTRY_SIZE 16
+-#define PPR_LOG_SIZE (PPR_ENTRY_SIZE * PPR_LOG_ENTRIES)
++#define PPRLOG_ENTRY_SIZE 0x10
++#define PPRLOG_SIZE_SHIFT 56
++#define PPRLOG_SIZE_DEF SZ_8K /* 512 entries */
++#define PPRLOG_LEN_MASK_DEF (0x9ULL << PPRLOG_SIZE_SHIFT)
++#define PPRLOG_SIZE_MAX SZ_512K /* 32K entries */
++#define PPRLOG_LEN_MASK_MAX (0xFULL << PPRLOG_SIZE_SHIFT)
+
+ /* PAGE_SERVICE_REQUEST PPR Log Buffer Entry flags */
+ #define PPR_FLAG_EXEC 0x002 /* Execute permission requested */
+diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
+index 570471e1058655..7fa340281b9fb2 100644
+--- a/drivers/iommu/amd/init.c
++++ b/drivers/iommu/amd/init.c
+@@ -134,6 +134,7 @@ struct ivhd_entry {
+ } __attribute__((packed));
+
+ int amd_iommu_evtlog_size = EVTLOG_SIZE_DEF;
++int amd_iommu_pprlog_size = PPRLOG_SIZE_DEF;
+
+ /*
+ * An AMD IOMMU memory definition structure. It defines things like exclusion
+@@ -3265,6 +3266,16 @@ static void amd_iommu_apply_erratum_snp(void)
+ amd_iommu_evtlog_size = EVTLOG_SIZE_MAX;
+ pr_info("Applying erratum: Increase Event log size to 0x%x\n",
+ amd_iommu_evtlog_size);
++
++ /*
++ * Set PPR log buffer size to max.
++ * (Family 0x19, model < 0x10 doesn't support PPR when SNP is enabled).
++ */
++ if (boot_cpu_data.x86_model >= 0x10) {
++ amd_iommu_pprlog_size = PPRLOG_SIZE_MAX;
++ pr_info("Applying erratum: Increase PPR log size to 0x%x\n",
++ amd_iommu_pprlog_size);
++ }
+ #endif
+ }
+
+@@ -3906,7 +3917,7 @@ int amd_iommu_snp_disable(void)
+ if (ret)
+ return ret;
+
+- ret = iommu_make_shared(iommu->ppr_log, PPR_LOG_SIZE);
++ ret = iommu_make_shared(iommu->ppr_log, amd_iommu_pprlog_size);
+ if (ret)
+ return ret;
+
+diff --git a/drivers/iommu/amd/ppr.c b/drivers/iommu/amd/ppr.c
+index 7c67d69f0b8cad..42d895bd1c44f7 100644
+--- a/drivers/iommu/amd/ppr.c
++++ b/drivers/iommu/amd/ppr.c
+@@ -20,7 +20,7 @@
+ int __init amd_iommu_alloc_ppr_log(struct amd_iommu *iommu)
+ {
+ iommu->ppr_log = iommu_alloc_4k_pages(iommu, GFP_KERNEL | __GFP_ZERO,
+- PPR_LOG_SIZE);
++ amd_iommu_pprlog_size);
+ return iommu->ppr_log ? 0 : -ENOMEM;
+ }
+
+@@ -33,7 +33,9 @@ void amd_iommu_enable_ppr_log(struct amd_iommu *iommu)
+
+ iommu_feature_enable(iommu, CONTROL_PPR_EN);
+
+- entry = iommu_virt_to_phys(iommu->ppr_log) | PPR_LOG_SIZE_512;
++ entry = iommu_virt_to_phys(iommu->ppr_log);
++ entry |= (amd_iommu_pprlog_size == PPRLOG_SIZE_DEF) ?
++ PPRLOG_LEN_MASK_DEF : PPRLOG_LEN_MASK_MAX;
+
+ memcpy_toio(iommu->mmio_base + MMIO_PPR_LOG_OFFSET,
+ &entry, sizeof(entry));
+@@ -48,7 +50,7 @@ void amd_iommu_enable_ppr_log(struct amd_iommu *iommu)
+
+ void __init amd_iommu_free_ppr_log(struct amd_iommu *iommu)
+ {
+- iommu_free_pages(iommu->ppr_log, get_order(PPR_LOG_SIZE));
++ iommu_free_pages(iommu->ppr_log, get_order(amd_iommu_pprlog_size));
+ }
+
+ /*
+@@ -201,7 +203,7 @@ void amd_iommu_poll_ppr_log(struct amd_iommu *iommu)
+ raw[0] = raw[1] = 0UL;
+
+ /* Update head pointer of hardware ring-buffer */
+- head = (head + PPR_ENTRY_SIZE) % PPR_LOG_SIZE;
++ head = (head + PPRLOG_ENTRY_SIZE) % amd_iommu_pprlog_size;
+ writel(head, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
+
+ /* Handle PPR entry */
+--
+2.53.0
+
--- /dev/null
+From 6856200fdf5a645c13b0b35a123b92188f320a3b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 19:29:14 +0200
+Subject: net: dropreason: Gather SOCKET_ drop reasons.
+
+From: Kuniyuki Iwashima <kuniyu@amazon.com>
+
+[ Upstream commit 454d402481d45af79ee7eea7e64bce02bbbe9766 ]
+
+The following patch adds a new drop reason starting with
+the SOCKET_ prefix.
+
+Let's gather the existing SOCKET_ reasons.
+
+Note that the order is not part of uAPI.
+
+Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Link: https://patch.msgid.link/20250116053441.5758-2-kuniyu@amazon.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Heiko Stuebner <heiko.stuebner@cherry.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/dropreason-core.h | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h
+index 02e7be19b0428f..76311b3ebfc890 100644
+--- a/include/net/dropreason-core.h
++++ b/include/net/dropreason-core.h
+@@ -6,9 +6,10 @@
+ #define DEFINE_DROP_REASON(FN, FNe) \
+ FN(NOT_SPECIFIED) \
+ FN(NO_SOCKET) \
++ FN(SOCKET_FILTER) \
++ FN(SOCKET_RCVBUFF) \
+ FN(PKT_TOO_SMALL) \
+ FN(TCP_CSUM) \
+- FN(SOCKET_FILTER) \
+ FN(UDP_CSUM) \
+ FN(NETFILTER_DROP) \
+ FN(OTHERHOST) \
+@@ -18,7 +19,6 @@
+ FN(UNICAST_IN_L2_MULTICAST) \
+ FN(XFRM_POLICY) \
+ FN(IP_NOPROTO) \
+- FN(SOCKET_RCVBUFF) \
+ FN(PROTO_MEM) \
+ FN(TCP_AUTH_HDR) \
+ FN(TCP_MD5NOTFOUND) \
+@@ -124,12 +124,14 @@ enum skb_drop_reason {
+ * 3) no valid child socket during 3WHS process
+ */
+ SKB_DROP_REASON_NO_SOCKET,
++ /** @SKB_DROP_REASON_SOCKET_FILTER: dropped by socket filter */
++ SKB_DROP_REASON_SOCKET_FILTER,
++ /** @SKB_DROP_REASON_SOCKET_RCVBUFF: socket receive buff is full */
++ SKB_DROP_REASON_SOCKET_RCVBUFF,
+ /** @SKB_DROP_REASON_PKT_TOO_SMALL: packet size is too small */
+ SKB_DROP_REASON_PKT_TOO_SMALL,
+ /** @SKB_DROP_REASON_TCP_CSUM: TCP checksum error */
+ SKB_DROP_REASON_TCP_CSUM,
+- /** @SKB_DROP_REASON_SOCKET_FILTER: dropped by socket filter */
+- SKB_DROP_REASON_SOCKET_FILTER,
+ /** @SKB_DROP_REASON_UDP_CSUM: UDP checksum error */
+ SKB_DROP_REASON_UDP_CSUM,
+ /** @SKB_DROP_REASON_NETFILTER_DROP: dropped by netfilter */
+@@ -160,8 +162,6 @@ enum skb_drop_reason {
+ SKB_DROP_REASON_XFRM_POLICY,
+ /** @SKB_DROP_REASON_IP_NOPROTO: no support for IP protocol */
+ SKB_DROP_REASON_IP_NOPROTO,
+- /** @SKB_DROP_REASON_SOCKET_RCVBUFF: socket receive buff is full */
+- SKB_DROP_REASON_SOCKET_RCVBUFF,
+ /**
+ * @SKB_DROP_REASON_PROTO_MEM: proto memory limitation, such as
+ * udp packet drop out of udp_memory_allocated.
+--
+2.53.0
+
timekeeping-register-default-clocksource-before-taki.patch
nvmet-tcp-check-init_failed-before-nvmet_req_uninit-in-digest-error-path.patch
nvmet-tcp-fix-potential-uaf-when-ddgst-mismatch.patch
+vsock-virtio-fix-zerocopy-completion-for-multi-skb-s.patch
+vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch
+crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
+iommu-amd-use-maximum-event-log-buffer-size-when-snp.patch
+iommu-amd-use-maximum-ppr-log-buffer-size-when-snp-i.patch
+x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch
+net-dropreason-gather-socket_-drop-reasons.patch
+af_unix-set-drop-reason-in-unix_release_sock.patch
+af_unix-set-drop-reason-in-manage_oob.patch
+af_unix-set-drop-reason-in-unix_stream_read_skb.patch
+af_unix-scm-fix-whitespace-errors.patch
+af_unix-don-t-hold-unix_state_lock-in-__unix_dgram_r.patch
+af_unix-don-t-check-sock_dead-in-unix_stream_read_sk.patch
+af_unix-don-t-use-skb_recv_datagram-in-unix_stream_r.patch
+af_unix-drop-all-scm-attributes-for-sockmap.patch
+crypto-crypto4xx-remove-ahash-related-code.patch
+crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch
+crypto-hisi-trng-remove-crypto_rng-interface.patch
+time-jiffies-register-jiffies-clocksource-before-usa.patch
+time-jiffies-change-register_refined_jiffies-to-void.patch
--- /dev/null
+From 87e8dd8f2eb92ca175214275d0b3c6cc43e596d0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Apr 2025 11:27:32 +0800
+Subject: time/jiffies: Change register_refined_jiffies() to void __init
+
+From: Su Hui <suhui@nfschina.com>
+
+[ Upstream commit 007c07168ac0c64387be500f6604b09ace3f3bdc ]
+
+register_refined_jiffies() is only used in setup code and always returns 0.
+Mark it as __init to save some bytes and change it to void.
+
+Signed-off-by: Su Hui <suhui@nfschina.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lore.kernel.org/all/20250430032734.2079290-2-suhui@nfschina.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/jiffies.h | 2 +-
+ kernel/time/jiffies.c | 5 +----
+ 2 files changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
+index 5d21dacd62bc7d..8e4a2d4fafe07b 100644
+--- a/include/linux/jiffies.h
++++ b/include/linux/jiffies.h
+@@ -59,7 +59,7 @@
+ /* LATCH is used in the interval timer and ftape setup. */
+ #define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
+
+-extern int register_refined_jiffies(long clock_tick_rate);
++extern void register_refined_jiffies(long clock_tick_rate);
+
+ /* TICK_USEC is the time between ticks in usec assuming SHIFTED_HZ */
+ #define TICK_USEC ((USEC_PER_SEC + HZ/2) / HZ)
+diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
+index 7ddedfa49b9dd8..e34a0623e7ada5 100644
+--- a/kernel/time/jiffies.c
++++ b/kernel/time/jiffies.c
+@@ -74,13 +74,11 @@ struct clocksource * __init __weak clocksource_default_clock(void)
+
+ static struct clocksource refined_jiffies;
+
+-int register_refined_jiffies(long cycles_per_second)
++void __init register_refined_jiffies(long cycles_per_second)
+ {
+ u64 nsec_per_tick, shift_hz;
+ long cycles_per_tick;
+
+-
+-
+ refined_jiffies = clocksource_jiffies;
+ refined_jiffies.name = "refined-jiffies";
+ refined_jiffies.rating++;
+@@ -99,5 +97,4 @@ int register_refined_jiffies(long cycles_per_second)
+ refined_jiffies.mult = ((u32)nsec_per_tick) << JIFFIES_SHIFT;
+
+ __clocksource_register(&refined_jiffies);
+- return 0;
+ }
+--
+2.53.0
+
--- /dev/null
+From d71c42f5c266d9e03155ee8575196cab78b9a28f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 9 Jun 2026 17:14:45 +0200
+Subject: time/jiffies: Register jiffies clocksource before usage
+
+From: Thomas Gleixner <tglx@kernel.org>
+
+[ Upstream commit f24df84cbe05e4471c04ac4b921fc0340bbc7752 ]
+
+Teddy reported that a XEN HVM has a long boot delay, which was bisected to
+the recent enhancements to the negative motion detection. It turned out
+that the jiffies clocksource is used in early boot before it is registered,
+which leaves the max_delta_raw field at zero. That causes the read out to
+be clamped to the max delta of 0, which means time is not making progress.
+
+Cure it by ensuring that it is initialized before its first usage in
+timekeeping_init().
+
+Fixes: 76031d9536a0 ("clocksource: Make negative motion detection more robust")
+Reported-by: Teddy Astie <teddy.astie@vates.tech>
+Signed-off-by: Thomas Gleixner <tglx@kernel.org>
+Tested-by: Teddy Astie <teddy.astie@vates.tech>
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/87y0gn3fve.ffs@fw13
+Closes: https://lore.kernel.org/all/1780914594.8631fc262581453bbf619ec5b2062170.19ea6c8227b000701b@vates.tech
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/time/jiffies.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
+index bc4db9e5ab70c1..7ddedfa49b9dd8 100644
+--- a/kernel/time/jiffies.c
++++ b/kernel/time/jiffies.c
+@@ -61,15 +61,14 @@ EXPORT_SYMBOL(get_jiffies_64);
+
+ EXPORT_SYMBOL(jiffies);
+
+-static int __init init_jiffies_clocksource(void)
+-{
+- return __clocksource_register(&clocksource_jiffies);
+-}
+-
+-core_initcall(init_jiffies_clocksource);
++static bool cs_jiffies_registered __initdata;
+
+ struct clocksource * __init __weak clocksource_default_clock(void)
+ {
++ if (!cs_jiffies_registered) {
++ __clocksource_register(&clocksource_jiffies);
++ cs_jiffies_registered = true;
++ }
+ return &clocksource_jiffies;
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 0fea85e11c69abf6dced5b779b3d4727776ab20d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 May 2026 10:33:01 +0800
+Subject: vsock/virtio: bind uarg before filling zerocopy skb
+
+From: Jingguo Tan <tanjingguo@huawei.com>
+
+[ Upstream commit 1e584c304cfb94a759417130b1fc6d30b30c4cce ]
+
+virtio_transport_send_pkt_info() allocates or reuses the zerocopy uarg
+before entering the send loop, but virtio_transport_alloc_skb() still
+fills the skb before it inherits that uarg. When fixed-buffer vectored
+zerocopy hits MAX_SKB_FRAGS, io_sg_from_iter() may partially attach
+managed frags and return -EMSGSIZE. The rollback path call kfree_skb()
+to free an skb that carries SKBFL_MANAGED_FRAG_REFS but no uarg, so
+skb_release_data() falls through to ordinary frag unref.
+
+Pass the uarg into virtio_transport_alloc_skb() and bind it immediately
+before virtio_transport_fill_skb(). This keeps control or no-payload skbs
+untouched while ensuring success and rollback share one lifetime rule.
+
+Fixes: 581512a6dc93 ("vsock/virtio: MSG_ZEROCOPY flag support")
+Signed-off-by: Lin Ma <malin89@huawei.com>
+Signed-off-by: Rongzhen Cui <cuirongzhen@huawei.com>
+Signed-off-by: Jingguo Tan <tanjingguo@huawei.com>
+Acked-by: Arseniy Krasnov <avkrasnov@salutedevices.com>
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
+Link: https://patch.msgid.link/20260527023301.1075581-1-malin89@huawei.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/vmw_vsock/virtio_transport_common.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
+index c3547d783db23c..49bd5d12c30276 100644
+--- a/net/vmw_vsock/virtio_transport_common.c
++++ b/net/vmw_vsock/virtio_transport_common.c
+@@ -208,6 +208,7 @@ static u16 virtio_transport_get_type(struct sock *sk)
+ static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *info,
+ size_t payload_len,
+ bool zcopy,
++ struct ubuf_info *uarg,
+ u32 src_cid,
+ u32 src_port,
+ u32 dst_cid,
+@@ -248,6 +249,12 @@ static struct sk_buff *virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *
+ if (info->msg && payload_len > 0) {
+ int err;
+
++ /* Bind the zerocopy lifetime before filling frags so error
++ * rollback frees managed fixed-buffer pages through
++ * the uarg-aware path.
++ */
++ skb_zcopy_set(skb, uarg, NULL);
++
+ err = virtio_transport_fill_skb(skb, info, payload_len, zcopy);
+ if (err)
+ goto out;
+@@ -367,6 +374,7 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
+ skb_len = min(max_skb_len, rest_len);
+
+ skb = virtio_transport_alloc_skb(info, skb_len, can_zcopy,
++ uarg,
+ src_cid, src_port,
+ dst_cid, dst_port);
+ if (!skb) {
+@@ -374,8 +382,6 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
+ break;
+ }
+
+- skb_zcopy_set(skb, uarg, NULL);
+-
+ virtio_transport_inc_tx_pkt(vvs, skb);
+
+ ret = t_ops->send_pkt(skb);
+@@ -1171,7 +1177,7 @@ static int virtio_transport_reset_no_sock(const struct virtio_transport *t,
+ if (!t)
+ return -ENOTCONN;
+
+- reply = virtio_transport_alloc_skb(&info, 0, false,
++ reply = virtio_transport_alloc_skb(&info, 0, false, NULL,
+ le64_to_cpu(hdr->dst_cid),
+ le32_to_cpu(hdr->dst_port),
+ le64_to_cpu(hdr->src_cid),
+--
+2.53.0
+
--- /dev/null
+From c3b9d59752084c6e16945d671ebf1407a1f92327 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 19:35:59 +0300
+Subject: vsock/virtio: fix zerocopy completion for multi-skb sends
+
+From: Stefano Garzarella <sgarzare@redhat.com>
+
+commit ae38d9179190a956e2a87a69ef1dd6f451b51c4d upstream.
+
+When a large message is fragmented into multiple skbs, the zerocopy
+uarg is only allocated and attached to the last skb in the loop.
+Non-final skbs carry pinned user pages with no completion tracking,
+so the kernel has no way to notify userspace when those pages are safe
+to reuse. If the loop breaks early the uarg is never allocated at all,
+leaking pinned pages with no completion notification.
+
+Fix this by following the approach used by TCP: allocate the zerocopy
+uarg (if not provided by the caller) before the send loop and attach
+it to every skb via skb_zcopy_set(), which takes a reference per skb.
+Each skb's completion properly decrements the refcount, and the
+notification only fires after the last skb is freed.
+On failure, if no data was sent, the uarg is cleanly aborted via
+net_zcopy_put_abort().
+
+This issue was initially discovered by sashiko while reviewing commit
+1cb36e252211 ("vsock/virtio: fix MSG_ZEROCOPY pinned-pages accounting")
+but was pre-existing.
+
+Fixes: 581512a6dc93 ("vsock/virtio: MSG_ZEROCOPY flag support")
+Closes: https://sashiko.dev/#/patchset/20260420132051.217589-1-sgarzare%40redhat.com
+Reported-by: Maher Azzouzi <maherazz04@gmail.com>
+Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Acked-by: Arseniy Krasnov <avkrasnov@salutedevices.com>
+Link: https://patch.msgid.link/20260514092948.268720-1-sgarzare@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Alexander Martyniuk <alexevgmart@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/vmw_vsock/virtio_transport_common.c | 78 +++++++++++--------------
+ 1 file changed, 34 insertions(+), 44 deletions(-)
+
+diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
+index 95170c7be7586d..c3547d783db23c 100644
+--- a/net/vmw_vsock/virtio_transport_common.c
++++ b/net/vmw_vsock/virtio_transport_common.c
+@@ -72,35 +72,6 @@ static bool virtio_transport_can_zcopy(const struct virtio_transport *t_ops,
+ return true;
+ }
+
+-static int virtio_transport_init_zcopy_skb(struct vsock_sock *vsk,
+- struct sk_buff *skb,
+- struct msghdr *msg,
+- bool zerocopy)
+-{
+- struct ubuf_info *uarg;
+-
+- if (msg->msg_ubuf) {
+- uarg = msg->msg_ubuf;
+- net_zcopy_get(uarg);
+- } else {
+- struct iov_iter *iter = &msg->msg_iter;
+- struct ubuf_info_msgzc *uarg_zc;
+-
+- uarg = msg_zerocopy_realloc(sk_vsock(vsk),
+- iter->count,
+- NULL);
+- if (!uarg)
+- return -1;
+-
+- uarg_zc = uarg_to_msgzc(uarg);
+- uarg_zc->zerocopy = zerocopy ? 1 : 0;
+- }
+-
+- skb_zcopy_init(skb, uarg);
+-
+- return 0;
+-}
+-
+ static int virtio_transport_fill_skb(struct sk_buff *skb,
+ struct virtio_vsock_pkt_info *info,
+ size_t len,
+@@ -321,8 +292,10 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
+ u32 src_cid, src_port, dst_cid, dst_port;
+ const struct virtio_transport *t_ops;
+ struct virtio_vsock_sock *vvs;
++ struct ubuf_info *uarg = NULL;
+ u32 pkt_len = info->pkt_len;
+ bool can_zcopy = false;
++ bool have_uref = false;
+ u32 rest_len;
+ int ret;
+
+@@ -364,6 +337,25 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
+ if (can_zcopy)
+ max_skb_len = min_t(u32, VIRTIO_VSOCK_MAX_PKT_BUF_SIZE,
+ (MAX_SKB_FRAGS * PAGE_SIZE));
++
++ if (info->msg->msg_flags & MSG_ZEROCOPY &&
++ info->op == VIRTIO_VSOCK_OP_RW) {
++ uarg = info->msg->msg_ubuf;
++
++ if (!uarg) {
++ uarg = msg_zerocopy_realloc(sk_vsock(vsk),
++ pkt_len, NULL);
++ if (!uarg) {
++ virtio_transport_put_credit(vvs, pkt_len);
++ return -ENOMEM;
++ }
++
++ if (!can_zcopy)
++ uarg_to_msgzc(uarg)->zerocopy = 0;
++
++ have_uref = true;
++ }
++ }
+ }
+
+ rest_len = pkt_len;
+@@ -382,21 +374,7 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
+ break;
+ }
+
+- /* We process buffer part by part, allocating skb on
+- * each iteration. If this is last skb for this buffer
+- * and MSG_ZEROCOPY mode is in use - we must allocate
+- * completion for the current syscall.
+- */
+- if (info->msg && info->msg->msg_flags & MSG_ZEROCOPY &&
+- skb_len == rest_len && info->op == VIRTIO_VSOCK_OP_RW) {
+- if (virtio_transport_init_zcopy_skb(vsk, skb,
+- info->msg,
+- can_zcopy)) {
+- kfree_skb(skb);
+- ret = -ENOMEM;
+- break;
+- }
+- }
++ skb_zcopy_set(skb, uarg, NULL);
+
+ virtio_transport_inc_tx_pkt(vvs, skb);
+
+@@ -420,6 +398,18 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
+
+ virtio_transport_put_credit(vvs, rest_len);
+
++ /* msg_zerocopy_realloc() initializes the ubuf_info refcnt to 1.
++ * skb_zcopy_set() increases it for each skb, so we can drop that
++ * initial reference to keep it balanced.
++ */
++ if (have_uref) {
++ if (rest_len == pkt_len)
++ /* No data sent, abort the notification. */
++ net_zcopy_put_abort(uarg, true);
++ else
++ net_zcopy_put(uarg);
++ }
++
+ /* Return number of bytes, if any data has been sent. */
+ if (rest_len != pkt_len)
+ ret = pkt_len - rest_len;
+--
+2.53.0
+
--- /dev/null
+From e7532e903b5167e00693a66acc994cacecdb2650 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 12:04:30 -0400
+Subject: x86/mm: Fix check/use ordering in switch_mm_irqs_off()
+
+From: Stephen Dolan <sdolan@janestreet.com>
+
+This is a stable-specific fix. There is no single upstream commit to
+cherry-pick; the equivalent mainline fix is commit 83b0177a6c48
+("x86/mm: Fix SMP ordering in switch_mm_irqs_off()"), which is in
+v6.18 but does not apply to these trees because the surrounding code
+was refactored.
+
+The backports of commit fea4e317f9e7 ("x86/mm: Eliminate window where
+TLB flushes may be inadvertently skipped") -- the fix for
+CVE-2025-37964 -- to the 6.1, 6.6 and 6.12 trees ended up with two
+code blocks in the wrong order relative to mainline. The fix depends
+on setting cpu_tlbstate.loaded_mm to LOADED_MM_SWITCHING *before*
+reading tlb_gen, so that a concurrent TLB shootdown either sees
+LOADED_MM_SWITCHING and sends the IPI, or the switching CPU sees the
+updated tlb_gen. In the stable trees the write of LOADED_MM_SWITCHING
+was placed after the tlb_gen read, so the race window fea4e317f9e7 was
+meant to close is still open and CVE-2025-37964 is unfixed there:
+a process can be left running with stale TLB entries, which typically
+manifests as rare, hard-to-bisect memory corruption or segfaults.
+
+This has been confirmed by several independent parties:
+
+ - reproduced on 6.1.y/6.6.y/6.12.y with the test program in [1],
+ and confirmed fixed by this patch
+ - Seth Forshee saw segfaults on 6.12.y within ~30 minutes of running
+ a test workload; with this patch it ran 18 hours cleanly [2]
+ - Greg Thelen reports 6.6.y- and 6.12.y-based test failures fixed by
+ this patch [3]
+
+Dave Hansen acked the patch [4] and has no objection to it going into
+stable [5].
+
+The patch below is against 6.12.y; the identical change applies to
+6.1.y and 6.6.y. (The cpumask_test_cpu()/smp_mb() portion of the
+mainline fix is not needed here because commit 209954cbc7d0
+("x86/mm/tlb: Update mm_cpumask lazily") was never backported to these
+trees.)
+
+[1] https://lore.kernel.org/lkml/CAHDw0oGd0B4=uuv8NGqbUQ_ZVmSheU2bN70e4QhFXWvuAZdt2w@mail.gmail.com/
+[2] https://lore.kernel.org/lkml/aZYWXe739XUJrBld@do-x1carbon/
+[3] https://lore.kernel.org/lkml/CAHH2K0brx9omC9QYyB6Lio3t_1Lf8v=VaFoiaG23UgQ-aec89Q@mail.gmail.com/
+[4] https://lore.kernel.org/lkml/281e8018-5506-4a79-8775-e0de7e58b95f@intel.com/
+[5] https://lore.kernel.org/lkml/86421ee5-5332-46c2-bb48-d40310b818be@intel.com/
+
+Fixes: fea4e317f9e7 ("x86/mm: Eliminate window where TLB flushes may be inadvertently skipped") # 6.1.y/6.6.y/6.12.y backports
+Acked-by: Dave Hansen <dave.hansen@intel.com>
+Tested-by: Seth Forshee <sforshee@kernel.org>
+Tested-by: Eric Hagberg <ehagberg@janestreet.com>
+Signed-off-by: Stephen Dolan <sdolan@janestreet.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/mm/tlb.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
+index 8629d90fdcd922..ed182831063c27 100644
+--- a/arch/x86/mm/tlb.c
++++ b/arch/x86/mm/tlb.c
+@@ -606,6 +606,14 @@ void switch_mm_irqs_off(struct mm_struct *unused, struct mm_struct *next,
+ */
+ cond_mitigation(tsk);
+
++ /*
++ * Indicate that CR3 is about to change. nmi_uaccess_okay()
++ * and others are sensitive to the window where mm_cpumask(),
++ * CR3 and cpu_tlbstate.loaded_mm are not all in sync.
++ */
++ this_cpu_write(cpu_tlbstate.loaded_mm, LOADED_MM_SWITCHING);
++ barrier();
++
+ /*
+ * Stop remote flushes for the previous mm.
+ * Skip kernel threads; we never send init_mm TLB flushing IPIs,
+@@ -623,14 +631,6 @@ void switch_mm_irqs_off(struct mm_struct *unused, struct mm_struct *next,
+ next_tlb_gen = atomic64_read(&next->context.tlb_gen);
+
+ choose_new_asid(next, next_tlb_gen, &new_asid, &need_flush);
+-
+- /*
+- * Indicate that CR3 is about to change. nmi_uaccess_okay()
+- * and others are sensitive to the window where mm_cpumask(),
+- * CR3 and cpu_tlbstate.loaded_mm are not all in sync.
+- */
+- this_cpu_write(cpu_tlbstate.loaded_mm, LOADED_MM_SWITCHING);
+- barrier();
+ }
+
+ new_lam = mm_lam_cr3_mask(next);
+--
+2.53.0
+
--- /dev/null
+From b206dc73e3ee5e222a2211e38f6e1fe95cc9ddf6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Apr 2026 18:48:29 +0000
+Subject: af_unix: Drop all SCM attributes for SOCKMAP.
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit 965dc93481d1b80d341bdd16c27b16fe197175ee ]
+
+SOCKMAP can hide inflight fd from AF_UNIX GC.
+
+When a socket in SOCKMAP receives skb with inflight fd,
+sk_psock_verdict_data_ready() looks up the mapped socket and
+enqueue skb to its psock->ingress_skb.
+
+Since neither the old nor the new GC can inspect the psock
+queue, the hidden skb leaks the inflight sockets. Note that
+this cannot be detected via kmemleak because inflight sockets
+are linked to a global list.
+
+In addition, SOCKMAP redirect breaks the Tarjan-based GC's
+assumption that unix_edge.successor is always alive, which
+is no longer true once skb is redirected, resulting in
+use-after-free below. [0]
+
+Moreover, SOCKMAP does not call scm_stat_del() properly,
+so unix_show_fdinfo() could report an incorrect fd count.
+
+sk_msg_recvmsg() does not support any SCM attributes in the
+first place.
+
+Let's drop all SCM attributes before passing skb to the
+SOCKMAP layer.
+
+[0]:
+BUG: KASAN: slab-use-after-free in unix_del_edges (net/unix/garbage.c:118 net/unix/garbage.c:181 net/unix/garbage.c:251)
+Read of size 8 at addr ffff888125362670 by task kworker/56:1/496
+
+CPU: 56 UID: 0 PID: 496 Comm: kworker/56:1 Not tainted 7.0.0-rc7-00263-gb9d8b856689d #3 PREEMPT(lazy)
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
+Workqueue: events sk_psock_backlog
+Call Trace:
+ <TASK>
+ dump_stack_lvl (lib/dump_stack.c:122)
+ print_report (mm/kasan/report.c:379)
+ kasan_report (mm/kasan/report.c:597)
+ unix_del_edges (net/unix/garbage.c:118 net/unix/garbage.c:181 net/unix/garbage.c:251)
+ unix_destroy_fpl (net/unix/garbage.c:317)
+ unix_destruct_scm (./include/net/scm.h:80 ./include/net/scm.h:86 net/unix/af_unix.c:1976)
+ sk_psock_backlog (./include/linux/skbuff.h:?)
+ process_scheduled_works (kernel/workqueue.c:?)
+ worker_thread (kernel/workqueue.c:?)
+ kthread (kernel/kthread.c:438)
+ ret_from_fork (arch/x86/kernel/process.c:164)
+ ret_from_fork_asm (arch/x86/entry/entry_64.S:258)
+ </TASK>
+
+Allocated by task 955:
+ kasan_save_track (mm/kasan/common.c:58 mm/kasan/common.c:78)
+ __kasan_slab_alloc (mm/kasan/common.c:369)
+ kmem_cache_alloc_noprof (mm/slub.c:4539)
+ sk_prot_alloc (net/core/sock.c:2240)
+ sk_alloc (net/core/sock.c:2301)
+ unix_create1 (net/unix/af_unix.c:1099)
+ unix_create (net/unix/af_unix.c:1169)
+ __sock_create (net/socket.c:1606)
+ __sys_socketpair (net/socket.c:1811)
+ __x64_sys_socketpair (net/socket.c:1863 net/socket.c:1860 net/socket.c:1860)
+ do_syscall_64 (arch/x86/entry/syscall_64.c:?)
+ entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
+
+Freed by task 496:
+ kasan_save_track (mm/kasan/common.c:58 mm/kasan/common.c:78)
+ kasan_save_free_info (mm/kasan/generic.c:587)
+ __kasan_slab_free (mm/kasan/common.c:287)
+ kmem_cache_free (mm/slub.c:6165)
+ __sk_destruct (net/core/sock.c:2282 net/core/sock.c:2384)
+ sk_psock_destroy (./include/net/sock.h:?)
+ process_scheduled_works (kernel/workqueue.c:?)
+ worker_thread (kernel/workqueue.c:?)
+ kthread (kernel/kthread.c:438)
+ ret_from_fork (arch/x86/kernel/process.c:164)
+ ret_from_fork_asm (arch/x86/entry/entry_64.S:258)
+
+Fixes: c63829182c37 ("af_unix: Implement ->psock_update_sk_prot()")
+Fixes: 77462de14a43 ("af_unix: Add read_sock for stream socket types")
+Reported-by: Xingyu Jin <xingyuj@google.com>
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://patch.msgid.link/20260415184830.3988432-1-kuniyu@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/unix/af_unix.c | 35 +++++++++++++++++++++++++++--------
+ 1 file changed, 27 insertions(+), 8 deletions(-)
+
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index b339f83caf036e..12c075a07e76b7 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -1985,16 +1985,19 @@ static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)
+
+ static void unix_destruct_scm(struct sk_buff *skb)
+ {
+- struct scm_cookie scm;
++ struct scm_cookie scm = {};
++
++ swap(scm.pid, UNIXCB(skb).pid);
+
+- memset(&scm, 0, sizeof(scm));
+- scm.pid = UNIXCB(skb).pid;
+ if (UNIXCB(skb).fp)
+ unix_detach_fds(&scm, skb);
+
+- /* Alas, it calls VFS */
+- /* So fscking what? fput() had been SMP-safe since the last Summer */
+ scm_destroy(&scm);
++}
++
++static void unix_wfree(struct sk_buff *skb)
++{
++ unix_destruct_scm(skb);
+ sock_wfree(skb);
+ }
+
+@@ -2010,7 +2013,7 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
+ if (scm->fp && send_fds)
+ err = unix_attach_fds(scm, skb);
+
+- skb->destructor = unix_destruct_scm;
++ skb->destructor = unix_wfree;
+ return err;
+ }
+
+@@ -2087,6 +2090,13 @@ static void scm_stat_del(struct sock *sk, struct sk_buff *skb)
+ }
+ }
+
++static void unix_orphan_scm(struct sock *sk, struct sk_buff *skb)
++{
++ scm_stat_del(sk, skb);
++ unix_destruct_scm(skb);
++ skb->destructor = sock_wfree;
++}
++
+ /*
+ * Send AF_UNIX data.
+ */
+@@ -2704,10 +2714,16 @@ static int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
+ int err;
+
+ mutex_lock(&u->iolock);
++
+ skb = skb_recv_datagram(sk, MSG_DONTWAIT, &err);
+- mutex_unlock(&u->iolock);
+- if (!skb)
++ if (!skb) {
++ mutex_unlock(&u->iolock);
+ return err;
++ }
++
++ unix_orphan_scm(sk, skb);
++
++ mutex_unlock(&u->iolock);
+
+ return recv_actor(sk, skb);
+ }
+@@ -2905,6 +2921,9 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
+ #endif
+
+ spin_unlock(&queue->lock);
++
++ unix_orphan_scm(sk, skb);
++
+ mutex_unlock(&u->iolock);
+
+ return recv_actor(sk, skb);
+--
+2.53.0
+
--- /dev/null
+From ef65a09d670e123f65ae4839058302666bc22a1a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 12:47:27 +0800
+Subject: bpf: Clear delta when clearing reg id for non-{add,sub} ops
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+commit 1b327732c84640c1e3da487eefe9d00cc9f2dd34 upstream.
+
+When a non-{add,sub} alu op such as xor is performed on a scalar
+register that previously had a BPF_ADD_CONST delta, the else path
+in adjust_reg_min_max_vals() only clears dst_reg->id but leaves
+dst_reg->delta unchanged.
+
+This stale delta can propagate via assign_scalar_id_before_mov()
+when the register is later used in a mov. It gets a fresh id but
+keeps the stale delta from the old (now-cleared) BPF_ADD_CONST.
+This stale delta can later propagate leading to a verifier-vs-
+runtime value mismatch.
+
+The clear_id label already correctly clears both delta and id.
+Make the else path consistent by also zeroing the delta when id
+is cleared. More generally, this introduces a helper clear_scalar_id()
+which internally takes care of zeroing. There are various other
+locations in the verifier where only the id is cleared. By using
+the helper we catch all current and future locations.
+
+Fixes: 98d7ca374ba4 ("bpf: Track delta between "linked" registers.")
+Reported-by: STAR Labs SG <info@starlabs.sg>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Link: https://lore.kernel.org/r/20260407192421.508817-2-daniel@iogearbox.net
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+[shung-hsi.yu: `delta` field was called `off` before commit 3d91c618aca4 ("bpf:
+rename bpf_reg_state->off to bpf_reg_state->delta"), and clear_singular_ids()
+does not exists before commit b2a0aa3a8739 ("bpf: Clear singular ids for
+scalars in is_state_visited()")]
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/verifier.c | 50 ++++++++++++++++++++++---------------------
+ 1 file changed, 26 insertions(+), 24 deletions(-)
+
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 3dcf591acd50d2..bf8cadd19593b2 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -5013,27 +5013,30 @@ static bool __is_pointer_value(bool allow_ptr_leaks,
+ return reg->type != SCALAR_VALUE;
+ }
+
++static void clear_scalar_id(struct bpf_reg_state *reg)
++{
++ reg->id = 0;
++ reg->off = 0;
++}
++
+ static void assign_scalar_id_before_mov(struct bpf_verifier_env *env,
+ struct bpf_reg_state *src_reg)
+ {
+ if (src_reg->type != SCALAR_VALUE)
+ return;
+-
+- if (src_reg->id & BPF_ADD_CONST) {
+- /*
+- * The verifier is processing rX = rY insn and
+- * rY->id has special linked register already.
+- * Cleared it, since multiple rX += const are not supported.
+- */
+- src_reg->id = 0;
+- src_reg->off = 0;
+- }
+-
++ /*
++ * The verifier is processing rX = rY insn and
++ * rY->id has special linked register already.
++ * Cleared it, since multiple rX += const are not supported.
++ */
++ if (src_reg->id & BPF_ADD_CONST)
++ clear_scalar_id(src_reg);
++ /*
++ * Ensure that src_reg has a valid ID that will be copied to
++ * dst_reg and then will be used by sync_linked_regs() to
++ * propagate min/max range.
++ */
+ if (!src_reg->id && !tnum_is_const(src_reg->var_off))
+- /* Ensure that src_reg has a valid ID that will be copied to
+- * dst_reg and then will be used by sync_linked_regs() to
+- * propagate min/max range.
+- */
+ src_reg->id = ++env->id_gen;
+ }
+
+@@ -5466,7 +5469,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
+ * coerce_reg_to_size will adjust the boundaries.
+ */
+ if (get_reg_width(reg) > size * BITS_PER_BYTE)
+- state->regs[dst_regno].id = 0;
++ clear_scalar_id(&state->regs[dst_regno]);
+ } else {
+ int spill_cnt = 0, zero_cnt = 0;
+
+@@ -15476,7 +15479,7 @@ static void scalar_byte_swap(struct bpf_reg_state *dst_reg, struct bpf_insn *ins
+ * any existing ties and avoid incorrect bounds propagation.
+ */
+ if (need_bswap || insn->imm == 16 || insn->imm == 32)
+- dst_reg->id = 0;
++ clear_scalar_id(dst_reg);
+
+ if (need_bswap) {
+ if (insn->imm == 16)
+@@ -15845,8 +15848,7 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
+ * we cannot accumulate another val into rx->off.
+ */
+ clear_id:
+- dst_reg->off = 0;
+- dst_reg->id = 0;
++ clear_scalar_id(dst_reg);
+ } else {
+ if (alu32)
+ dst_reg->id |= BPF_ADD_CONST32;
+@@ -15859,7 +15861,7 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env,
+ * Make sure ID is cleared otherwise dst_reg min/max could be
+ * incorrectly propagated into other registers by sync_linked_regs()
+ */
+- dst_reg->id = 0;
++ clear_scalar_id(dst_reg);
+ }
+ return 0;
+ }
+@@ -15990,7 +15992,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
+ assign_scalar_id_before_mov(env, src_reg);
+ copy_register_state(dst_reg, src_reg);
+ if (!no_sext)
+- dst_reg->id = 0;
++ clear_scalar_id(dst_reg);
+ coerce_reg_to_size_sx(dst_reg, insn->off >> 3);
+ dst_reg->subreg_def = DEF_NOT_SUBREG;
+ } else {
+@@ -16016,7 +16018,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
+ * propagated into src_reg by sync_linked_regs()
+ */
+ if (!is_src_reg_u32)
+- dst_reg->id = 0;
++ clear_scalar_id(dst_reg);
+ dst_reg->subreg_def = env->insn_idx + 1;
+ } else {
+ /* case: W1 = (s8, s16)W2 */
+@@ -16026,7 +16028,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
+ assign_scalar_id_before_mov(env, src_reg);
+ copy_register_state(dst_reg, src_reg);
+ if (!no_sext)
+- dst_reg->id = 0;
++ clear_scalar_id(dst_reg);
+ dst_reg->subreg_def = env->insn_idx + 1;
+ coerce_subreg_to_size_sx(dst_reg, insn->off >> 3);
+ }
+@@ -16856,7 +16858,7 @@ static void __collect_linked_regs(struct linked_regs *reg_set, struct bpf_reg_st
+ e->is_reg = is_reg;
+ e->regno = spi_or_reg;
+ } else {
+- reg->id = 0;
++ clear_scalar_id(reg);
+ }
+ }
+
+--
+2.53.0
+
--- /dev/null
+From 2e2fc7864acf998cb8f618832a317fe577b14cd8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:50:58 -0700
+Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit b2c41fa9dd8fc740c489e060b199165771f268d1 upstream.
+
+Remove sun4i_ss_rng, as it is insecure and unused:
+
+- It has multiple vulnerabilities. sun4i_ss_prng_seed() is missing
+ locking and has a buffer overflow. sun4i_ss_prng_generate() fails to
+ fill the entire buffer with cryptographic random bytes, because it
+ rounds the destination length down and also doesn't actually wait for
+ the hardware to be ready before pulling bytes from it.
+
+- No user of this code is known. It's usable only theoretically via the
+ "rng" algorithm type of AF_ALG. But userspace actually just uses the
+ actual Linux RNG (/dev/random etc) instead. And rng_algs don't
+ contribute entropy to the actual Linux RNG either. (This may have
+ been confused with hwrng, which does contribute entropy.)
+
+The sun4i_ss_prng_seed() buffer overflow was reported by Tianchu Chen
+and discovered by Atuin - Automated Vulnerability Discovery Engine
+
+There's no point in fixing all these vulnerabilities individually when
+this is unused code, so let's just remove it.
+
+Fixes: b8ae5c7387ad ("crypto: sun4i-ss - support the Security System PRNG")
+Cc: stable@vger.kernel.org
+Reported-by: Tianchu Chen <flynnnchen@tencent.com>
+Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/
+Acked-by: Corentin LABBE <clabbe.montjoie@gmail.com>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/configs/sunxi_defconfig | 1 -
+ drivers/crypto/allwinner/Kconfig | 8 ---
+ drivers/crypto/allwinner/sun4i-ss/Makefile | 1 -
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-core.c | 36 ----------
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-prng.c | 69 -------------------
+ drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h | 20 ------
+ 6 files changed, 135 deletions(-)
+ delete mode 100644 drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+
+diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
+index a83d29fed17563..f4b8d8f7dbefbb 100644
+--- a/arch/arm/configs/sunxi_defconfig
++++ b/arch/arm/configs/sunxi_defconfig
+@@ -170,7 +170,6 @@ CONFIG_ROOT_NFS=y
+ CONFIG_NLS_CODEPAGE_437=y
+ CONFIG_NLS_ISO8859_1=y
+ CONFIG_CRYPTO_DEV_SUN4I_SS=y
+-CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG=y
+ CONFIG_CRYPTO_DEV_SUN8I_CE=y
+ CONFIG_CRYPTO_DEV_SUN8I_SS=y
+ CONFIG_DMA_CMA=y
+diff --git a/drivers/crypto/allwinner/Kconfig b/drivers/crypto/allwinner/Kconfig
+index b8e75210a0e315..06ea0e9fe6f22f 100644
+--- a/drivers/crypto/allwinner/Kconfig
++++ b/drivers/crypto/allwinner/Kconfig
+@@ -24,14 +24,6 @@ config CRYPTO_DEV_SUN4I_SS
+ To compile this driver as a module, choose M here: the module
+ will be called sun4i-ss.
+
+-config CRYPTO_DEV_SUN4I_SS_PRNG
+- bool "Support for Allwinner Security System PRNG"
+- depends on CRYPTO_DEV_SUN4I_SS
+- select CRYPTO_RNG
+- help
+- Select this option if you want to provide kernel-side support for
+- the Pseudo-Random Number Generator found in the Security System.
+-
+ config CRYPTO_DEV_SUN4I_SS_DEBUG
+ bool "Enable sun4i-ss stats"
+ depends on CRYPTO_DEV_SUN4I_SS
+diff --git a/drivers/crypto/allwinner/sun4i-ss/Makefile b/drivers/crypto/allwinner/sun4i-ss/Makefile
+index c0a2797d316827..06a9ae81f9f808 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/Makefile
++++ b/drivers/crypto/allwinner/sun4i-ss/Makefile
+@@ -1,4 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sun4i-ss.o
+ sun4i-ss-y += sun4i-ss-core.o sun4i-ss-hash.o sun4i-ss-cipher.o
+-sun4i-ss-$(CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG) += sun4i-ss-prng.o
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+index 58a76e2ba64e25..35ef0930e77f1a 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+@@ -213,23 +213,6 @@ static struct sun4i_ss_alg_template ss_algs[] = {
+ }
+ }
+ },
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+-{
+- .type = CRYPTO_ALG_TYPE_RNG,
+- .alg.rng = {
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "sun4i_ss_rng",
+- .cra_priority = 300,
+- .cra_ctxsize = 0,
+- .cra_module = THIS_MODULE,
+- },
+- .generate = sun4i_ss_prng_generate,
+- .seed = sun4i_ss_prng_seed,
+- .seedsize = SS_SEED_LEN / BITS_PER_BYTE,
+- }
+-},
+-#endif
+ };
+
+ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
+@@ -247,12 +230,6 @@ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
+ ss_algs[i].stat_req, ss_algs[i].stat_opti, ss_algs[i].stat_fb,
+ ss_algs[i].stat_bytes);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",
+- ss_algs[i].alg.rng.base.cra_driver_name,
+- ss_algs[i].alg.rng.base.cra_name,
+- ss_algs[i].stat_req, ss_algs[i].stat_bytes);
+- break;
+ case CRYPTO_ALG_TYPE_AHASH:
+ seq_printf(seq, "%s %s reqs=%lu\n",
+ ss_algs[i].alg.hash.halg.base.cra_driver_name,
+@@ -471,13 +448,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ goto error_alg;
+ }
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- err = crypto_register_rng(&ss_algs[i].alg.rng);
+- if (err) {
+- dev_err(ss->dev, "Fail to register %s\n",
+- ss_algs[i].alg.rng.base.cra_name);
+- }
+- break;
+ }
+ }
+
+@@ -497,9 +467,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+ error_pm:
+@@ -520,9 +487,6 @@ static void sun4i_ss_remove(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+deleted file mode 100644
+index 491fcb7b81b40b..00000000000000
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
++++ /dev/null
+@@ -1,69 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-#include "sun4i-ss.h"
+-
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- memcpy(algt->ss->seed, seed, slen);
+-
+- return 0;
+-}
+-
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+- int i, err;
+- u32 v;
+- u32 *data = (u32 *)dst;
+- const u32 mode = SS_OP_PRNG | SS_PRNG_CONTINUE | SS_ENABLED;
+- size_t len;
+- struct sun4i_ss_ctx *ss;
+- unsigned int todo = (dlen / 4) * 4;
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- ss = algt->ss;
+-
+- err = pm_runtime_resume_and_get(ss->dev);
+- if (err < 0)
+- return err;
+-
+- if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) {
+- algt->stat_req++;
+- algt->stat_bytes += todo;
+- }
+-
+- spin_lock_bh(&ss->slock);
+-
+- writel(mode, ss->base + SS_CTL);
+-
+- while (todo > 0) {
+- /* write the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++)
+- writel(ss->seed[i], ss->base + SS_KEY0 + i * 4);
+-
+- /* Read the random data */
+- len = min_t(size_t, SS_DATA_LEN / BITS_PER_BYTE, todo);
+- readsl(ss->base + SS_TXFIFO, data, len / 4);
+- data += len / 4;
+- todo -= len;
+-
+- /* Update the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++) {
+- v = readl(ss->base + SS_KEY0 + i * 4);
+- ss->seed[i] = v;
+- }
+- }
+-
+- writel(0, ss->base + SS_CTL);
+- spin_unlock_bh(&ss->slock);
+-
+- pm_runtime_put(ss->dev);
+-
+- return 0;
+-}
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+index 6c5d4aa6453c7f..f7d1c79ac677d8 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+@@ -31,8 +31,6 @@
+ #include <crypto/internal/skcipher.h>
+ #include <crypto/aes.h>
+ #include <crypto/internal/des.h>
+-#include <crypto/internal/rng.h>
+-#include <crypto/rng.h>
+
+ #define SS_CTL 0x00
+ #define SS_KEY0 0x04
+@@ -62,10 +60,6 @@
+
+ /* SS_CTL configuration values */
+
+-/* PRNG generator mode - bit 15 */
+-#define SS_PRNG_ONESHOT (0 << 15)
+-#define SS_PRNG_CONTINUE (1 << 15)
+-
+ /* IV mode for hash */
+ #define SS_IV_ARBITRARY (1 << 14)
+
+@@ -94,14 +88,10 @@
+ #define SS_OP_3DES (2 << 4)
+ #define SS_OP_SHA1 (3 << 4)
+ #define SS_OP_MD5 (4 << 4)
+-#define SS_OP_PRNG (5 << 4)
+
+ /* Data end bit - bit 2 */
+ #define SS_DATA_END (1 << 2)
+
+-/* PRNG start bit - bit 1 */
+-#define SS_PRNG_START (1 << 1)
+-
+ /* SS Enable bit - bit 0 */
+ #define SS_DISABLED (0 << 0)
+ #define SS_ENABLED (1 << 0)
+@@ -128,9 +118,6 @@
+ #define SS_RXFIFO_EMP_INT_ENABLE (1 << 2)
+ #define SS_TXFIFO_AVA_INT_ENABLE (1 << 0)
+
+-#define SS_SEED_LEN 192
+-#define SS_DATA_LEN 160
+-
+ /*
+ * struct ss_variant - Describe SS hardware variant
+ * @sha1_in_be: The SHA1 digest is given by SS in BE, and so need to be inverted.
+@@ -151,9 +138,6 @@ struct sun4i_ss_ctx {
+ char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */
+ char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */
+ spinlock_t slock; /* control the use of the device */
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+- u32 seed[SS_SEED_LEN / BITS_PER_LONG];
+-#endif
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_stats;
+ };
+@@ -164,7 +148,6 @@ struct sun4i_ss_alg_template {
+ union {
+ struct skcipher_alg crypto;
+ struct ahash_alg hash;
+- struct rng_alg rng;
+ } alg;
+ struct sun4i_ss_ctx *ss;
+ unsigned long stat_req;
+@@ -231,6 +214,3 @@ int sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+ int sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen);
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen);
+--
+2.53.0
+
--- /dev/null
+From 5d037460a1553fa9dd96a682e176a7fdcee26381 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 09:51:27 -0700
+Subject: exfat: preserve benign secondary entries during rename and move
+
+From: Rochan Avlur <rochan.avlur@gmail.com>
+
+[ Upstream commit 942296784b2a9439651750c42f540bf2579b330f ]
+
+Commit 8258ef28001a ("exfat: handle unreconized benign secondary
+entries") added cluster freeing for benign secondary entries inside
+exfat_remove_entries(). However, exfat_remove_entries() is also called
+from the rename and move paths (exfat_rename_file and exfat_move_file),
+where the old entry set is being relocated rather than deleted. This
+causes benign secondary entries such as vendor extension entries to be
+silently destroyed on rename or cross-directory move, violating the
+exFAT spec requirement (section 8.2) that implementations preserve
+unrecognized benign secondary entries.
+
+Fix this by adding a free_benign parameter to exfat_remove_entries()
+so callers can suppress cluster freeing during relocation, and
+extending exfat_init_ext_entry() to copy trailing benign secondary
+entries from the old entry set into the new one internally. Also
+clean up the error paths to delete newly allocated entries on failure.
+
+Fixes: 8258ef28001a ("exfat: handle unreconized benign secondary entries")
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/linux-fsdevel/CAG7tbBV--waov7XVu2FHQEc6paR92dufS=em9DW5Kzsrpu3iQg@mail.gmail.com/
+Signed-off-by: Rochan Avlur <rochan.avlur@gmail.com>
+Reviewed-by: Yuezhang Mo <Yuezhang.Mo@sony.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Rochan Avlur <rochan.avlur@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/exfat/dir.c | 49 ++++++++++++++++++++++---
+ fs/exfat/exfat_fs.h | 5 ++-
+ fs/exfat/namei.c | 89 +++++++++++++++++++++++++++++++++++----------
+ 3 files changed, 116 insertions(+), 27 deletions(-)
+
+diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c
+index e1b28c1a7e8576..1f6cb533a48d18 100644
+--- a/fs/exfat/dir.c
++++ b/fs/exfat/dir.c
+@@ -481,31 +481,70 @@ static void exfat_free_benign_secondary_clusters(struct inode *inode,
+ exfat_free_cluster(inode, &dir);
+ }
+
++/*
++ * exfat_init_ext_entry - initialize extension entries in a directory entry set
++ * @es: target entry set
++ * @num_entries: number of entries excluding benign secondary entries
++ * @p_uniname: filename to store
++ * @old_es: optional source entry set with benign secondary entries, or NULL
++ * @num_extra: number of benign secondary entries to copy from @old_es
++ *
++ * Set up the file, stream extension, and filename entries in @es, optionally
++ * preserving @num_extra benign secondary entries from @old_es. @es and @old_es
++ * may refer to the same entry set; excess entries are marked as deleted.
++ */
+ void exfat_init_ext_entry(struct exfat_entry_set_cache *es, int num_entries,
+- struct exfat_uni_name *p_uniname)
++ struct exfat_uni_name *p_uniname,
++ struct exfat_entry_set_cache *old_es, int num_extra)
+ {
+- int i;
++ int i, src_start = 0, old_num;
+ unsigned short *uniname = p_uniname->name;
+ struct exfat_dentry *ep;
+
++ if (WARN_ON(num_extra < 0 || (num_extra && (!old_es ||
++ old_es->num_entries < ES_IDX_FIRST_FILENAME + num_extra))))
++ num_extra = 0;
++
++ /*
++ * Save old entry count and source position before modifying
++ * es->num_entries, since old_es and es may point to the same
++ * entry set.
++ */
++ old_num = es->num_entries;
++ if (old_es && num_extra > 0)
++ src_start = old_es->num_entries - num_extra;
++
++ es->num_entries = num_entries + num_extra;
+ ep = exfat_get_dentry_cached(es, ES_IDX_FILE);
+- ep->dentry.file.num_ext = (unsigned char)(num_entries - 1);
++ ep->dentry.file.num_ext = (unsigned char)(num_entries - 1 + num_extra);
+
+ ep = exfat_get_dentry_cached(es, ES_IDX_STREAM);
+ ep->dentry.stream.name_len = p_uniname->name_len;
+ ep->dentry.stream.name_hash = cpu_to_le16(p_uniname->name_hash);
+
++ if (old_es && num_extra > 0) {
++ for (i = 0; i < num_extra; i++)
++ *exfat_get_dentry_cached(es, num_entries + i) =
++ *exfat_get_dentry_cached(old_es, src_start + i);
++ }
++
+ for (i = ES_IDX_FIRST_FILENAME; i < num_entries; i++) {
+ ep = exfat_get_dentry_cached(es, i);
+ exfat_init_name_entry(ep, uniname);
+ uniname += EXFAT_FILE_NAME_LEN;
+ }
+
++ /* Mark excess old entries as deleted (in-place shrink) */
++ for (i = num_entries + num_extra; i < old_num; i++) {
++ ep = exfat_get_dentry_cached(es, i);
++ exfat_set_entry_type(ep, TYPE_DELETED);
++ }
++
+ exfat_update_dir_chksum(es);
+ }
+
+ void exfat_remove_entries(struct inode *inode, struct exfat_entry_set_cache *es,
+- int order)
++ int order, bool free_benign)
+ {
+ int i;
+ struct exfat_dentry *ep;
+@@ -513,7 +552,7 @@ void exfat_remove_entries(struct inode *inode, struct exfat_entry_set_cache *es,
+ for (i = order; i < es->num_entries; i++) {
+ ep = exfat_get_dentry_cached(es, i);
+
+- if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC)
++ if (free_benign && (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC))
+ exfat_free_benign_secondary_clusters(inode, ep);
+
+ exfat_set_entry_type(ep, TYPE_DELETED);
+diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
+index 38210fb6901c09..9a85270f8493f9 100644
+--- a/fs/exfat/exfat_fs.h
++++ b/fs/exfat/exfat_fs.h
+@@ -496,9 +496,10 @@ void exfat_init_dir_entry(struct exfat_entry_set_cache *es,
+ unsigned int type, unsigned int start_clu,
+ unsigned long long size, struct timespec64 *ts);
+ void exfat_init_ext_entry(struct exfat_entry_set_cache *es, int num_entries,
+- struct exfat_uni_name *p_uniname);
++ struct exfat_uni_name *p_uniname,
++ struct exfat_entry_set_cache *old_es, int num_extra);
+ void exfat_remove_entries(struct inode *inode, struct exfat_entry_set_cache *es,
+- int order);
++ int order, bool free_benign);
+ void exfat_update_dir_chksum(struct exfat_entry_set_cache *es);
+ int exfat_calc_num_entries(struct exfat_uni_name *p_uniname);
+ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
+diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c
+index dfe957493d49ee..6b544df0a03a68 100644
+--- a/fs/exfat/namei.c
++++ b/fs/exfat/namei.c
+@@ -509,7 +509,7 @@ static int exfat_add_entry(struct inode *inode, const char *path,
+ * the first cluster is not determined yet. (0)
+ */
+ exfat_init_dir_entry(&es, type, start_clu, clu_size, &ts);
+- exfat_init_ext_entry(&es, num_entries, &uniname);
++ exfat_init_ext_entry(&es, num_entries, &uniname, NULL, 0);
+
+ ret = exfat_put_dentry_set(&es, IS_DIRSYNC(inode));
+ if (ret)
+@@ -820,7 +820,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
+ exfat_set_volume_dirty(sb);
+
+ /* update the directory entry */
+- exfat_remove_entries(inode, &es, ES_IDX_FILE);
++ exfat_remove_entries(inode, &es, ES_IDX_FILE, true);
+
+ err = exfat_put_dentry_set(&es, IS_DIRSYNC(inode));
+ if (err)
+@@ -981,7 +981,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
+
+ exfat_set_volume_dirty(sb);
+
+- exfat_remove_entries(inode, &es, ES_IDX_FILE);
++ exfat_remove_entries(inode, &es, ES_IDX_FILE, true);
+
+ err = exfat_put_dentry_set(&es, IS_DIRSYNC(dir));
+ if (err)
+@@ -1008,6 +1008,23 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
+ return err;
+ }
+
++/*
++ * Count benign secondary entries beyond the filename entries.
++ * Returns the count, or -EIO if the entry set is inconsistent.
++ */
++static int exfat_count_extra_entries(struct exfat_entry_set_cache *es)
++{
++ struct exfat_dentry *stream;
++ unsigned int name_entries;
++ int extra;
++
++ stream = exfat_get_dentry_cached(es, ES_IDX_STREAM);
++ name_entries = EXFAT_FILENAME_ENTRY_NUM(stream->dentry.stream.name_len);
++ extra = es->num_entries - (ES_IDX_FIRST_FILENAME + name_entries);
++
++ return extra >= 0 ? extra : -EIO;
++}
++
+ static int exfat_rename_file(struct inode *parent_inode,
+ struct exfat_uni_name *p_uniname, struct exfat_inode_info *ei)
+ {
+@@ -1016,6 +1033,7 @@ static int exfat_rename_file(struct inode *parent_inode,
+ struct super_block *sb = parent_inode->i_sb;
+ struct exfat_entry_set_cache old_es, new_es;
+ int sync = IS_DIRSYNC(parent_inode);
++ unsigned int num_extra_entries, num_total_entries;
+
+ if (unlikely(exfat_forced_shutdown(sb)))
+ return -EIO;
+@@ -1025,19 +1043,23 @@ static int exfat_rename_file(struct inode *parent_inode,
+ return num_new_entries;
+
+ ret = exfat_get_dentry_set_by_ei(&old_es, sb, ei);
+- if (ret) {
+- ret = -EIO;
+- return ret;
+- }
++ if (ret)
++ return -EIO;
+
+ epold = exfat_get_dentry_cached(&old_es, ES_IDX_FILE);
+
+- if (old_es.num_entries < num_new_entries) {
++ ret = exfat_count_extra_entries(&old_es);
++ if (ret < 0)
++ goto put_old_es;
++ num_extra_entries = ret;
++ num_total_entries = num_new_entries + num_extra_entries;
++
++ if (old_es.num_entries < num_total_entries) {
+ int newentry;
+ struct exfat_chain dir;
+
+ newentry = exfat_find_empty_entry(parent_inode, &dir,
+- num_new_entries, &new_es);
++ num_total_entries, &new_es);
+ if (newentry < 0) {
+ ret = newentry; /* -EIO or -ENOSPC */
+ goto put_old_es;
+@@ -1054,13 +1076,23 @@ static int exfat_rename_file(struct inode *parent_inode,
+ epnew = exfat_get_dentry_cached(&new_es, ES_IDX_STREAM);
+ *epnew = *epold;
+
+- exfat_init_ext_entry(&new_es, num_new_entries, p_uniname);
++ exfat_init_ext_entry(&new_es, num_new_entries, p_uniname,
++ &old_es, num_extra_entries);
+
+ ret = exfat_put_dentry_set(&new_es, sync);
+- if (ret)
++ if (ret) {
++ /* Best-effort delete to avoid duplicate entries */
++ if (!exfat_get_dentry_set(&new_es, sb,
++ &dir, newentry,
++ ES_ALL_ENTRIES)) {
++ exfat_remove_entries(parent_inode, &new_es,
++ ES_IDX_FILE, false);
++ exfat_put_dentry_set(&new_es, false);
++ }
+ goto put_old_es;
++ }
+
+- exfat_remove_entries(parent_inode, &old_es, ES_IDX_FILE);
++ exfat_remove_entries(parent_inode, &old_es, ES_IDX_FILE, false);
+ ei->dir = dir;
+ ei->entry = newentry;
+ } else {
+@@ -1069,8 +1101,8 @@ static int exfat_rename_file(struct inode *parent_inode,
+ ei->attr |= EXFAT_ATTR_ARCHIVE;
+ }
+
+- exfat_remove_entries(parent_inode, &old_es, ES_IDX_FIRST_FILENAME + 1);
+- exfat_init_ext_entry(&old_es, num_new_entries, p_uniname);
++ exfat_init_ext_entry(&old_es, num_new_entries, p_uniname,
++ &old_es, num_extra_entries);
+ }
+ return exfat_put_dentry_set(&old_es, sync);
+
+@@ -1086,6 +1118,7 @@ static int exfat_move_file(struct inode *parent_inode,
+ struct exfat_dentry *epmov, *epnew;
+ struct exfat_entry_set_cache mov_es, new_es;
+ struct exfat_chain newdir;
++ unsigned int num_extra_entries, num_total_entries;
+
+ num_new_entries = exfat_calc_num_entries(p_uniname);
+ if (num_new_entries < 0)
+@@ -1095,8 +1128,14 @@ static int exfat_move_file(struct inode *parent_inode,
+ if (ret)
+ return -EIO;
+
++ ret = exfat_count_extra_entries(&mov_es);
++ if (ret < 0)
++ goto put_mov_es;
++ num_extra_entries = ret;
++ num_total_entries = num_new_entries + num_extra_entries;
++
+ newentry = exfat_find_empty_entry(parent_inode, &newdir,
+- num_new_entries, &new_es);
++ num_total_entries, &new_es);
+ if (newentry < 0) {
+ ret = newentry; /* -EIO or -ENOSPC */
+ goto put_mov_es;
+@@ -1114,21 +1153,31 @@ static int exfat_move_file(struct inode *parent_inode,
+ epnew = exfat_get_dentry_cached(&new_es, ES_IDX_STREAM);
+ *epnew = *epmov;
+
+- exfat_init_ext_entry(&new_es, num_new_entries, p_uniname);
+- exfat_remove_entries(parent_inode, &mov_es, ES_IDX_FILE);
++ exfat_init_ext_entry(&new_es, num_new_entries, p_uniname,
++ &mov_es, num_extra_entries);
++
++ exfat_remove_entries(parent_inode, &mov_es, ES_IDX_FILE, false);
+
+ ei->dir = newdir;
+ ei->entry = newentry;
+
+ ret = exfat_put_dentry_set(&new_es, IS_DIRSYNC(parent_inode));
+- if (ret)
++ if (ret) {
++ /* Best-effort delete to avoid duplicate entries */
++ if (!exfat_get_dentry_set(&new_es, parent_inode->i_sb,
++ &newdir, newentry,
++ ES_ALL_ENTRIES)) {
++ exfat_remove_entries(parent_inode, &new_es,
++ ES_IDX_FILE, false);
++ exfat_put_dentry_set(&new_es, false);
++ }
+ goto put_mov_es;
++ }
+
+ return exfat_put_dentry_set(&mov_es, IS_DIRSYNC(parent_inode));
+
+ put_mov_es:
+ exfat_put_dentry_set(&mov_es, false);
+-
+ return ret;
+ }
+
+@@ -1202,7 +1251,7 @@ static int __exfat_rename(struct inode *old_parent_inode,
+ goto del_out;
+ }
+
+- exfat_remove_entries(new_inode, &es, ES_IDX_FILE);
++ exfat_remove_entries(new_inode, &es, ES_IDX_FILE, true);
+
+ ret = exfat_put_dentry_set(&es, IS_DIRSYNC(new_inode));
+ if (ret)
+--
+2.53.0
+
--- /dev/null
+From f44c0f3d62cc2559cdb912ca4a326e1430f9ab87 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Apr 2026 08:42:03 +0000
+Subject: iommu/amd: Use maximum Event log buffer size when SNP is enabled on
+ Family 0x19
+
+From: Vasant Hegde <vasant.hegde@amd.com>
+
+[ Upstream commit 58c0ac6125d89bf6ec65a521eaeb52a0e8e20a9f ]
+
+Due to CVE-2023-20585, the Event log buffer must use the maximum supported
+size (512K) on Milan/Genoa (Family 0x19) systems when SNP is enabled,
+to mitigate a potential security vulnerability. All other systems continue to
+use the default Event log buffer size (8K).
+
+Apply the errata fix by making the following changes:
+
+* Introduce new global variable (amd_iommu_evtlog_size) to have event log
+ buffer size. Adjust variable size for family 0x19.
+
+* Since 'iommu_snp_enable()' must be called after the core IOMMU subsystem
+ is initialized, it cannot be moved to the early init stage. The SNP errata
+ must also be applied after the 'iommu_snp_enable()' check. Therefore,
+ 'alloc_event_buffer()' and 'iommu_enable_event_buffer()' are now called
+ in the IOMMU_ENABLED state, after the errata is applied.
+
+* Adjust alloc_event_buffer() and iommu_enable_event_buffer() to handle
+ all IOMMU instances.
+
+* Also rename EVT_* macros to make it more readable.
+
+Link: https://www.amd.com/en/resources/product-security/bulletin/amd-sb-3016.html
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+Cc: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
+Tested-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava@amd.com>
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd/amd_iommu.h | 2 +
+ drivers/iommu/amd/amd_iommu_types.h | 10 ++-
+ drivers/iommu/amd/init.c | 110 +++++++++++++++++++---------
+ drivers/iommu/amd/iommu.c | 2 +-
+ 4 files changed, 86 insertions(+), 38 deletions(-)
+
+diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
+index bf77fdf5529f48..57d7f3faa98c6e 100644
+--- a/drivers/iommu/amd/amd_iommu.h
++++ b/drivers/iommu/amd/amd_iommu.h
+@@ -11,6 +11,8 @@
+
+ #include "amd_iommu_types.h"
+
++extern int amd_iommu_evtlog_size;
++
+ irqreturn_t amd_iommu_int_thread(int irq, void *data);
+ irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data);
+ irqreturn_t amd_iommu_int_thread_pprlog(int irq, void *data);
+diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
+index b0d919cd1a8fb1..bdd6c38ddfec9b 100644
+--- a/drivers/iommu/amd/amd_iommu_types.h
++++ b/drivers/iommu/amd/amd_iommu_types.h
+@@ -15,6 +15,7 @@
+ #include <linux/mutex.h>
+ #include <linux/msi.h>
+ #include <linux/list.h>
++#include <linux/sizes.h>
+ #include <linux/spinlock.h>
+ #include <linux/pci.h>
+ #include <linux/irqreturn.h>
+@@ -136,7 +137,6 @@
+ #define MMIO_STATUS_GALOG_INT_MASK BIT(10)
+
+ /* event logging constants */
+-#define EVENT_ENTRY_SIZE 0x10
+ #define EVENT_TYPE_SHIFT 28
+ #define EVENT_TYPE_MASK 0xf
+ #define EVENT_TYPE_ILL_DEV 0x1
+@@ -249,8 +249,12 @@
+ #define MMIO_CMD_SIZE_512 (0x9ULL << MMIO_CMD_SIZE_SHIFT)
+
+ /* constants for event buffer handling */
+-#define EVT_BUFFER_SIZE 8192 /* 512 entries */
+-#define EVT_LEN_MASK (0x9ULL << 56)
++#define EVTLOG_ENTRY_SIZE 0x10
++#define EVTLOG_SIZE_SHIFT 56
++#define EVTLOG_SIZE_DEF SZ_8K /* 512 entries */
++#define EVTLOG_LEN_MASK_DEF (0x9ULL << EVTLOG_SIZE_SHIFT)
++#define EVTLOG_SIZE_MAX SZ_512K /* 32K entries */
++#define EVTLOG_LEN_MASK_MAX (0xFULL << EVTLOG_SIZE_SHIFT)
+
+ /* Constants for PPR Log handling */
+ #define PPR_LOG_ENTRIES 512
+diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
+index 76efd74124b33c..64964bb5ce0d36 100644
+--- a/drivers/iommu/amd/init.c
++++ b/drivers/iommu/amd/init.c
+@@ -132,6 +132,8 @@ struct ivhd_entry {
+ u8 uid;
+ } __attribute__((packed));
+
++int amd_iommu_evtlog_size = EVTLOG_SIZE_DEF;
++
+ /*
+ * An AMD IOMMU memory definition structure. It defines things like exclusion
+ * ranges for devices and regions that should be unity mapped.
+@@ -867,35 +869,47 @@ void *__init iommu_alloc_4k_pages(struct amd_iommu *iommu, gfp_t gfp,
+ }
+
+ /* allocates the memory where the IOMMU will log its events to */
+-static int __init alloc_event_buffer(struct amd_iommu *iommu)
++static int __init alloc_event_buffer(void)
+ {
+- iommu->evt_buf = iommu_alloc_4k_pages(iommu, GFP_KERNEL,
+- EVT_BUFFER_SIZE);
++ struct amd_iommu *iommu;
+
+- return iommu->evt_buf ? 0 : -ENOMEM;
++ for_each_iommu(iommu) {
++ iommu->evt_buf = iommu_alloc_4k_pages(iommu, GFP_KERNEL,
++ amd_iommu_evtlog_size);
++ if (!iommu->evt_buf)
++ return -ENOMEM;
++ }
++
++ return 0;
+ }
+
+-static void iommu_enable_event_buffer(struct amd_iommu *iommu)
++static void iommu_enable_event_buffer(void)
+ {
++ struct amd_iommu *iommu;
+ u64 entry;
+
+- BUG_ON(iommu->evt_buf == NULL);
++ for_each_iommu(iommu) {
++ BUG_ON(iommu->evt_buf == NULL);
+
+- if (!is_kdump_kernel()) {
+- /*
+- * Event buffer is re-used for kdump kernel and setting
+- * of MMIO register is not required.
+- */
+- entry = iommu_virt_to_phys(iommu->evt_buf) | EVT_LEN_MASK;
+- memcpy_toio(iommu->mmio_base + MMIO_EVT_BUF_OFFSET,
+- &entry, sizeof(entry));
+- }
++ if (!is_kdump_kernel()) {
++ /*
++ * Event buffer is re-used for kdump kernel and setting
++ * of MMIO register is not required.
++ */
++ entry = iommu_virt_to_phys(iommu->evt_buf);
++ entry |= (amd_iommu_evtlog_size == EVTLOG_SIZE_DEF) ?
++ EVTLOG_LEN_MASK_DEF : EVTLOG_LEN_MASK_MAX;
++
++ memcpy_toio(iommu->mmio_base + MMIO_EVT_BUF_OFFSET,
++ &entry, sizeof(entry));
++ }
+
+- /* set head and tail to zero manually */
+- writel(0x00, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
+- writel(0x00, iommu->mmio_base + MMIO_EVT_TAIL_OFFSET);
++ /* set head and tail to zero manually */
++ writel(0x00, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
++ writel(0x00, iommu->mmio_base + MMIO_EVT_TAIL_OFFSET);
+
+- iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
++ iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
++ }
+ }
+
+ /*
+@@ -984,15 +998,20 @@ static int __init alloc_cwwb_sem(struct amd_iommu *iommu)
+ return 0;
+ }
+
+-static int __init remap_event_buffer(struct amd_iommu *iommu)
++static int __init remap_event_buffer(void)
+ {
++ struct amd_iommu *iommu;
+ u64 paddr;
+
+ pr_info_once("Re-using event buffer from the previous kernel\n");
+- paddr = readq(iommu->mmio_base + MMIO_EVT_BUF_OFFSET) & PM_ADDR_MASK;
+- iommu->evt_buf = iommu_memremap(paddr, EVT_BUFFER_SIZE);
++ for_each_iommu(iommu) {
++ paddr = readq(iommu->mmio_base + MMIO_EVT_BUF_OFFSET) & PM_ADDR_MASK;
++ iommu->evt_buf = iommu_memremap(paddr, amd_iommu_evtlog_size);
++ if (!iommu->evt_buf)
++ return -ENOMEM;
++ }
+
+- return iommu->evt_buf ? 0 : -ENOMEM;
++ return 0;
+ }
+
+ static int __init remap_command_buffer(struct amd_iommu *iommu)
+@@ -1044,10 +1063,6 @@ static int __init alloc_iommu_buffers(struct amd_iommu *iommu)
+ ret = remap_command_buffer(iommu);
+ if (ret)
+ return ret;
+-
+- ret = remap_event_buffer(iommu);
+- if (ret)
+- return ret;
+ } else {
+ ret = alloc_cwwb_sem(iommu);
+ if (ret)
+@@ -1056,10 +1071,6 @@ static int __init alloc_iommu_buffers(struct amd_iommu *iommu)
+ ret = alloc_command_buffer(iommu);
+ if (ret)
+ return ret;
+-
+- ret = alloc_event_buffer(iommu);
+- if (ret)
+- return ret;
+ }
+
+ return 0;
+@@ -2884,7 +2895,6 @@ static void early_enable_iommu(struct amd_iommu *iommu)
+ iommu_init_flags(iommu);
+ iommu_set_device_table(iommu);
+ iommu_enable_command_buffer(iommu);
+- iommu_enable_event_buffer(iommu);
+ iommu_set_exclusion_range(iommu);
+ iommu_enable_gt(iommu);
+ iommu_enable_ga(iommu);
+@@ -2948,7 +2958,6 @@ static void early_enable_iommus(void)
+ iommu_disable_event_buffer(iommu);
+ iommu_disable_irtcachedis(iommu);
+ iommu_enable_command_buffer(iommu);
+- iommu_enable_event_buffer(iommu);
+ iommu_enable_ga(iommu);
+ iommu_enable_xt(iommu);
+ iommu_enable_irtcachedis(iommu);
+@@ -3061,6 +3070,7 @@ static void amd_iommu_resume(void)
+ for_each_iommu(iommu)
+ early_enable_iommu(iommu);
+
++ iommu_enable_event_buffer();
+ amd_iommu_enable_interrupts();
+ }
+
+@@ -3387,6 +3397,23 @@ static __init void iommu_snp_enable(void)
+ #endif
+ }
+
++static void amd_iommu_apply_erratum_snp(void)
++{
++#ifdef CONFIG_KVM_AMD_SEV
++ if (!amd_iommu_snp_en)
++ return;
++
++ /* Errata fix for Family 0x19 */
++ if (boot_cpu_data.x86 != 0x19)
++ return;
++
++ /* Set event log buffer size to max */
++ amd_iommu_evtlog_size = EVTLOG_SIZE_MAX;
++ pr_info("Applying erratum: Increase Event log size to 0x%x\n",
++ amd_iommu_evtlog_size);
++#endif
++}
++
+ /****************************************************************************
+ *
+ * AMD IOMMU Initialization State Machine
+@@ -3423,6 +3450,21 @@ static int __init state_next(void)
+ case IOMMU_ENABLED:
+ register_syscore_ops(&amd_iommu_syscore_ops);
+ iommu_snp_enable();
++
++ amd_iommu_apply_erratum_snp();
++
++ /* Allocate/enable event log buffer */
++ if (is_kdump_kernel())
++ ret = remap_event_buffer();
++ else
++ ret = alloc_event_buffer();
++
++ if (ret) {
++ init_state = IOMMU_INIT_ERROR;
++ break;
++ }
++ iommu_enable_event_buffer();
++
+ ret = amd_iommu_init_pci();
+ init_state = ret ? IOMMU_INIT_ERROR : IOMMU_PCI_INIT;
+ break;
+@@ -4025,7 +4067,7 @@ int amd_iommu_snp_disable(void)
+ return 0;
+
+ for_each_iommu(iommu) {
+- ret = iommu_make_shared(iommu->evt_buf, EVT_BUFFER_SIZE);
++ ret = iommu_make_shared(iommu->evt_buf, amd_iommu_evtlog_size);
+ if (ret)
+ return ret;
+
+diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
+index 5fef68797fdab9..c458eec8a5bba8 100644
+--- a/drivers/iommu/amd/iommu.c
++++ b/drivers/iommu/amd/iommu.c
+@@ -992,7 +992,7 @@ static void iommu_poll_events(struct amd_iommu *iommu)
+ iommu_print_event(iommu, iommu->evt_buf + head);
+
+ /* Update head pointer of hardware ring-buffer */
+- head = (head + EVENT_ENTRY_SIZE) % EVT_BUFFER_SIZE;
++ head = (head + EVTLOG_ENTRY_SIZE) % amd_iommu_evtlog_size;
+ writel(head, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
+ }
+
+--
+2.53.0
+
--- /dev/null
+From e7634cef1b1b11e6adf1f8691ef804575af6e8b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 20 Apr 2026 08:42:04 +0000
+Subject: iommu/amd: Use maximum PPR log buffer size when SNP is enabled on
+ Family 0x19
+
+From: Vasant Hegde <vasant.hegde@amd.com>
+
+[ Upstream commit 1f44aab79bac31f459422dfb213e907bb386509c ]
+
+Due to CVE-2023-20585, the PPR log buffer must use the maximum supported
+size (512K) on Genoa (Family 0x19, model >= 0x10) systems when SNP is
+enabled, to mitigate a potential security vulnerability. Note that Family
+0x19 models below 0x10 (Milan) do not support PPR when SNP is enabled.
+Hence the PPR log size increase is only applied for model >= 0x10.
+All other systems continue to use the default PPR log buffer size (8K).
+
+Apply the errata fix by making the following changes:
+
+- Introduce global new variable (amd_iommu_pprlog_size) to have PPR log buffer
+ size. Adjust variable size for Genoa family.
+
+- Extend 'amd_iommu_apply_erratum_snp()' to also set the PPR log buffer
+ size to maximum for Family 0x19 model >= 0x10 when SNP is enabled.
+
+- Rename PPR_* macros to make it more readable.
+
+Link: https://www.amd.com/en/resources/product-security/bulletin/amd-sb-3016.html
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+Cc: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
+Tested-by: Dheeraj Kumar Srivastava <dheerajkumar.srivastava@amd.com>
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iommu/amd/amd_iommu.h | 1 +
+ drivers/iommu/amd/amd_iommu_types.h | 11 ++++++-----
+ drivers/iommu/amd/init.c | 13 ++++++++++++-
+ drivers/iommu/amd/ppr.c | 8 +++++---
+ 4 files changed, 24 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
+index 57d7f3faa98c6e..ef397c5a2c4ab2 100644
+--- a/drivers/iommu/amd/amd_iommu.h
++++ b/drivers/iommu/amd/amd_iommu.h
+@@ -12,6 +12,7 @@
+ #include "amd_iommu_types.h"
+
+ extern int amd_iommu_evtlog_size;
++extern int amd_iommu_pprlog_size;
+
+ irqreturn_t amd_iommu_int_thread(int irq, void *data);
+ irqreturn_t amd_iommu_int_thread_evtlog(int irq, void *data);
+diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
+index bdd6c38ddfec9b..2494b1958117b2 100644
+--- a/drivers/iommu/amd/amd_iommu_types.h
++++ b/drivers/iommu/amd/amd_iommu_types.h
+@@ -257,11 +257,12 @@
+ #define EVTLOG_LEN_MASK_MAX (0xFULL << EVTLOG_SIZE_SHIFT)
+
+ /* Constants for PPR Log handling */
+-#define PPR_LOG_ENTRIES 512
+-#define PPR_LOG_SIZE_SHIFT 56
+-#define PPR_LOG_SIZE_512 (0x9ULL << PPR_LOG_SIZE_SHIFT)
+-#define PPR_ENTRY_SIZE 16
+-#define PPR_LOG_SIZE (PPR_ENTRY_SIZE * PPR_LOG_ENTRIES)
++#define PPRLOG_ENTRY_SIZE 0x10
++#define PPRLOG_SIZE_SHIFT 56
++#define PPRLOG_SIZE_DEF SZ_8K /* 512 entries */
++#define PPRLOG_LEN_MASK_DEF (0x9ULL << PPRLOG_SIZE_SHIFT)
++#define PPRLOG_SIZE_MAX SZ_512K /* 32K entries */
++#define PPRLOG_LEN_MASK_MAX (0xFULL << PPRLOG_SIZE_SHIFT)
+
+ /* PAGE_SERVICE_REQUEST PPR Log Buffer Entry flags */
+ #define PPR_FLAG_EXEC 0x002 /* Execute permission requested */
+diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
+index 64964bb5ce0d36..6e5efc340c83e4 100644
+--- a/drivers/iommu/amd/init.c
++++ b/drivers/iommu/amd/init.c
+@@ -133,6 +133,7 @@ struct ivhd_entry {
+ } __attribute__((packed));
+
+ int amd_iommu_evtlog_size = EVTLOG_SIZE_DEF;
++int amd_iommu_pprlog_size = PPRLOG_SIZE_DEF;
+
+ /*
+ * An AMD IOMMU memory definition structure. It defines things like exclusion
+@@ -3411,6 +3412,16 @@ static void amd_iommu_apply_erratum_snp(void)
+ amd_iommu_evtlog_size = EVTLOG_SIZE_MAX;
+ pr_info("Applying erratum: Increase Event log size to 0x%x\n",
+ amd_iommu_evtlog_size);
++
++ /*
++ * Set PPR log buffer size to max.
++ * (Family 0x19, model < 0x10 doesn't support PPR when SNP is enabled).
++ */
++ if (boot_cpu_data.x86_model >= 0x10) {
++ amd_iommu_pprlog_size = PPRLOG_SIZE_MAX;
++ pr_info("Applying erratum: Increase PPR log size to 0x%x\n",
++ amd_iommu_pprlog_size);
++ }
+ #endif
+ }
+
+@@ -4071,7 +4082,7 @@ int amd_iommu_snp_disable(void)
+ if (ret)
+ return ret;
+
+- ret = iommu_make_shared(iommu->ppr_log, PPR_LOG_SIZE);
++ ret = iommu_make_shared(iommu->ppr_log, amd_iommu_pprlog_size);
+ if (ret)
+ return ret;
+
+diff --git a/drivers/iommu/amd/ppr.c b/drivers/iommu/amd/ppr.c
+index e6767c057d01fa..1f8d2823bea42c 100644
+--- a/drivers/iommu/amd/ppr.c
++++ b/drivers/iommu/amd/ppr.c
+@@ -20,7 +20,7 @@
+ int __init amd_iommu_alloc_ppr_log(struct amd_iommu *iommu)
+ {
+ iommu->ppr_log = iommu_alloc_4k_pages(iommu, GFP_KERNEL | __GFP_ZERO,
+- PPR_LOG_SIZE);
++ amd_iommu_pprlog_size);
+ return iommu->ppr_log ? 0 : -ENOMEM;
+ }
+
+@@ -33,7 +33,9 @@ void amd_iommu_enable_ppr_log(struct amd_iommu *iommu)
+
+ iommu_feature_enable(iommu, CONTROL_PPR_EN);
+
+- entry = iommu_virt_to_phys(iommu->ppr_log) | PPR_LOG_SIZE_512;
++ entry = iommu_virt_to_phys(iommu->ppr_log);
++ entry |= (amd_iommu_pprlog_size == PPRLOG_SIZE_DEF) ?
++ PPRLOG_LEN_MASK_DEF : PPRLOG_LEN_MASK_MAX;
+
+ memcpy_toio(iommu->mmio_base + MMIO_PPR_LOG_OFFSET,
+ &entry, sizeof(entry));
+@@ -201,7 +203,7 @@ void amd_iommu_poll_ppr_log(struct amd_iommu *iommu)
+ raw[0] = raw[1] = 0UL;
+
+ /* Update head pointer of hardware ring-buffer */
+- head = (head + PPR_ENTRY_SIZE) % PPR_LOG_SIZE;
++ head = (head + PPRLOG_ENTRY_SIZE) % amd_iommu_pprlog_size;
+ writel(head, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
+
+ /* Handle PPR entry */
+--
+2.53.0
+
--- /dev/null
+From 2faa78fee2c57bdb841cfbbf997c9dabfd4a778a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Mar 2026 11:58:22 -0400
+Subject: media: uvcvideo: Fix deadlock if uvc_status_stop is called from
+ async_ctrl.work
+
+From: Sean Anderson <sean.anderson@linux.dev>
+
+[ Upstream commit 6d27f92c54ce28cfbd2a8a479a96d6f4a781b7d2 ]
+
+If a UVC camera has an asynchronous control, uvc_status_stop may be
+called from async_ctrl.work:
+
+uvc_ctrl_status_event_work()
+ uvc_ctrl_status_event()
+ uvc_ctrl_clear_handle()
+ uvc_pm_put()
+ uvc_status_put()
+ uvc_status_stop()
+ cancel_work_sync()
+
+This will cause a deadlock, since cancel_work_sync will wait for
+uvc_ctrl_status_event_work to complete before returning.
+
+Fix this by returning early from uvc_status_stop if we are currently in
+the work function. flush_status now remains false until uvc_status_start
+is called again, ensuring that uvc_ctrl_status_event_work won't resubmit
+the URB.
+
+Fixes: a32d9c41bdb8 ("media: uvcvideo: Make power management granular")
+Cc: stable@vger.kernel.org
+Closes: https://lore.kernel.org/all/6733bdfb-3e88-479f-8956-ab09c04c433e@linux.dev/
+Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20260316155823.1855434-1-sean.anderson@linux.dev
+Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
+Tested-by: Ricardo Ribalda <ribalda@chromium.org>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/usb/uvc/uvc_status.c | 28 +++++++++++++++++++---------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c
+index 231cfee8e7c2c4..7de074006c6a96 100644
+--- a/drivers/media/usb/uvc/uvc_status.c
++++ b/drivers/media/usb/uvc/uvc_status.c
+@@ -316,6 +316,16 @@ static int uvc_status_start(struct uvc_device *dev, gfp_t flags)
+ if (!dev->int_urb)
+ return 0;
+
++ /*
++ * If the previous uvc_status_stop() call was from the async work,
++ * the work may still be running. Wait for it to finish before we submit
++ * the urb.
++ */
++ flush_work(&dev->async_ctrl.work);
++
++ /* Clear the flush status if we were previously stopped. */
++ smp_store_release(&dev->flush_status, false);
++
+ return usb_submit_urb(dev->int_urb, flags);
+ }
+
+@@ -336,6 +346,15 @@ static void uvc_status_stop(struct uvc_device *dev)
+ */
+ smp_store_release(&dev->flush_status, true);
+
++ /*
++ * If we are called from the event work function, the URB is guaranteed
++ * to not be in flight as it has completed and has not been resubmitted.
++ * There's no need to cancel the work (which would deadlock), or to kill
++ * the URB.
++ */
++ if (current_work() == &w->work)
++ return;
++
+ /*
+ * Cancel any pending asynchronous work. If any status event was queued,
+ * process it synchronously.
+@@ -354,15 +373,6 @@ static void uvc_status_stop(struct uvc_device *dev)
+ */
+ if (cancel_work_sync(&w->work))
+ uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
+-
+- /*
+- * From this point, there are no events on the queue and the status URB
+- * is dead. No events will be queued until uvc_status_start() is called.
+- * The barrier is needed to make sure that flush_status is visible to
+- * uvc_ctrl_status_event_work() when uvc_status_start() will be called
+- * again.
+- */
+- smp_store_release(&dev->flush_status, false);
+ }
+
+ int uvc_status_resume(struct uvc_device *dev)
+--
+2.53.0
+
--- /dev/null
+From cbb9b65df986529605db80d2fabd47015c6aebe1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 12:47:26 +0800
+Subject: selftests/bpf: Add a test cases for sync_linked_regs regarding zext
+ propagation
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+commit 4a04d13576fd69149b91672b5f1dc62eca272fa5 upstream.
+
+Add multiple test cases for linked register tracking with alu32 ops:
+
+ - Add a test that checks sync_linked_regs() regarding reg->id (the linked
+ target register) for BPF_ADD_CONST32 rather than known_reg->id (the
+ branch register).
+
+ - Add a test case for linked register tracking that exposes the cross-type
+ sync_linked_regs() bug. One register uses alu32 (w7 += 1, BPF_ADD_CONST32)
+ and another uses alu64 (r8 += 2, BPF_ADD_CONST64), both linked to the
+ same base register.
+
+ - Add a test case that exercises regsafe() path pruning when two execution
+ paths reach the same program point with linked registers carrying
+ different ADD_CONST flags (BPF_ADD_CONST32 from alu32 vs BPF_ADD_CONST64
+ from alu64). This particular test passes with and without the fix since
+ the pruning will fail due to different ranges, but it would still be
+ useful to carry this one as a regression test for the unreachable div
+ by zero.
+
+With the fix applied all the tests pass:
+
+ # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_linked_scalars
+ [...]
+ ./test_progs -t verifier_linked_scalars
+ #602/1 verifier_linked_scalars/scalars: find linked scalars:OK
+ #602/2 verifier_linked_scalars/sync_linked_regs_preserves_id:OK
+ #602/3 verifier_linked_scalars/scalars_neg:OK
+ #602/4 verifier_linked_scalars/scalars_neg_sub:OK
+ #602/5 verifier_linked_scalars/scalars_neg_alu32_add:OK
+ #602/6 verifier_linked_scalars/scalars_neg_alu32_sub:OK
+ #602/7 verifier_linked_scalars/scalars_pos:OK
+ #602/8 verifier_linked_scalars/scalars_sub_neg_imm:OK
+ #602/9 verifier_linked_scalars/scalars_double_add:OK
+ #602/10 verifier_linked_scalars/scalars_sync_delta_overflow:OK
+ #602/11 verifier_linked_scalars/scalars_sync_delta_overflow_large_range:OK
+ #602/12 verifier_linked_scalars/scalars_alu32_big_offset:OK
+ #602/13 verifier_linked_scalars/scalars_alu32_basic:OK
+ #602/14 verifier_linked_scalars/scalars_alu32_wrap:OK
+ #602/15 verifier_linked_scalars/scalars_alu32_zext_linked_reg:OK
+ #602/16 verifier_linked_scalars/scalars_alu32_alu64_cross_type:OK
+ #602/17 verifier_linked_scalars/scalars_alu32_alu64_regsafe_pruning:OK
+ #602/18 verifier_linked_scalars/alu32_negative_offset:OK
+ #602/19 verifier_linked_scalars/spurious_precision_marks:OK
+ #602 verifier_linked_scalars:OK
+ Summary: 1/19 PASSED, 0 SKIPPED, 0 FAILED
+
+Co-developed-by: Puranjay Mohan <puranjay@kernel.org>
+Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20260319211507.213816-2-daniel@iogearbox.net
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../bpf/progs/verifier_linked_scalars.c | 108 ++++++++++++++++++
+ 1 file changed, 108 insertions(+)
+
+diff --git a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+index 2ef346c827c25b..87930b5e7b784f 100644
+--- a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
++++ b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+@@ -348,6 +348,114 @@ l0_%=: \
+ : __clobber_all);
+ }
+
++/*
++ * Test that sync_linked_regs() checks reg->id (the linked target register)
++ * for BPF_ADD_CONST32 rather than known_reg->id (the branch register).
++ */
++SEC("socket")
++__success
++__naked void scalars_alu32_zext_linked_reg(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ w6 = w0; /* r6 in [0, 0xFFFFFFFF] */ \
++ r7 = r6; /* linked: same id as r6 */ \
++ w7 += 1; /* alu32: r7.id |= BPF_ADD_CONST32 */ \
++ r8 = 0xFFFFffff ll; \
++ if r6 < r8 goto l0_%=; \
++ /* r6 in [0xFFFFFFFF, 0xFFFFFFFF] */ \
++ /* sync_linked_regs: known_reg=r6, reg=r7 */ \
++ /* CPU: w7 = (u32)(0xFFFFFFFF + 1) = 0, zext -> r7 = 0 */ \
++ /* With fix: r7 64-bit = [0, 0] (zext applied) */ \
++ /* Without fix: r7 64-bit = [0x100000000] (no zext) */ \
++ r7 >>= 32; \
++ if r7 == 0 goto l0_%=; \
++ r0 /= 0; /* unreachable with fix */ \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/*
++ * Test that sync_linked_regs() skips propagation when one register used
++ * alu32 (BPF_ADD_CONST32) and the other used alu64 (BPF_ADD_CONST64).
++ * The delta relationship doesn't hold across different ALU widths.
++ */
++SEC("socket")
++__failure __msg("div by zero")
++__naked void scalars_alu32_alu64_cross_type(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ w6 = w0; /* r6 in [0, 0xFFFFFFFF] */ \
++ r7 = r6; /* linked: same id as r6 */ \
++ w7 += 1; /* alu32: BPF_ADD_CONST32, delta = 1 */ \
++ r8 = r6; /* linked: same id as r6 */ \
++ r8 += 2; /* alu64: BPF_ADD_CONST64, delta = 2 */ \
++ r9 = 0xFFFFffff ll; \
++ if r7 < r9 goto l0_%=; \
++ /* r7 = 0xFFFFFFFF */ \
++ /* sync: known_reg=r7 (ADD_CONST32), reg=r8 (ADD_CONST64) */ \
++ /* Without fix: r8 = zext(0xFFFFFFFF + 1) = 0 */ \
++ /* With fix: r8 stays [2, 0x100000001] (r8 >= 2) */ \
++ if r8 > 0 goto l1_%=; \
++ goto l0_%=; \
++l1_%=: \
++ r0 /= 0; /* div by zero */ \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/*
++ * Test that regsafe() prevents pruning when two paths reach the same program
++ * point with linked registers carrying different ADD_CONST flags (one
++ * BPF_ADD_CONST32 from alu32, another BPF_ADD_CONST64 from alu64).
++ */
++SEC("socket")
++__failure __msg("div by zero")
++__flag(BPF_F_TEST_STATE_FREQ)
++__naked void scalars_alu32_alu64_regsafe_pruning(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ w6 = w0; /* r6 in [0, 0xFFFFFFFF] */ \
++ r7 = r6; /* linked: same id as r6 */ \
++ /* Get another random value for the path branch */ \
++ call %[bpf_get_prandom_u32]; \
++ if r0 > 0 goto l_pathb_%=; \
++ /* Path A: alu32 */ \
++ w7 += 1; /* BPF_ADD_CONST32, delta = 1 */\
++ goto l_merge_%=; \
++l_pathb_%=: \
++ /* Path B: alu64 */ \
++ r7 += 1; /* BPF_ADD_CONST64, delta = 1 */\
++l_merge_%=: \
++ /* Merge point: regsafe() compares path B against cached path A. */ \
++ /* Narrow r6 to trigger sync_linked_regs for r7 */ \
++ r9 = 0xFFFFffff ll; \
++ if r6 < r9 goto l0_%=; \
++ /* r6 = 0xFFFFFFFF */ \
++ /* sync: r7 = 0xFFFFFFFF + 1 = 0x100000000 */ \
++ /* Path A: zext -> r7 = 0 */ \
++ /* Path B: no zext -> r7 = 0x100000000 */ \
++ r7 >>= 32; \
++ if r7 == 0 goto l0_%=; \
++ r0 /= 0; /* div by zero on path B */ \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
+ SEC("socket")
+ __success
+ void alu32_negative_offset(void)
+--
+2.53.0
+
--- /dev/null
+From 0ac64faf1b50975df6b9adbd5433482ad7d27798 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 12:47:24 +0800
+Subject: selftests: bpf: Add test for multiple syncs from linked register
+
+From: Puranjay Mohan <puranjay@kernel.org>
+
+commit 086c99fbe45070d02851427eab5ae26fe7d0f3c0 upstream.
+
+Before the last commit, sync_linked_regs() corrupted the register whose
+bounds are being updated by copying known_reg's id to it. The ids are
+the same in value but known_reg has the BPF_ADD_CONST flag which is
+wrongly copied to reg.
+
+This later causes issues when creating new links to this reg.
+assign_scalar_id_before_mov() sees this BPF_ADD_CONST and gives a new id
+to this register and breaks the old links. This is exposed by the added
+selftest.
+
+Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
+Tested-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20260115151143.1344724-3-puranjay@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../bpf/progs/verifier_linked_scalars.c | 33 +++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+
+diff --git a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+index 8f755d2464cf5e..5f41bbb730a713 100644
+--- a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
++++ b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+@@ -31,4 +31,37 @@ l1: \
+ " ::: __clobber_all);
+ }
+
++/*
++ * Test that sync_linked_regs() preserves register IDs.
++ *
++ * The sync_linked_regs() function copies bounds from known_reg to linked
++ * registers. When doing so, it must preserve each register's original id
++ * to allow subsequent syncs from the same source to work correctly.
++ *
++ */
++SEC("socket")
++__success
++__naked void sync_linked_regs_preserves_id(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ r0 &= 0xff; /* r0 in [0, 255] */ \
++ r1 = r0; /* r0, r1 linked with id 1 */ \
++ r1 += 4; /* r1 has id=1 and off=4 in [4, 259] */ \
++ if r1 < 10 goto l0_%=; \
++ /* r1 in [10, 259], r0 synced to [6, 255] */ \
++ r2 = r0; /* r2 has id=1 and in [6, 255] */ \
++ if r1 < 14 goto l0_%=; \
++ /* r1 in [14, 259], r0 synced to [10, 255] */ \
++ if r0 >= 10 goto l0_%=; \
++ /* Never executed */ \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
+ char _license[] SEC("license") = "GPL";
+--
+2.53.0
+
--- /dev/null
+From 9ce1ac53fc343f67d932b809113759467ea9b8a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 12:47:28 +0800
+Subject: selftests/bpf: Add tests for delta tracking when src_reg == dst_reg
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+commit ed2eecdc0c6613353bc1565e900d2b23237713da upstream.
+
+Extend the verifier_linked_scalars BPF selftest with a rX += rX test
+such that the div-by-zero path is rejected in the fixed case.
+
+ # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_linked_scalars
+ [...]
+ ./test_progs -t verifier_linked_scalars
+ #612/1 verifier_linked_scalars/scalars: find linked scalars:OK
+ #612/2 verifier_linked_scalars/sync_linked_regs_preserves_id:OK
+ #612/3 verifier_linked_scalars/scalars_neg:OK
+ #612/4 verifier_linked_scalars/scalars_neg_sub:OK
+ #612/5 verifier_linked_scalars/scalars_neg_alu32_add:OK
+ #612/6 verifier_linked_scalars/scalars_neg_alu32_sub:OK
+ #612/7 verifier_linked_scalars/scalars_pos:OK
+ #612/8 verifier_linked_scalars/scalars_sub_neg_imm:OK
+ #612/9 verifier_linked_scalars/scalars_double_add:OK
+ #612/10 verifier_linked_scalars/scalars_sync_delta_overflow:OK
+ #612/11 verifier_linked_scalars/scalars_sync_delta_overflow_large_range:OK
+ #612/12 verifier_linked_scalars/scalars_alu32_big_offset:OK
+ #612/13 verifier_linked_scalars/scalars_alu32_basic:OK
+ #612/14 verifier_linked_scalars/scalars_alu32_wrap:OK
+ #612/15 verifier_linked_scalars/scalars_alu32_zext_linked_reg:OK
+ #612/16 verifier_linked_scalars/scalars_alu32_alu64_cross_type:OK
+ #612/17 verifier_linked_scalars/scalars_alu32_alu64_regsafe_pruning:OK
+ #612/18 verifier_linked_scalars/alu32_negative_offset:OK
+ #612/19 verifier_linked_scalars/spurious_precision_marks:OK
+ #612/20 verifier_linked_scalars/scalars_self_add_clears_id:OK
+ #612/21 verifier_linked_scalars/scalars_self_add_alu32_clears_id:OK
+ #612 verifier_linked_scalars:OK
+ Summary: 1/21 PASSED, 0 SKIPPED, 0 FAILED
+
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Link: https://lore.kernel.org/r/20260407192421.508817-3-daniel@iogearbox.net
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+[shung-hsi.yu: missing context from commit 223ffb6a3d05 ("selftests/bpf: add
+reproducer for spurious precision propagation through calls").]
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../bpf/progs/verifier_linked_scalars.c | 57 +++++++++++++++++++
+ 1 file changed, 57 insertions(+)
+
+diff --git a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+index 87930b5e7b784f..8741238b2ebd94 100644
+--- a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
++++ b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+@@ -471,4 +471,61 @@ void alu32_negative_offset(void)
+ __sink(path[0]);
+ }
+
++/*
++ * Test that r += r (self-add, src_reg == dst_reg) clears the scalar ID
++ * so that sync_linked_regs() does not propagate an incorrect delta.
++ */
++SEC("socket")
++__failure
++__msg("div by zero")
++__naked void scalars_self_add_clears_id(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ r6 = r0; /* r6 unknown, id A */ \
++ r7 = r6; /* r7 linked to r6, id A */ \
++ call %[bpf_get_prandom_u32]; \
++ r8 = r0; /* r8 unknown, id B */ \
++ r9 = r8; /* r9 linked to r8, id B */ \
++ if r7 != 1 goto l_exit_%=; \
++ /* r7 == 1; sync propagates: r6 = 1 (known, id A) */ \
++ r6 += r6; /* r6 = 2; should clear id */ \
++ if r7 == r9 goto l_exit_%=; \
++ /* Bug: r6 synced to r7(1)+delta(2)=3; Fix: r6 = 2 */ \
++ if r6 == 3 goto l_exit_%=; \
++ r0 /= 0; \
++l_exit_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/* Same as above but with alu32 such that w6 += w6 also clears id. */
++SEC("socket")
++__failure
++__msg("div by zero")
++__naked void scalars_self_add_alu32_clears_id(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ w6 = w0; \
++ w7 = w6; \
++ call %[bpf_get_prandom_u32]; \
++ w8 = w0; \
++ w9 = w8; \
++ if w7 != 1 goto l_exit_%=; \
++ w6 += w6; \
++ if w7 == w9 goto l_exit_%=; \
++ if w6 == 3 goto l_exit_%=; \
++ r0 /= 0; \
++l_exit_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
+ char _license[] SEC("license") = "GPL";
+--
+2.53.0
+
--- /dev/null
+From e564e04547b2fc4dd3b8b370bf7a4a91bd80460b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 12:47:25 +0800
+Subject: selftests/bpf: Add tests for improved linked register tracking
+
+From: Puranjay Mohan <puranjay@kernel.org>
+
+commit 47fcf4dc0a346dd0b873a679c547d6848bd85a37 upstream.
+
+Add tests for linked register tracking with negative offsets, BPF_SUB,
+and alu32. These test for all edge cases like overflows, etc.
+
+Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
+Acked-by: Eduard Zingerman <eddyz87@gmail.com>
+Link: https://lore.kernel.org/r/20260204151741.2678118-3-puranjay@kernel.org
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../bpf/progs/verifier_linked_scalars.c | 303 +++++++++++++++++-
+ 1 file changed, 301 insertions(+), 2 deletions(-)
+
+diff --git a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+index 5f41bbb730a713..2ef346c827c25b 100644
+--- a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
++++ b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+@@ -1,6 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0
+
+ #include <linux/bpf.h>
++#include <limits.h>
+ #include <bpf/bpf_helpers.h>
+ #include "bpf_misc.h"
+
+@@ -18,9 +19,9 @@ __naked void scalars(void)
+ r4 = r1; \
+ w2 += 0x7FFFFFFF; \
+ w4 += 0; \
+- if r2 == 0 goto l1; \
++ if r2 == 0 goto l0_%=; \
+ exit; \
+-l1: \
++l0_%=: \
+ r4 >>= 63; \
+ r3 = 1; \
+ r3 -= r4; \
+@@ -64,4 +65,302 @@ l0_%=: \
+ : __clobber_all);
+ }
+
++SEC("socket")
++__success
++__naked void scalars_neg(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ r0 &= 0xff; \
++ r1 = r0; \
++ r1 += -4; \
++ if r1 s< 0 goto l0_%=; \
++ if r0 != 0 goto l0_%=; \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/* Same test but using BPF_SUB instead of BPF_ADD with negative immediate */
++SEC("socket")
++__success
++__naked void scalars_neg_sub(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ r0 &= 0xff; \
++ r1 = r0; \
++ r1 -= 4; \
++ if r1 s< 0 goto l0_%=; \
++ if r0 != 0 goto l0_%=; \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/* alu32 with negative offset */
++SEC("socket")
++__success
++__naked void scalars_neg_alu32_add(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ w0 &= 0xff; \
++ w1 = w0; \
++ w1 += -4; \
++ if w1 s< 0 goto l0_%=; \
++ if w0 != 0 goto l0_%=; \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/* alu32 with negative offset using SUB */
++SEC("socket")
++__success
++__naked void scalars_neg_alu32_sub(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ w0 &= 0xff; \
++ w1 = w0; \
++ w1 -= 4; \
++ if w1 s< 0 goto l0_%=; \
++ if w0 != 0 goto l0_%=; \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/* Positive offset: r1 = r0 + 4, then if r1 >= 6, r0 >= 2, so r0 != 0 */
++SEC("socket")
++__success
++__naked void scalars_pos(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ r0 &= 0xff; \
++ r1 = r0; \
++ r1 += 4; \
++ if r1 < 6 goto l0_%=; \
++ if r0 != 0 goto l0_%=; \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/* SUB with negative immediate: r1 -= -4 is equivalent to r1 += 4 */
++SEC("socket")
++__success
++__naked void scalars_sub_neg_imm(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ r0 &= 0xff; \
++ r1 = r0; \
++ r1 -= -4; \
++ if r1 < 6 goto l0_%=; \
++ if r0 != 0 goto l0_%=; \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/* Double ADD clears the ID (can't accumulate offsets) */
++SEC("socket")
++__failure
++__msg("div by zero")
++__naked void scalars_double_add(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ r0 &= 0xff; \
++ r1 = r0; \
++ r1 += 2; \
++ r1 += 2; \
++ if r1 < 6 goto l0_%=; \
++ if r0 != 0 goto l0_%=; \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/*
++ * Test that sync_linked_regs() correctly handles large offset differences.
++ * r1.off = S32_MIN, r2.off = 1, delta = S32_MIN - 1 requires 64-bit math.
++ */
++SEC("socket")
++__success
++__naked void scalars_sync_delta_overflow(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ r0 &= 0xff; \
++ r1 = r0; \
++ r2 = r0; \
++ r1 += %[s32_min]; \
++ r2 += 1; \
++ if r2 s< 100 goto l0_%=; \
++ if r1 s< 0 goto l0_%=; \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32),
++ [s32_min]"i"(INT_MIN)
++ : __clobber_all);
++}
++
++/*
++ * Another large delta case: r1.off = S32_MAX, r2.off = -1.
++ * delta = S32_MAX - (-1) = S32_MAX + 1 requires 64-bit math.
++ */
++SEC("socket")
++__success
++__naked void scalars_sync_delta_overflow_large_range(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ r0 &= 0xff; \
++ r1 = r0; \
++ r2 = r0; \
++ r1 += %[s32_max]; \
++ r2 += -1; \
++ if r2 s< 0 goto l0_%=; \
++ if r1 s>= 0 goto l0_%=; \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32),
++ [s32_max]"i"(INT_MAX)
++ : __clobber_all);
++}
++
++/*
++ * Test linked scalar tracking with alu32 and large positive offset (0x7FFFFFFF).
++ * After w1 += 0x7FFFFFFF, w1 wraps to negative for any r0 >= 1.
++ * If w1 is signed-negative, then r0 >= 1, so r0 != 0.
++ */
++SEC("socket")
++__success
++__naked void scalars_alu32_big_offset(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ w0 &= 0xff; \
++ w1 = w0; \
++ w1 += 0x7FFFFFFF; \
++ if w1 s>= 0 goto l0_%=; \
++ if w0 != 0 goto l0_%=; \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++SEC("socket")
++__failure
++__msg("div by zero")
++__naked void scalars_alu32_basic(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ r1 = r0; \
++ w1 += 1; \
++ if r1 > 10 goto 1f; \
++ r0 >>= 32; \
++ if r0 == 0 goto 1f; \
++ r0 /= 0; \
++1: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/*
++ * Test alu32 linked register tracking with wrapping.
++ * R0 is bounded to [0xffffff00, 0xffffffff] (high 32-bit values)
++ * w1 += 0x100 causes R1 to wrap to [0, 0xff]
++ *
++ * After sync_linked_regs, if bounds are computed correctly:
++ * R0 should be [0x00000000_ffffff00, 0x00000000_ffffff80]
++ * R0 >> 32 == 0, so div by zero is unreachable
++ *
++ * If bounds are computed incorrectly (64-bit underflow):
++ * R0 becomes [0xffffffff_ffffff00, 0xffffffff_ffffff80]
++ * R0 >> 32 == 0xffffffff != 0, so div by zero is reachable
++ */
++SEC("socket")
++__success
++__naked void scalars_alu32_wrap(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ w0 |= 0xffffff00; \
++ r1 = r0; \
++ w1 += 0x100; \
++ if r1 > 0x80 goto l0_%=; \
++ r2 = r0; \
++ r2 >>= 32; \
++ if r2 == 0 goto l0_%=; \
++ r0 /= 0; \
++l0_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++SEC("socket")
++__success
++void alu32_negative_offset(void)
++{
++ volatile char path[5];
++ volatile int offset = bpf_get_prandom_u32();
++ int off = offset;
++
++ if (off >= 5 && off < 10)
++ path[off - 5] = '.';
++
++ /* So compiler doesn't say: error: variable 'path' set but not used */
++ __sink(path[0]);
++}
++
+ char _license[] SEC("license") = "GPL";
+--
+2.53.0
+
--- /dev/null
+From 1ac77f3711f74f800e767647bceba2d40bbf8b41 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 12:47:29 +0800
+Subject: selftests/bpf: Add tests for stale delta leaking through id
+ reassignment
+
+From: Daniel Borkmann <daniel@iogearbox.net>
+
+commit cac16ce1e3786bd98cec0c108e3bc06ed3d3c6a9 upstream.
+
+Extend the verifier_linked_scalars BPF selftest with a stale delta test
+such that the div-by-zero path is rejected in the fixed case.
+
+ # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_linked_scalars
+ [...]
+ ./test_progs -t verifier_linked_scalars
+ #612/1 verifier_linked_scalars/scalars: find linked scalars:OK
+ #612/2 verifier_linked_scalars/sync_linked_regs_preserves_id:OK
+ #612/3 verifier_linked_scalars/scalars_neg:OK
+ #612/4 verifier_linked_scalars/scalars_neg_sub:OK
+ #612/5 verifier_linked_scalars/scalars_neg_alu32_add:OK
+ #612/6 verifier_linked_scalars/scalars_neg_alu32_sub:OK
+ #612/7 verifier_linked_scalars/scalars_pos:OK
+ #612/8 verifier_linked_scalars/scalars_sub_neg_imm:OK
+ #612/9 verifier_linked_scalars/scalars_double_add:OK
+ #612/10 verifier_linked_scalars/scalars_sync_delta_overflow:OK
+ #612/11 verifier_linked_scalars/scalars_sync_delta_overflow_large_range:OK
+ #612/12 verifier_linked_scalars/scalars_alu32_big_offset:OK
+ #612/13 verifier_linked_scalars/scalars_alu32_basic:OK
+ #612/14 verifier_linked_scalars/scalars_alu32_wrap:OK
+ #612/15 verifier_linked_scalars/scalars_alu32_zext_linked_reg:OK
+ #612/16 verifier_linked_scalars/scalars_alu32_alu64_cross_type:OK
+ #612/17 verifier_linked_scalars/scalars_alu32_alu64_regsafe_pruning:OK
+ #612/18 verifier_linked_scalars/alu32_negative_offset:OK
+ #612/19 verifier_linked_scalars/spurious_precision_marks:OK
+ #612/20 verifier_linked_scalars/scalars_self_add_clears_id:OK
+ #612/21 verifier_linked_scalars/scalars_self_add_alu32_clears_id:OK
+ #612/22 verifier_linked_scalars/scalars_stale_delta_from_cleared_id:OK
+ #612/23 verifier_linked_scalars/scalars_stale_delta_from_cleared_id_alu32:OK
+ #612 verifier_linked_scalars:OK
+ Summary: 1/23 PASSED, 0 SKIPPED, 0 FAILED
+
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Link: https://lore.kernel.org/r/20260407192421.508817-4-daniel@iogearbox.net
+Signed-off-by: Alexei Starovoitov <ast@kernel.org>
+Signed-off-by: Shung-Hsi Yu <shung-hsi.yu@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../bpf/progs/verifier_linked_scalars.c | 55 +++++++++++++++++++
+ 1 file changed, 55 insertions(+)
+
+diff --git a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+index 8741238b2ebd94..3b0c300c9cbd80 100644
+--- a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
++++ b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+@@ -528,4 +528,59 @@ l_exit_%=: \
+ : __clobber_all);
+ }
+
++/*
++ * Test that stale delta from a cleared BPF_ADD_CONST does not leak
++ * through assign_scalar_id_before_mov() into a new id, causing
++ * sync_linked_regs() to compute an incorrect offset.
++ */
++SEC("socket")
++__failure
++__msg("div by zero")
++__naked void scalars_stale_delta_from_cleared_id(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ r6 = r0; /* r6 unknown, gets id A */ \
++ r6 += 5; /* id A|ADD_CONST, delta 5 */ \
++ r6 ^= 0; /* id cleared; delta stays 5 */ \
++ r8 = r6; /* new id B, stale delta 5 */ \
++ r8 += 3; /* id B|ADD_CONST, delta 3 */ \
++ r9 = r6; /* id B, stale delta 5 */ \
++ if r9 != 10 goto l_exit_%=; \
++ /* Bug: r8 = 10+(3-5) = 8; Fix: r8 = 10+(3-0) = 13 */ \
++ if r8 == 8 goto l_exit_%=; \
++ r0 /= 0; \
++l_exit_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
++/* Same as above but with alu32. */
++SEC("socket")
++__failure
++__msg("div by zero")
++__naked void scalars_stale_delta_from_cleared_id_alu32(void)
++{
++ asm volatile (" \
++ call %[bpf_get_prandom_u32]; \
++ w6 = w0; \
++ w6 += 5; \
++ w6 ^= 0; \
++ w8 = w6; \
++ w8 += 3; \
++ w9 = w6; \
++ if w9 != 10 goto l_exit_%=; \
++ if w8 == 8 goto l_exit_%=; \
++ r0 /= 0; \
++l_exit_%=: \
++ r0 = 0; \
++ exit; \
++" :
++ : __imm(bpf_get_prandom_u32)
++ : __clobber_all);
++}
++
+ char _license[] SEC("license") = "GPL";
+--
+2.53.0
+
iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch
nvmet-tcp-check-init_failed-before-nvmet_req_uninit-in-digest-error-path.patch
nvmet-tcp-fix-potential-uaf-when-ddgst-mismatch.patch
+crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
+media-uvcvideo-fix-deadlock-if-uvc_status_stop-is-ca.patch
+selftests-bpf-add-test-for-multiple-syncs-from-linke.patch
+selftests-bpf-add-tests-for-improved-linked-register.patch
+selftests-bpf-add-a-test-cases-for-sync_linked_regs-.patch
+bpf-clear-delta-when-clearing-reg-id-for-non-add-sub.patch
+selftests-bpf-add-tests-for-delta-tracking-when-src_.patch
+selftests-bpf-add-tests-for-stale-delta-leaking-thro.patch
+exfat-preserve-benign-secondary-entries-during-renam.patch
+iommu-amd-use-maximum-event-log-buffer-size-when-snp.patch
+iommu-amd-use-maximum-ppr-log-buffer-size-when-snp-i.patch
+af_unix-drop-all-scm-attributes-for-sockmap.patch
--- /dev/null
+From 81baa16a9ae3bcffa75f207ce7359a773a40dded Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 10:07:01 -0700
+Subject: bpf: Prefer dirty packs for eBPF allocations
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit b72e29e0f7ee329d89f86db8700c8ea99b4a370a upstream.
+
+The pack allocator only flushes predictors when reusing a dirty pack for
+cBPF, eBPF allocations never trigger a flush. Currently, eBPF picks the
+first free pack, which could be a clean pack. As an optimization, leaving
+a clean pack for cBPF can avoid flushes.
+
+Prefer dirty packs for eBPF and keep clean packs free for cBPF. This
+mirrors the existing cBPF preference for clean packs: each program kind
+prefers the pack that avoids an extra flush, and falls back to the other
+kind only when no preferred pack has room. eBPF reuse of a dirty pack is
+harmless since eBPF being privileged does not flush.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/core.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index 7dc59570cd25a5..4669a57265ad75 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -950,10 +950,10 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool
+ goto found_free_area;
+ /*
+ * cBPF reuse of a dirty pack triggers a flush, so prefer a
+- * clean pack for cBPF. eBPF never flushes, so pick the first
+- * free pack, dirty or clean.
++ * clean pack for cBPF. eBPF never flushes, so steer it to a
++ * dirty pack and keep clean packs free for cBPF.
+ */
+- if (!was_classic || !pack->arch_flush_needed)
++ if (was_classic ^ pack->arch_flush_needed)
+ goto found_free_area;
+ if (!fallback_pack) {
+ fallback_pack = pack;
+--
+2.53.0
+
--- /dev/null
+From 1781114de228c3d2f9162fa2c95d57c1c942b130 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 10:06:46 -0700
+Subject: bpf: Prefer packs that won't trigger an IBPB flush on allocation
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit a9b1f19a6a673ba06820898d0f1ad02883ea1639 upstream.
+
+Currently BPF pack allocator picks the chunks from the first available
+pack. While this is okay, it naturally leads to more frequent flushes
+when there are multiple packs in the system that weren't used since the
+last flush.
+
+As an optimization prefer allocating the new programs from packs that
+are unused since last flush. When all packs are dirty, allocation forces
+a flush and marks all packs clean.
+
+Below are some future optimizations ideas:
+
+ 1. Currently, the "dirty" tracking is only done at the pack-level.
+ Flush frequency can further be reduced with chunk-level tracking.
+ This requires a new bitmap per-pack to track the dirty state.
+ 2. IBPB flush is done on all CPUs, even if only a single CPU ran the
+ BPF program. On a system with hundreds of CPUs this could be a
+ major bottleneck forcing hundreds of IPIs to deliver the flush.
+ The solution is to track the CPUs where a BPF program ran, and
+ issue IBPB only on those CPUs.
+ 3. Avoid IBPB when flush is already done at other sources (e.g.
+ context switch).
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/core.c | 27 ++++++++++++++++++++++++---
+ 1 file changed, 24 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index a2e5684d623996..7dc59570cd25a5 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -917,8 +917,8 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins
+ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic)
+ {
+ unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size);
+- struct bpf_prog_pack *pack;
+- unsigned long pos;
++ struct bpf_prog_pack *pack, *fallback_pack = NULL;
++ unsigned long pos, fallback_pos = 0;
+ void *ptr = NULL;
+
+ mutex_lock(&pack_mutex);
+@@ -943,8 +943,29 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool
+ list_for_each_entry(pack, &pack_list, list) {
+ pos = bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0,
+ nbits, 0);
+- if (pos < BPF_PROG_CHUNK_COUNT)
++ if (pos >= BPF_PROG_CHUNK_COUNT)
++ continue;
++ /* Flush not enabled, use any pack */
++ if (!static_branch_unlikely(&bpf_pred_flush_enabled))
+ goto found_free_area;
++ /*
++ * cBPF reuse of a dirty pack triggers a flush, so prefer a
++ * clean pack for cBPF. eBPF never flushes, so pick the first
++ * free pack, dirty or clean.
++ */
++ if (!was_classic || !pack->arch_flush_needed)
++ goto found_free_area;
++ if (!fallback_pack) {
++ fallback_pack = pack;
++ fallback_pos = pos;
++ }
++ }
++
++ /* No preferred pack found */
++ if (fallback_pack) {
++ pack = fallback_pack;
++ pos = fallback_pos;
++ goto found_free_area;
+ }
+
+ pack = alloc_new_pack(bpf_fill_ill_insns);
+--
+2.53.0
+
--- /dev/null
+From d087786ab8abdc6fb77574ca92b784a5950de88d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 10:06:16 -0700
+Subject: bpf: Restrict JIT predictor flush to cBPF
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit 0bb99f2cfaae6822d734d69722de30af823efdf3 upstream.
+
+Currently predictor flush on memory reuse is done for all BPF JIT
+allocations, but only cBPF programs can be loaded by an unprivileged user.
+eBPF is privileged by default, and flushing predictors for all CPUs on
+every eBPF reuse penalizes the common case for no security benefit.
+
+eBPF allocations can be frequent on busy systems, only flush predictors
+for cBPF programs. Trampoline and dispatcher allocations also skip the
+flush as they are eBPF-only.
+
+ [pawan: backport dropped "was_classic" hunk for arches that do not
+ support pack allocator]
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/net/bpf_jit_core.c | 3 ++-
+ arch/x86/net/bpf_jit_comp.c | 3 ++-
+ include/linux/filter.h | 5 +++--
+ kernel/bpf/core.c | 13 ++++++++-----
+ kernel/bpf/dispatcher.c | 2 +-
+ 5 files changed, 16 insertions(+), 10 deletions(-)
+
+diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
+index 7b70ccb7fec345..8d8c5eb2e8dacb 100644
+--- a/arch/riscv/net/bpf_jit_core.c
++++ b/arch/riscv/net/bpf_jit_core.c
+@@ -123,7 +123,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+ bpf_jit_binary_pack_alloc(prog_size + extable_size,
+ &jit_data->ro_image, sizeof(u32),
+ &jit_data->header, &jit_data->image,
+- bpf_fill_ill_insns);
++ bpf_fill_ill_insns,
++ bpf_prog_was_classic(prog));
+ if (!jit_data->ro_header) {
+ prog = orig_prog;
+ goto out_offset;
+diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
+index 0be138fbd0a058..8028a5a4ab6457 100644
+--- a/arch/x86/net/bpf_jit_comp.c
++++ b/arch/x86/net/bpf_jit_comp.c
+@@ -2927,7 +2927,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+ /* allocate module memory for x86 insns and extable */
+ header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size,
+ &image, align, &rw_header, &rw_image,
+- jit_fill_hole);
++ jit_fill_hole,
++ bpf_prog_was_classic(prog));
+ if (!header) {
+ prog = orig_prog;
+ goto out_addrs;
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index 72926bc394ad56..f2e351cc543d62 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -1065,7 +1065,7 @@ void bpf_jit_free(struct bpf_prog *fp);
+ struct bpf_binary_header *
+ bpf_jit_binary_pack_hdr(const struct bpf_prog *fp);
+
+-void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns);
++void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic);
+ void bpf_prog_pack_free(struct bpf_binary_header *hdr);
+
+ static inline bool bpf_prog_kallsyms_verify_off(const struct bpf_prog *fp)
+@@ -1079,7 +1079,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **ro_image,
+ unsigned int alignment,
+ struct bpf_binary_header **rw_hdr,
+ u8 **rw_image,
+- bpf_jit_fill_hole_t bpf_fill_ill_insns);
++ bpf_jit_fill_hole_t bpf_fill_ill_insns,
++ bool was_classic);
+ int bpf_jit_binary_pack_finalize(struct bpf_prog *prog,
+ struct bpf_binary_header *ro_header,
+ struct bpf_binary_header *rw_header);
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index 0d8008711629c5..509f1b9c2b2e28 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -911,7 +911,7 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins
+ return pack;
+ }
+
+-void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
++void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic)
+ {
+ unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size);
+ struct bpf_prog_pack *pack;
+@@ -926,7 +926,7 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+ * safe because cBPF programs (the unprivileged attack surface)
+ * are bounded well below a pack size.
+ */
+- if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ if (was_classic && static_branch_unlikely(&bpf_pred_flush_enabled))
+ pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n");
+ size = round_up(size, PAGE_SIZE);
+ ptr = bpf_jit_alloc_exec(size);
+@@ -951,7 +951,9 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+ pos = 0;
+
+ found_free_area:
+- static_call_cond(bpf_arch_pred_flush)();
++ /* Flush only for cBPF as it may contain a crafted gadget */
++ if (static_branch_unlikely(&bpf_pred_flush_enabled) && was_classic)
++ static_call_cond(bpf_arch_pred_flush)();
+ bitmap_set(pack->bitmap, pos, nbits);
+ ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT);
+
+@@ -1111,7 +1113,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr,
+ unsigned int alignment,
+ struct bpf_binary_header **rw_header,
+ u8 **rw_image,
+- bpf_jit_fill_hole_t bpf_fill_ill_insns)
++ bpf_jit_fill_hole_t bpf_fill_ill_insns,
++ bool was_classic)
+ {
+ struct bpf_binary_header *ro_header;
+ u32 size, hole, start;
+@@ -1124,7 +1127,7 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr,
+
+ if (bpf_jit_charge_modmem(size))
+ return NULL;
+- ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns);
++ ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns, was_classic);
+ if (!ro_header) {
+ bpf_jit_uncharge_modmem(size);
+ return NULL;
+diff --git a/kernel/bpf/dispatcher.c b/kernel/bpf/dispatcher.c
+index fa3e9225aedc0a..b3f164e31c6bb4 100644
+--- a/kernel/bpf/dispatcher.c
++++ b/kernel/bpf/dispatcher.c
+@@ -145,7 +145,7 @@ void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from,
+
+ mutex_lock(&d->mutex);
+ if (!d->image) {
+- d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero);
++ d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero, false);
+ if (!d->image)
+ goto out;
+ d->rw_image = bpf_jit_alloc_exec(PAGE_SIZE);
+--
+2.53.0
+
--- /dev/null
+From 7a8ed9a43bd1484265a037867860372ff67b5ce3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 10:06:31 -0700
+Subject: bpf: Skip redundant IBPB in pack allocator
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit a23c1c5396a91680703360d1ee28a44657c503c4 upstream.
+
+bpf_prog_pack_alloc() issues IBPB on all CPUs on every cBPF allocation,
+even when reusing chunks from an existing pack where no new memory was
+touched since the last IBPB.
+
+Since IBPB on all CPUs is heavy, Dave Hansen suggested to track allocation
+since last IBPB, and only issue IBPB at reuse for the chunks that have not
+seen an IBPB since they were last freed.
+
+Track per-pack whether an IBPB is needed via arch_flush_needed. Set it when
+allocating a chunk, reset on IBPB flush. On reuse, conditionally issue the
+flush. Since IBPB invalidates all BTB entries, clear the flag on all packs
+after flushing.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/bpf/core.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index 509f1b9c2b2e28..a2e5684d623996 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -851,6 +851,7 @@ int bpf_jit_add_poke_descriptor(struct bpf_prog *prog,
+ struct bpf_prog_pack {
+ struct list_head list;
+ void *ptr;
++ bool arch_flush_needed;
+ unsigned long bitmap[];
+ };
+
+@@ -906,6 +907,8 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins
+ bitmap_zero(pack->bitmap, BPF_PROG_PACK_SIZE / BPF_PROG_CHUNK_SIZE);
+ list_add_tail(&pack->list, &pack_list);
+
++ if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ pack->arch_flush_needed = true;
+ set_vm_flush_reset_perms(pack->ptr);
+ set_memory_rox((unsigned long)pack->ptr, BPF_PROG_PACK_SIZE / PAGE_SIZE);
+ return pack;
+@@ -952,8 +955,15 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool
+
+ found_free_area:
+ /* Flush only for cBPF as it may contain a crafted gadget */
+- if (static_branch_unlikely(&bpf_pred_flush_enabled) && was_classic)
++ if (static_branch_unlikely(&bpf_pred_flush_enabled) &&
++ pack->arch_flush_needed &&
++ was_classic) {
++ struct bpf_prog_pack *p;
++
+ static_call_cond(bpf_arch_pred_flush)();
++ list_for_each_entry(p, &pack_list, list)
++ p->arch_flush_needed = false;
++ }
+ bitmap_set(pack->bitmap, pos, nbits);
+ ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT);
+
+@@ -991,6 +1001,9 @@ void bpf_prog_pack_free(struct bpf_binary_header *hdr)
+ "bpf_prog_pack bug: missing bpf_arch_text_invalidate?\n");
+
+ bitmap_clear(pack->bitmap, pos, nbits);
++
++ if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ pack->arch_flush_needed = true;
+ if (bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0,
+ BPF_PROG_CHUNK_COUNT, 0) == 0) {
+ list_del(&pack->list);
+--
+2.53.0
+
--- /dev/null
+From a13b06faceb9e9dddd541386228940a7ee1bec4c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 10:05:45 -0700
+Subject: bpf: Support for hardening against JIT spraying
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit 96cce16e26dd02a8678f1e87f88a4b5cdb63b995 upstream.
+
+The BPF JIT allocator packs many small programs into larger executable
+allocations and reuses space within those allocations as programs are
+loaded and freed. When fresh code is written into space that a previous
+program occupied, an indirect jump into the new program can reuse a branch
+prediction left behind by the old one.
+
+Flush the indirect branch predictors before reusing JIT memory so that
+indirect jumps into a newly written program don't reuse predictions from an
+old program that occupied the same space.
+
+Introduce bpf_arch_pred_flush_enabled static key and bpf_arch_pred_flush
+static call for flushing the branch predictors on JIT memory reuse.
+Architectures that need a flush, can update it to a predictor flush
+function. By default, its a NOP and does not emit any CALL.
+
+Allocations larger than a pack are not covered by this flush. That is safe
+because cBPF programs (the unprivileged attack surface) are bounded well
+below a pack size. Issue a warning if this assumption is ever violated
+while the flush is active.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/filter.h | 10 ++++++++++
+ kernel/bpf/core.c | 19 +++++++++++++++++++
+ 2 files changed, 29 insertions(+)
+
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index 30fe140d488882..72926bc394ad56 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -22,6 +22,7 @@
+ #include <linux/vmalloc.h>
+ #include <linux/sockptr.h>
+ #include <crypto/sha1.h>
++#include <linux/static_call.h>
+ #include <linux/u64_stats_sync.h>
+
+ #include <net/sch_generic.h>
+@@ -1041,6 +1042,15 @@ extern long bpf_jit_limit_max;
+
+ typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size);
+
++/*
++ * Flush the indirect branch predictors before reusing JIT memory, so that
++ * indirect jumps into a newly written program don't reuse predictions left
++ * behind by an old program that occupied the same space.
++ */
++void bpf_arch_pred_flush(void);
++DECLARE_STATIC_CALL(bpf_arch_pred_flush, bpf_arch_pred_flush);
++DECLARE_STATIC_KEY_FALSE(bpf_pred_flush_enabled);
++
+ void bpf_jit_fill_hole_with_zero(void *area, unsigned int size);
+
+ struct bpf_binary_header *
+diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
+index d708cf3e6207f9..0d8008711629c5 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -37,6 +37,7 @@
+ #include <linux/nospec.h>
+ #include <linux/bpf_mem_alloc.h>
+ #include <linux/memcontrol.h>
++#include <linux/static_call.h>
+
+ #include <asm/barrier.h>
+ #include <asm/unaligned.h>
+@@ -858,6 +859,15 @@ void bpf_jit_fill_hole_with_zero(void *area, unsigned int size)
+ memset(area, 0, size);
+ }
+
++DEFINE_STATIC_CALL_NULL(bpf_arch_pred_flush, bpf_arch_pred_flush);
++
++/*
++ * Enabled once bpf_arch_pred_flush points at a real flush routine. Lets the
++ * pack allocator test "is a predictor flush wired up at all" with a cheap
++ * static branch instead of repeatedly querying the static call target.
++ */
++DEFINE_STATIC_KEY_FALSE(bpf_pred_flush_enabled);
++
+ #define BPF_PROG_SIZE_TO_NBITS(size) (round_up(size, BPF_PROG_CHUNK_SIZE) / BPF_PROG_CHUNK_SIZE)
+
+ static DEFINE_MUTEX(pack_mutex);
+@@ -910,6 +920,14 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+
+ mutex_lock(&pack_mutex);
+ if (size > BPF_PROG_PACK_SIZE) {
++ /*
++ * Allocations larger than a pack get their own pages, and
++ * predictors are not flushed for such allocation. This is only
++ * safe because cBPF programs (the unprivileged attack surface)
++ * are bounded well below a pack size.
++ */
++ if (static_branch_unlikely(&bpf_pred_flush_enabled))
++ pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n");
+ size = round_up(size, PAGE_SIZE);
+ ptr = bpf_jit_alloc_exec(size);
+ if (ptr) {
+@@ -933,6 +951,7 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns)
+ pos = 0;
+
+ found_free_area:
++ static_call_cond(bpf_arch_pred_flush)();
+ bitmap_set(pack->bitmap, pos, nbits);
+ ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT);
+
+--
+2.53.0
+
--- /dev/null
+From 3a8abfee4a7efe326df871b4c55f1920175c75fb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 19:44:02 -0700
+Subject: crypto: crypto4xx - Remove ahash-related code
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+commit 97855e7f1ccf4917f305baab199edb9f2595ff5b upstream.
+
+The hash implementation in crypto4xx has been disabled since 2009.
+As nobody has tried to fix this remove all the dead code.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/amcc/crypto4xx_alg.c | 106 ---------------------------
+ drivers/crypto/amcc/crypto4xx_core.c | 43 +----------
+ drivers/crypto/amcc/crypto4xx_core.h | 7 --
+ 3 files changed, 1 insertion(+), 155 deletions(-)
+
+diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c
+index ded73224273295..91cecec729f25e 100644
+--- a/drivers/crypto/amcc/crypto4xx_alg.c
++++ b/drivers/crypto/amcc/crypto4xx_alg.c
+@@ -12,9 +12,6 @@
+ #include <linux/interrupt.h>
+ #include <linux/spinlock_types.h>
+ #include <linux/scatterlist.h>
+-#include <linux/crypto.h>
+-#include <linux/hash.h>
+-#include <crypto/internal/hash.h>
+ #include <linux/dma-mapping.h>
+ #include <crypto/algapi.h>
+ #include <crypto/aead.h>
+@@ -616,106 +613,3 @@ int crypto4xx_decrypt_aes_gcm(struct aead_request *req)
+ {
+ return crypto4xx_crypt_aes_gcm(req, true);
+ }
+-
+-/*
+- * HASH SHA1 Functions
+- */
+-static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
+- unsigned int sa_len,
+- unsigned char ha,
+- unsigned char hm)
+-{
+- struct crypto_alg *alg = tfm->__crt_alg;
+- struct crypto4xx_alg *my_alg;
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
+- struct dynamic_sa_hash160 *sa;
+- int rc;
+-
+- my_alg = container_of(__crypto_ahash_alg(alg), struct crypto4xx_alg,
+- alg.u.hash);
+- ctx->dev = my_alg->dev;
+-
+- /* Create SA */
+- if (ctx->sa_in || ctx->sa_out)
+- crypto4xx_free_sa(ctx);
+-
+- rc = crypto4xx_alloc_sa(ctx, sa_len);
+- if (rc)
+- return rc;
+-
+- crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+- sizeof(struct crypto4xx_ctx));
+- sa = (struct dynamic_sa_hash160 *)ctx->sa_in;
+- set_dynamic_sa_command_0(&sa->ctrl, SA_SAVE_HASH, SA_NOT_SAVE_IV,
+- SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
+- SA_NO_HEADER_PROC, ha, SA_CIPHER_ALG_NULL,
+- SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
+- SA_OPCODE_HASH, DIR_INBOUND);
+- set_dynamic_sa_command_1(&sa->ctrl, 0, SA_HASH_MODE_HASH,
+- CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
+- SA_SEQ_MASK_OFF, SA_MC_ENABLE,
+- SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
+- SA_NOT_COPY_HDR);
+- /* Need to zero hash digest in SA */
+- memset(sa->inner_digest, 0, sizeof(sa->inner_digest));
+- memset(sa->outer_digest, 0, sizeof(sa->outer_digest));
+-
+- return 0;
+-}
+-
+-int crypto4xx_hash_init(struct ahash_request *req)
+-{
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- int ds;
+- struct dynamic_sa_ctl *sa;
+-
+- sa = ctx->sa_in;
+- ds = crypto_ahash_digestsize(
+- __crypto_ahash_cast(req->base.tfm));
+- sa->sa_command_0.bf.digest_len = ds >> 2;
+- sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA;
+-
+- return 0;
+-}
+-
+-int crypto4xx_hash_update(struct ahash_request *req)
+-{
+- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- struct scatterlist dst;
+- unsigned int ds = crypto_ahash_digestsize(ahash);
+-
+- sg_init_one(&dst, req->result, ds);
+-
+- return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
+- req->nbytes, NULL, 0, ctx->sa_in,
+- ctx->sa_len, 0, NULL);
+-}
+-
+-int crypto4xx_hash_final(struct ahash_request *req)
+-{
+- return 0;
+-}
+-
+-int crypto4xx_hash_digest(struct ahash_request *req)
+-{
+- struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+- struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+- struct scatterlist dst;
+- unsigned int ds = crypto_ahash_digestsize(ahash);
+-
+- sg_init_one(&dst, req->result, ds);
+-
+- return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
+- req->nbytes, NULL, 0, ctx->sa_in,
+- ctx->sa_len, 0, NULL);
+-}
+-
+-/*
+- * SHA1 Algorithm
+- */
+-int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm)
+-{
+- return crypto4xx_hash_alg_init(tfm, SA_HASH160_LEN, SA_HASH_ALG_SHA1,
+- SA_HASH_MODE_HASH);
+-}
+diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
+index d553f3f1efbeea..e426127a8ac482 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.c
++++ b/drivers/crypto/amcc/crypto4xx_core.c
+@@ -485,18 +485,6 @@ static void crypto4xx_copy_pkt_to_dst(struct crypto4xx_device *dev,
+ }
+ }
+
+-static void crypto4xx_copy_digest_to_dst(void *dst,
+- struct pd_uinfo *pd_uinfo,
+- struct crypto4xx_ctx *ctx)
+-{
+- struct dynamic_sa_ctl *sa = (struct dynamic_sa_ctl *) ctx->sa_in;
+-
+- if (sa->sa_command_0.bf.hash_alg == SA_HASH_ALG_SHA1) {
+- memcpy(dst, pd_uinfo->sr_va->save_digest,
+- SA_HASH_ALG_SHA1_DIGEST_SIZE);
+- }
+-}
+-
+ static void crypto4xx_ret_sg_desc(struct crypto4xx_device *dev,
+ struct pd_uinfo *pd_uinfo)
+ {
+@@ -549,23 +537,6 @@ static void crypto4xx_cipher_done(struct crypto4xx_device *dev,
+ skcipher_request_complete(req, 0);
+ }
+
+-static void crypto4xx_ahash_done(struct crypto4xx_device *dev,
+- struct pd_uinfo *pd_uinfo)
+-{
+- struct crypto4xx_ctx *ctx;
+- struct ahash_request *ahash_req;
+-
+- ahash_req = ahash_request_cast(pd_uinfo->async_req);
+- ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(ahash_req));
+-
+- crypto4xx_copy_digest_to_dst(ahash_req->result, pd_uinfo, ctx);
+- crypto4xx_ret_sg_desc(dev, pd_uinfo);
+-
+- if (pd_uinfo->state & PD_ENTRY_BUSY)
+- ahash_request_complete(ahash_req, -EINPROGRESS);
+- ahash_request_complete(ahash_req, 0);
+-}
+-
+ static void crypto4xx_aead_done(struct crypto4xx_device *dev,
+ struct pd_uinfo *pd_uinfo,
+ struct ce_pd *pd)
+@@ -642,9 +613,6 @@ static void crypto4xx_pd_done(struct crypto4xx_device *dev, u32 idx)
+ case CRYPTO_ALG_TYPE_AEAD:
+ crypto4xx_aead_done(dev, pd_uinfo, pd);
+ break;
+- case CRYPTO_ALG_TYPE_AHASH:
+- crypto4xx_ahash_done(dev, pd_uinfo);
+- break;
+ }
+ }
+
+@@ -915,8 +883,7 @@ int crypto4xx_build_pd(struct crypto_async_request *req,
+ }
+
+ pd->pd_ctl.w = PD_CTL_HOST_READY |
+- ((crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AHASH) ||
+- (crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AEAD) ?
++ ((crypto_tfm_alg_type(req->tfm) == CRYPTO_ALG_TYPE_AEAD) ?
+ PD_CTL_HASH_FINAL : 0);
+ pd->pd_ctl_len.w = 0x00400000 | (assoclen + datalen);
+ pd_uinfo->state = PD_ENTRY_INUSE | (is_busy ? PD_ENTRY_BUSY : 0);
+@@ -1022,10 +989,6 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
+ rc = crypto_register_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_AHASH:
+- rc = crypto_register_ahash(&alg->alg.u.hash);
+- break;
+-
+ case CRYPTO_ALG_TYPE_RNG:
+ rc = crypto_register_rng(&alg->alg.u.rng);
+ break;
+@@ -1051,10 +1014,6 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
+ list_for_each_entry_safe(alg, tmp, &sec_dev->alg_list, entry) {
+ list_del(&alg->entry);
+ switch (alg->alg.type) {
+- case CRYPTO_ALG_TYPE_AHASH:
+- crypto_unregister_ahash(&alg->alg.u.hash);
+- break;
+-
+ case CRYPTO_ALG_TYPE_AEAD:
+ crypto_unregister_aead(&alg->alg.u.aead);
+ break;
+diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
+index 56c10668c0ab0a..0d83cde84cca9a 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.h
++++ b/drivers/crypto/amcc/crypto4xx_core.h
+@@ -16,7 +16,6 @@
+ #include <linux/ratelimit.h>
+ #include <linux/mutex.h>
+ #include <linux/scatterlist.h>
+-#include <crypto/internal/hash.h>
+ #include <crypto/internal/aead.h>
+ #include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+@@ -135,7 +134,6 @@ struct crypto4xx_alg_common {
+ u32 type;
+ union {
+ struct skcipher_alg cipher;
+- struct ahash_alg hash;
+ struct aead_alg aead;
+ struct rng_alg rng;
+ } u;
+@@ -182,11 +180,6 @@ int crypto4xx_encrypt_noiv_block(struct skcipher_request *req);
+ int crypto4xx_decrypt_noiv_block(struct skcipher_request *req);
+ int crypto4xx_rfc3686_encrypt(struct skcipher_request *req);
+ int crypto4xx_rfc3686_decrypt(struct skcipher_request *req);
+-int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm);
+-int crypto4xx_hash_digest(struct ahash_request *req);
+-int crypto4xx_hash_final(struct ahash_request *req);
+-int crypto4xx_hash_update(struct ahash_request *req);
+-int crypto4xx_hash_init(struct ahash_request *req);
+
+ /*
+ * Note: Only use this function to copy items that is word aligned.
+--
+2.53.0
+
--- /dev/null
+From 70b711ee4fafb3c6009f6dd6a219d07764f016aa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 19:44:03 -0700
+Subject: crypto: crypto4xx - Remove insecure and unused rng_alg
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 7811ec9e973d2c9e465083699f0c8240b98cb8c4 upstream.
+
+Remove crypto4xx_rng, as it is insecure and unused:
+
+- It has only a 64-bit security strength, which is highly inadequate.
+ This can be seen by the fact that crypto4xx_hw_init() seeds it with
+ only 64 bits of entropy, and the fact that the original commit
+ mentions that it implements ANSI X9.17 Annex C.
+
+ Another issue was that this driver didn't implement the crypto_rng API
+ correctly, as crypto4xx_prng_generate() didn't return 0 on success.
+
+- No user of this code is known. It's usable only theoretically via the
+ "rng" algorithm type of AF_ALG. But userspace actually just uses the
+ actual Linux RNG (/dev/random etc) instead. And rng_algs don't
+ contribute entropy to the actual Linux RNG either. (This may have
+ been confused with hwrng, which does contribute entropy.)
+
+Fixes: d072bfa48853 ("crypto: crypto4xx - add prng crypto support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Acked-by: Christian Lamparter <chunkeey@gmail.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/amcc/crypto4xx_core.c | 87 -------------------------
+ drivers/crypto/amcc/crypto4xx_core.h | 4 --
+ drivers/crypto/amcc/crypto4xx_reg_def.h | 11 ----
+ 3 files changed, 102 deletions(-)
+
+diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
+index e426127a8ac482..822c1ac2d5dd57 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.c
++++ b/drivers/crypto/amcc/crypto4xx_core.c
+@@ -31,11 +31,9 @@
+ #include <crypto/ctr.h>
+ #include <crypto/gcm.h>
+ #include <crypto/sha1.h>
+-#include <crypto/rng.h>
+ #include <crypto/scatterwalk.h>
+ #include <crypto/skcipher.h>
+ #include <crypto/internal/aead.h>
+-#include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+ #include "crypto4xx_reg_def.h"
+ #include "crypto4xx_core.h"
+@@ -989,10 +987,6 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
+ rc = crypto_register_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_RNG:
+- rc = crypto_register_rng(&alg->alg.u.rng);
+- break;
+-
+ default:
+ rc = crypto_register_skcipher(&alg->alg.u.cipher);
+ break;
+@@ -1018,10 +1012,6 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
+ crypto_unregister_aead(&alg->alg.u.aead);
+ break;
+
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&alg->alg.u.rng);
+- break;
+-
+ default:
+ crypto_unregister_skcipher(&alg->alg.u.cipher);
+ }
+@@ -1080,69 +1070,6 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
+ PPC4XX_TMO_ERR_INT);
+ }
+
+-static int ppc4xx_prng_data_read(struct crypto4xx_device *dev,
+- u8 *data, unsigned int max)
+-{
+- unsigned int i, curr = 0;
+- u32 val[2];
+-
+- do {
+- /* trigger PRN generation */
+- writel(PPC4XX_PRNG_CTRL_AUTO_EN,
+- dev->ce_base + CRYPTO4XX_PRNG_CTRL);
+-
+- for (i = 0; i < 1024; i++) {
+- /* usually 19 iterations are enough */
+- if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) &
+- CRYPTO4XX_PRNG_STAT_BUSY))
+- continue;
+-
+- val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0);
+- val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1);
+- break;
+- }
+- if (i == 1024)
+- return -ETIMEDOUT;
+-
+- if ((max - curr) >= 8) {
+- memcpy(data, &val, 8);
+- data += 8;
+- curr += 8;
+- } else {
+- /* copy only remaining bytes */
+- memcpy(data, &val, max - curr);
+- break;
+- }
+- } while (curr < max);
+-
+- return curr;
+-}
+-
+-static int crypto4xx_prng_generate(struct crypto_rng *tfm,
+- const u8 *src, unsigned int slen,
+- u8 *dstn, unsigned int dlen)
+-{
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+- struct crypto4xx_alg *amcc_alg;
+- struct crypto4xx_device *dev;
+- int ret;
+-
+- amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng);
+- dev = amcc_alg->dev;
+-
+- mutex_lock(&dev->core_dev->rng_lock);
+- ret = ppc4xx_prng_data_read(dev, dstn, dlen);
+- mutex_unlock(&dev->core_dev->rng_lock);
+- return ret;
+-}
+-
+-
+-static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- return 0;
+-}
+-
+ /*
+ * Supported Crypto Algorithms
+ */
+@@ -1312,18 +1239,6 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
+ .cra_module = THIS_MODULE,
+ },
+ } },
+- { .type = CRYPTO_ALG_TYPE_RNG, .u.rng = {
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "crypto4xx_rng",
+- .cra_priority = 300,
+- .cra_ctxsize = 0,
+- .cra_module = THIS_MODULE,
+- },
+- .generate = crypto4xx_prng_generate,
+- .seed = crypto4xx_prng_seed,
+- .seedsize = 0,
+- } },
+ };
+
+ /*
+@@ -1401,7 +1316,6 @@ static int crypto4xx_probe(struct platform_device *ofdev)
+ core_dev->dev->core_dev = core_dev;
+ core_dev->dev->is_revb = is_revb;
+ core_dev->device = dev;
+- mutex_init(&core_dev->rng_lock);
+ spin_lock_init(&core_dev->lock);
+ INIT_LIST_HEAD(&core_dev->dev->alg_list);
+ ratelimit_default_init(&core_dev->dev->aead_ratelimit);
+@@ -1479,7 +1393,6 @@ static int crypto4xx_remove(struct platform_device *ofdev)
+ tasklet_kill(&core_dev->tasklet);
+ /* Un-register with Linux CryptoAPI */
+ crypto4xx_unregister_alg(core_dev->dev);
+- mutex_destroy(&core_dev->rng_lock);
+ /* Free all allocated memory */
+ crypto4xx_stop_all(core_dev);
+
+diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
+index 0d83cde84cca9a..d8224bbe89ca27 100644
+--- a/drivers/crypto/amcc/crypto4xx_core.h
++++ b/drivers/crypto/amcc/crypto4xx_core.h
+@@ -14,10 +14,8 @@
+ #define __CRYPTO4XX_CORE_H__
+
+ #include <linux/ratelimit.h>
+-#include <linux/mutex.h>
+ #include <linux/scatterlist.h>
+ #include <crypto/internal/aead.h>
+-#include <crypto/internal/rng.h>
+ #include <crypto/internal/skcipher.h>
+ #include "crypto4xx_reg_def.h"
+ #include "crypto4xx_sa.h"
+@@ -111,7 +109,6 @@ struct crypto4xx_core_device {
+ u32 irq;
+ struct tasklet_struct tasklet;
+ spinlock_t lock;
+- struct mutex rng_lock;
+ };
+
+ struct crypto4xx_ctx {
+@@ -135,7 +132,6 @@ struct crypto4xx_alg_common {
+ union {
+ struct skcipher_alg cipher;
+ struct aead_alg aead;
+- struct rng_alg rng;
+ } u;
+ };
+
+diff --git a/drivers/crypto/amcc/crypto4xx_reg_def.h b/drivers/crypto/amcc/crypto4xx_reg_def.h
+index 1038061224da66..73d626308a8484 100644
+--- a/drivers/crypto/amcc/crypto4xx_reg_def.h
++++ b/drivers/crypto/amcc/crypto4xx_reg_def.h
+@@ -90,20 +90,9 @@
+ #define CRYPTO4XX_BYTE_ORDER_CFG 0x000600d8
+ #define CRYPTO4XX_ENDIAN_CFG 0x000600d8
+
+-#define CRYPTO4XX_PRNG_STAT 0x00070000
+-#define CRYPTO4XX_PRNG_STAT_BUSY 0x1
+ #define CRYPTO4XX_PRNG_CTRL 0x00070004
+ #define CRYPTO4XX_PRNG_SEED_L 0x00070008
+ #define CRYPTO4XX_PRNG_SEED_H 0x0007000c
+-
+-#define CRYPTO4XX_PRNG_RES_0 0x00070020
+-#define CRYPTO4XX_PRNG_RES_1 0x00070024
+-#define CRYPTO4XX_PRNG_RES_2 0x00070028
+-#define CRYPTO4XX_PRNG_RES_3 0x0007002C
+-
+-#define CRYPTO4XX_PRNG_LFSR_L 0x00070030
+-#define CRYPTO4XX_PRNG_LFSR_H 0x00070034
+-
+ /*
+ * Initialize CRYPTO ENGINE registers, and memory bases.
+ */
+--
+2.53.0
+
--- /dev/null
+From bcff38f085826344f211b89c3fa59bb03f18caba Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:42:54 -0700
+Subject: crypto: hisi-trng - Remove crypto_rng interface
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit 216a7795ec210bdabd5dad42323eee70bbfc8d90 upstream.
+
+drivers/crypto/hisilicon/trng/trng.c exposes the same hardware through
+two completely separate interfaces, crypto_rng and hwrng. However, the
+implementation of this is buggy because it permits generation operations
+from these interfaces to run concurrently with each other, accessing the
+same registers. That is, hisi_trng_generate() synchronizes with itself
+but not with hisi_trng_read(). This results in potential repetition of
+output from the RNG, output of non-random values, etc.
+
+Fortunately, there's actually no point in hardware RNG drivers
+implementing the crypto_rng interface. It's not actually used by
+anything besides the "rng" algorithm type of AF_ALG, which in turn is
+not actually used in practice. Other crypto_rng hardware drivers are
+likewise being phased out, leaving just the hwrng support.
+
+Thus, remove it to simplify the code and avoid conflict (and confusion)
+with the hwrng interface which is the one that actually matters.
+
+Fixes: e4d9d10ef4be ("crypto: hisilicon/trng - add support for PRNG")
+Cc: stable@vger.kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/hisilicon/Kconfig | 1 -
+ drivers/crypto/hisilicon/trng/trng.c | 298 +--------------------------
+ 2 files changed, 2 insertions(+), 297 deletions(-)
+
+diff --git a/drivers/crypto/hisilicon/Kconfig b/drivers/crypto/hisilicon/Kconfig
+index 4137a8bf131f0c..107bfffaead2bd 100644
+--- a/drivers/crypto/hisilicon/Kconfig
++++ b/drivers/crypto/hisilicon/Kconfig
+@@ -79,6 +79,5 @@ config CRYPTO_DEV_HISI_TRNG
+ tristate "Support for HISI TRNG Driver"
+ depends on ARM64 && ACPI
+ select HW_RANDOM
+- select CRYPTO_RNG
+ help
+ Support for HiSilicon TRNG Driver.
+diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c
+index b2d9b5310b784c..6584ed051e0997 100644
+--- a/drivers/crypto/hisilicon/trng/trng.c
++++ b/drivers/crypto/hisilicon/trng/trng.c
+@@ -1,234 +1,27 @@
+ // SPDX-License-Identifier: GPL-2.0
+ /* Copyright (c) 2019 HiSilicon Limited. */
+
+-#include <crypto/internal/rng.h>
+ #include <linux/acpi.h>
+-#include <linux/crypto.h>
+ #include <linux/err.h>
+ #include <linux/hw_random.h>
+ #include <linux/io.h>
+ #include <linux/iopoll.h>
+ #include <linux/kernel.h>
+-#include <linux/list.h>
+ #include <linux/module.h>
+-#include <linux/mutex.h>
+ #include <linux/platform_device.h>
+ #include <linux/random.h>
+
+ #define HISI_TRNG_REG 0x00F0
+ #define HISI_TRNG_BYTES 4
+ #define HISI_TRNG_QUALITY 512
+-#define HISI_TRNG_VERSION 0x01B8
+-#define HISI_TRNG_VER_V1 GENMASK(31, 0)
+ #define SLEEP_US 10
+ #define TIMEOUT_US 10000
+-#define SW_DRBG_NUM_SHIFT 2
+-#define SW_DRBG_KEY_BASE 0x082C
+-#define SW_DRBG_SEED(n) (SW_DRBG_KEY_BASE - ((n) << SW_DRBG_NUM_SHIFT))
+-#define SW_DRBG_SEED_REGS_NUM 12
+-#define SW_DRBG_SEED_SIZE 48
+-#define SW_DRBG_BLOCKS 0x0830
+-#define SW_DRBG_INIT 0x0834
+-#define SW_DRBG_GEN 0x083c
+-#define SW_DRBG_STATUS 0x0840
+-#define SW_DRBG_BLOCKS_NUM 4095
+-#define SW_DRBG_DATA_BASE 0x0850
+-#define SW_DRBG_DATA_NUM 4
+-#define SW_DRBG_DATA(n) (SW_DRBG_DATA_BASE - ((n) << SW_DRBG_NUM_SHIFT))
+-#define SW_DRBG_BYTES 16
+-#define SW_DRBG_ENABLE_SHIFT 12
+-#define SEED_SHIFT_24 24
+-#define SEED_SHIFT_16 16
+-#define SEED_SHIFT_8 8
+-#define SW_MAX_RANDOM_BYTES 65520
+-
+-struct hisi_trng_list {
+- struct mutex lock;
+- struct list_head list;
+- bool is_init;
+-};
+
+ struct hisi_trng {
+ void __iomem *base;
+- struct hisi_trng_list *trng_list;
+- struct list_head list;
+ struct hwrng rng;
+- u32 ver;
+- u32 ctx_num;
+- /* The bytes of the random number generated since the last seeding. */
+- u32 random_bytes;
+- struct mutex lock;
+-};
+-
+-struct hisi_trng_ctx {
+- struct hisi_trng *trng;
+ };
+
+-static atomic_t trng_active_devs;
+-static struct hisi_trng_list trng_devices;
+-static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait);
+-
+-static int hisi_trng_set_seed(struct hisi_trng *trng, const u8 *seed)
+-{
+- u32 val, seed_reg, i;
+- int ret;
+-
+- writel(0x0, trng->base + SW_DRBG_BLOCKS);
+-
+- for (i = 0; i < SW_DRBG_SEED_SIZE;
+- i += SW_DRBG_SEED_SIZE / SW_DRBG_SEED_REGS_NUM) {
+- val = seed[i] << SEED_SHIFT_24;
+- val |= seed[i + 1UL] << SEED_SHIFT_16;
+- val |= seed[i + 2UL] << SEED_SHIFT_8;
+- val |= seed[i + 3UL];
+-
+- seed_reg = (i >> SW_DRBG_NUM_SHIFT) % SW_DRBG_SEED_REGS_NUM;
+- writel(val, trng->base + SW_DRBG_SEED(seed_reg));
+- }
+-
+- writel(SW_DRBG_BLOCKS_NUM | (0x1 << SW_DRBG_ENABLE_SHIFT),
+- trng->base + SW_DRBG_BLOCKS);
+- writel(0x1, trng->base + SW_DRBG_INIT);
+- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
+- val, val & BIT(0), SLEEP_US, TIMEOUT_US);
+- if (ret) {
+- pr_err("failed to init trng(%d)\n", ret);
+- return -EIO;
+- }
+-
+- trng->random_bytes = 0;
+-
+- return 0;
+-}
+-
+-static int hisi_trng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
+- struct hisi_trng *trng = ctx->trng;
+- int ret;
+-
+- if (slen < SW_DRBG_SEED_SIZE) {
+- pr_err("slen(%u) is not matched with trng(%d)\n", slen,
+- SW_DRBG_SEED_SIZE);
+- return -EINVAL;
+- }
+-
+- mutex_lock(&trng->lock);
+- ret = hisi_trng_set_seed(trng, seed);
+- mutex_unlock(&trng->lock);
+-
+- return ret;
+-}
+-
+-static int hisi_trng_reseed(struct hisi_trng *trng)
+-{
+- u8 seed[SW_DRBG_SEED_SIZE];
+- int size;
+-
+- if (!trng->random_bytes)
+- return 0;
+-
+- size = hisi_trng_read(&trng->rng, seed, SW_DRBG_SEED_SIZE, false);
+- if (size != SW_DRBG_SEED_SIZE)
+- return -EIO;
+-
+- return hisi_trng_set_seed(trng, seed);
+-}
+-
+-static int hisi_trng_get_bytes(struct hisi_trng *trng, u8 *dstn, unsigned int dlen)
+-{
+- u32 data[SW_DRBG_DATA_NUM];
+- u32 currsize = 0;
+- u32 val = 0;
+- int ret;
+- u32 i;
+-
+- ret = hisi_trng_reseed(trng);
+- if (ret)
+- return ret;
+-
+- do {
+- ret = readl_relaxed_poll_timeout(trng->base + SW_DRBG_STATUS,
+- val, val & BIT(1), SLEEP_US, TIMEOUT_US);
+- if (ret) {
+- pr_err("failed to generate random number(%d)!\n", ret);
+- break;
+- }
+-
+- for (i = 0; i < SW_DRBG_DATA_NUM; i++)
+- data[i] = readl(trng->base + SW_DRBG_DATA(i));
+-
+- if (dlen - currsize >= SW_DRBG_BYTES) {
+- memcpy(dstn + currsize, data, SW_DRBG_BYTES);
+- currsize += SW_DRBG_BYTES;
+- } else {
+- memcpy(dstn + currsize, data, dlen - currsize);
+- currsize = dlen;
+- }
+-
+- trng->random_bytes += SW_DRBG_BYTES;
+- writel(0x1, trng->base + SW_DRBG_GEN);
+- } while (currsize < dlen);
+-
+- return ret;
+-}
+-
+-static int hisi_trng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dstn, unsigned int dlen)
+-{
+- struct hisi_trng_ctx *ctx = crypto_rng_ctx(tfm);
+- struct hisi_trng *trng = ctx->trng;
+- unsigned int currsize = 0;
+- unsigned int block_size;
+- int ret;
+-
+- if (!dstn || !dlen) {
+- pr_err("output is error, dlen %u!\n", dlen);
+- return -EINVAL;
+- }
+-
+- do {
+- block_size = min_t(unsigned int, dlen - currsize, SW_MAX_RANDOM_BYTES);
+- mutex_lock(&trng->lock);
+- ret = hisi_trng_get_bytes(trng, dstn + currsize, block_size);
+- mutex_unlock(&trng->lock);
+- if (ret)
+- return ret;
+- currsize += block_size;
+- } while (currsize < dlen);
+-
+- return 0;
+-}
+-
+-static int hisi_trng_init(struct crypto_tfm *tfm)
+-{
+- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
+- struct hisi_trng *trng;
+- u32 ctx_num = ~0;
+-
+- mutex_lock(&trng_devices.lock);
+- list_for_each_entry(trng, &trng_devices.list, list) {
+- if (trng->ctx_num < ctx_num) {
+- ctx_num = trng->ctx_num;
+- ctx->trng = trng;
+- }
+- }
+- ctx->trng->ctx_num++;
+- mutex_unlock(&trng_devices.lock);
+-
+- return 0;
+-}
+-
+-static void hisi_trng_exit(struct crypto_tfm *tfm)
+-{
+- struct hisi_trng_ctx *ctx = crypto_tfm_ctx(tfm);
+-
+- mutex_lock(&trng_devices.lock);
+- ctx->trng->ctx_num--;
+- mutex_unlock(&trng_devices.lock);
+-}
+-
+ static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+ {
+ struct hisi_trng *trng;
+@@ -260,42 +53,6 @@ static int hisi_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
+ return currsize;
+ }
+
+-static struct rng_alg hisi_trng_alg = {
+- .generate = hisi_trng_generate,
+- .seed = hisi_trng_seed,
+- .seedsize = SW_DRBG_SEED_SIZE,
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "hisi_stdrng",
+- .cra_priority = 300,
+- .cra_ctxsize = sizeof(struct hisi_trng_ctx),
+- .cra_module = THIS_MODULE,
+- .cra_init = hisi_trng_init,
+- .cra_exit = hisi_trng_exit,
+- },
+-};
+-
+-static void hisi_trng_add_to_list(struct hisi_trng *trng)
+-{
+- mutex_lock(&trng_devices.lock);
+- list_add_tail(&trng->list, &trng_devices.list);
+- mutex_unlock(&trng_devices.lock);
+-}
+-
+-static int hisi_trng_del_from_list(struct hisi_trng *trng)
+-{
+- int ret = -EBUSY;
+-
+- mutex_lock(&trng_devices.lock);
+- if (!trng->ctx_num) {
+- list_del(&trng->list);
+- ret = 0;
+- }
+- mutex_unlock(&trng_devices.lock);
+-
+- return ret;
+-}
+-
+ static int hisi_trng_probe(struct platform_device *pdev)
+ {
+ struct hisi_trng *trng;
+@@ -305,70 +62,20 @@ static int hisi_trng_probe(struct platform_device *pdev)
+ if (!trng)
+ return -ENOMEM;
+
+- platform_set_drvdata(pdev, trng);
+-
+ trng->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(trng->base))
+ return PTR_ERR(trng->base);
+
+- trng->ctx_num = 0;
+- trng->random_bytes = SW_MAX_RANDOM_BYTES;
+- mutex_init(&trng->lock);
+- trng->ver = readl(trng->base + HISI_TRNG_VERSION);
+- if (!trng_devices.is_init) {
+- INIT_LIST_HEAD(&trng_devices.list);
+- mutex_init(&trng_devices.lock);
+- trng_devices.is_init = true;
+- }
+-
+- hisi_trng_add_to_list(trng);
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_inc_return(&trng_active_devs) == 1) {
+- ret = crypto_register_rng(&hisi_trng_alg);
+- if (ret) {
+- dev_err(&pdev->dev,
+- "failed to register crypto(%d)\n", ret);
+- atomic_dec_return(&trng_active_devs);
+- goto err_remove_from_list;
+- }
+- }
+-
+ trng->rng.name = pdev->name;
+ trng->rng.read = hisi_trng_read;
+ trng->rng.quality = HISI_TRNG_QUALITY;
++
+ ret = devm_hwrng_register(&pdev->dev, &trng->rng);
+- if (ret) {
++ if (ret)
+ dev_err(&pdev->dev, "failed to register hwrng: %d!\n", ret);
+- goto err_crypto_unregister;
+- }
+-
+- return ret;
+-
+-err_crypto_unregister:
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_dec_return(&trng_active_devs) == 0)
+- crypto_unregister_rng(&hisi_trng_alg);
+-
+-err_remove_from_list:
+- hisi_trng_del_from_list(trng);
+ return ret;
+ }
+
+-static int hisi_trng_remove(struct platform_device *pdev)
+-{
+- struct hisi_trng *trng = platform_get_drvdata(pdev);
+-
+- /* Wait until the task is finished */
+- while (hisi_trng_del_from_list(trng))
+- ;
+-
+- if (trng->ver != HISI_TRNG_VER_V1 &&
+- atomic_dec_return(&trng_active_devs) == 0)
+- crypto_unregister_rng(&hisi_trng_alg);
+-
+- return 0;
+-}
+-
+ static const struct acpi_device_id hisi_trng_acpi_match[] = {
+ { "HISI02B3", 0 },
+ { }
+@@ -377,7 +84,6 @@ MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi_match);
+
+ static struct platform_driver hisi_trng_driver = {
+ .probe = hisi_trng_probe,
+- .remove = hisi_trng_remove,
+ .driver = {
+ .name = "hisi-trng-v2",
+ .acpi_match_table = ACPI_PTR(hisi_trng_acpi_match),
+--
+2.53.0
+
--- /dev/null
+From 215a56756795604a7b890c43ecf4fafa8c6e3269 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:50:58 -0700
+Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit b2c41fa9dd8fc740c489e060b199165771f268d1 upstream.
+
+Remove sun4i_ss_rng, as it is insecure and unused:
+
+- It has multiple vulnerabilities. sun4i_ss_prng_seed() is missing
+ locking and has a buffer overflow. sun4i_ss_prng_generate() fails to
+ fill the entire buffer with cryptographic random bytes, because it
+ rounds the destination length down and also doesn't actually wait for
+ the hardware to be ready before pulling bytes from it.
+
+- No user of this code is known. It's usable only theoretically via the
+ "rng" algorithm type of AF_ALG. But userspace actually just uses the
+ actual Linux RNG (/dev/random etc) instead. And rng_algs don't
+ contribute entropy to the actual Linux RNG either. (This may have
+ been confused with hwrng, which does contribute entropy.)
+
+The sun4i_ss_prng_seed() buffer overflow was reported by Tianchu Chen
+and discovered by Atuin - Automated Vulnerability Discovery Engine
+
+There's no point in fixing all these vulnerabilities individually when
+this is unused code, so let's just remove it.
+
+Fixes: b8ae5c7387ad ("crypto: sun4i-ss - support the Security System PRNG")
+Cc: stable@vger.kernel.org
+Reported-by: Tianchu Chen <flynnnchen@tencent.com>
+Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/
+Acked-by: Corentin LABBE <clabbe.montjoie@gmail.com>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/configs/sunxi_defconfig | 1 -
+ drivers/crypto/allwinner/Kconfig | 8 ---
+ drivers/crypto/allwinner/sun4i-ss/Makefile | 1 -
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-core.c | 36 ----------
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-prng.c | 69 -------------------
+ drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h | 20 ------
+ 6 files changed, 135 deletions(-)
+ delete mode 100644 drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+
+diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
+index a83d29fed17563..f4b8d8f7dbefbb 100644
+--- a/arch/arm/configs/sunxi_defconfig
++++ b/arch/arm/configs/sunxi_defconfig
+@@ -170,7 +170,6 @@ CONFIG_ROOT_NFS=y
+ CONFIG_NLS_CODEPAGE_437=y
+ CONFIG_NLS_ISO8859_1=y
+ CONFIG_CRYPTO_DEV_SUN4I_SS=y
+-CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG=y
+ CONFIG_CRYPTO_DEV_SUN8I_CE=y
+ CONFIG_CRYPTO_DEV_SUN8I_SS=y
+ CONFIG_DMA_CMA=y
+diff --git a/drivers/crypto/allwinner/Kconfig b/drivers/crypto/allwinner/Kconfig
+index b8e75210a0e315..06ea0e9fe6f22f 100644
+--- a/drivers/crypto/allwinner/Kconfig
++++ b/drivers/crypto/allwinner/Kconfig
+@@ -24,14 +24,6 @@ config CRYPTO_DEV_SUN4I_SS
+ To compile this driver as a module, choose M here: the module
+ will be called sun4i-ss.
+
+-config CRYPTO_DEV_SUN4I_SS_PRNG
+- bool "Support for Allwinner Security System PRNG"
+- depends on CRYPTO_DEV_SUN4I_SS
+- select CRYPTO_RNG
+- help
+- Select this option if you want to provide kernel-side support for
+- the Pseudo-Random Number Generator found in the Security System.
+-
+ config CRYPTO_DEV_SUN4I_SS_DEBUG
+ bool "Enable sun4i-ss stats"
+ depends on CRYPTO_DEV_SUN4I_SS
+diff --git a/drivers/crypto/allwinner/sun4i-ss/Makefile b/drivers/crypto/allwinner/sun4i-ss/Makefile
+index c0a2797d316827..06a9ae81f9f808 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/Makefile
++++ b/drivers/crypto/allwinner/sun4i-ss/Makefile
+@@ -1,4 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sun4i-ss.o
+ sun4i-ss-y += sun4i-ss-core.o sun4i-ss-hash.o sun4i-ss-cipher.o
+-sun4i-ss-$(CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG) += sun4i-ss-prng.o
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+index 3bcfcfc3708426..6678fab422c31b 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+@@ -215,23 +215,6 @@ static struct sun4i_ss_alg_template ss_algs[] = {
+ }
+ }
+ },
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+-{
+- .type = CRYPTO_ALG_TYPE_RNG,
+- .alg.rng = {
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "sun4i_ss_rng",
+- .cra_priority = 300,
+- .cra_ctxsize = 0,
+- .cra_module = THIS_MODULE,
+- },
+- .generate = sun4i_ss_prng_generate,
+- .seed = sun4i_ss_prng_seed,
+- .seedsize = SS_SEED_LEN / BITS_PER_BYTE,
+- }
+-},
+-#endif
+ };
+
+ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
+@@ -249,12 +232,6 @@ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
+ ss_algs[i].stat_req, ss_algs[i].stat_opti, ss_algs[i].stat_fb,
+ ss_algs[i].stat_bytes);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",
+- ss_algs[i].alg.rng.base.cra_driver_name,
+- ss_algs[i].alg.rng.base.cra_name,
+- ss_algs[i].stat_req, ss_algs[i].stat_bytes);
+- break;
+ case CRYPTO_ALG_TYPE_AHASH:
+ seq_printf(seq, "%s %s reqs=%lu\n",
+ ss_algs[i].alg.hash.halg.base.cra_driver_name,
+@@ -473,13 +450,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ goto error_alg;
+ }
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- err = crypto_register_rng(&ss_algs[i].alg.rng);
+- if (err) {
+- dev_err(ss->dev, "Fail to register %s\n",
+- ss_algs[i].alg.rng.base.cra_name);
+- }
+- break;
+ }
+ }
+
+@@ -499,9 +469,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+ error_pm:
+@@ -522,9 +489,6 @@ static int sun4i_ss_remove(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+deleted file mode 100644
+index 491fcb7b81b40b..00000000000000
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
++++ /dev/null
+@@ -1,69 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-#include "sun4i-ss.h"
+-
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- memcpy(algt->ss->seed, seed, slen);
+-
+- return 0;
+-}
+-
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+- int i, err;
+- u32 v;
+- u32 *data = (u32 *)dst;
+- const u32 mode = SS_OP_PRNG | SS_PRNG_CONTINUE | SS_ENABLED;
+- size_t len;
+- struct sun4i_ss_ctx *ss;
+- unsigned int todo = (dlen / 4) * 4;
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- ss = algt->ss;
+-
+- err = pm_runtime_resume_and_get(ss->dev);
+- if (err < 0)
+- return err;
+-
+- if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) {
+- algt->stat_req++;
+- algt->stat_bytes += todo;
+- }
+-
+- spin_lock_bh(&ss->slock);
+-
+- writel(mode, ss->base + SS_CTL);
+-
+- while (todo > 0) {
+- /* write the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++)
+- writel(ss->seed[i], ss->base + SS_KEY0 + i * 4);
+-
+- /* Read the random data */
+- len = min_t(size_t, SS_DATA_LEN / BITS_PER_BYTE, todo);
+- readsl(ss->base + SS_TXFIFO, data, len / 4);
+- data += len / 4;
+- todo -= len;
+-
+- /* Update the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++) {
+- v = readl(ss->base + SS_KEY0 + i * 4);
+- ss->seed[i] = v;
+- }
+- }
+-
+- writel(0, ss->base + SS_CTL);
+- spin_unlock_bh(&ss->slock);
+-
+- pm_runtime_put(ss->dev);
+-
+- return 0;
+-}
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+index 6c5d4aa6453c7f..f7d1c79ac677d8 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+@@ -31,8 +31,6 @@
+ #include <crypto/internal/skcipher.h>
+ #include <crypto/aes.h>
+ #include <crypto/internal/des.h>
+-#include <crypto/internal/rng.h>
+-#include <crypto/rng.h>
+
+ #define SS_CTL 0x00
+ #define SS_KEY0 0x04
+@@ -62,10 +60,6 @@
+
+ /* SS_CTL configuration values */
+
+-/* PRNG generator mode - bit 15 */
+-#define SS_PRNG_ONESHOT (0 << 15)
+-#define SS_PRNG_CONTINUE (1 << 15)
+-
+ /* IV mode for hash */
+ #define SS_IV_ARBITRARY (1 << 14)
+
+@@ -94,14 +88,10 @@
+ #define SS_OP_3DES (2 << 4)
+ #define SS_OP_SHA1 (3 << 4)
+ #define SS_OP_MD5 (4 << 4)
+-#define SS_OP_PRNG (5 << 4)
+
+ /* Data end bit - bit 2 */
+ #define SS_DATA_END (1 << 2)
+
+-/* PRNG start bit - bit 1 */
+-#define SS_PRNG_START (1 << 1)
+-
+ /* SS Enable bit - bit 0 */
+ #define SS_DISABLED (0 << 0)
+ #define SS_ENABLED (1 << 0)
+@@ -128,9 +118,6 @@
+ #define SS_RXFIFO_EMP_INT_ENABLE (1 << 2)
+ #define SS_TXFIFO_AVA_INT_ENABLE (1 << 0)
+
+-#define SS_SEED_LEN 192
+-#define SS_DATA_LEN 160
+-
+ /*
+ * struct ss_variant - Describe SS hardware variant
+ * @sha1_in_be: The SHA1 digest is given by SS in BE, and so need to be inverted.
+@@ -151,9 +138,6 @@ struct sun4i_ss_ctx {
+ char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */
+ char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */
+ spinlock_t slock; /* control the use of the device */
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+- u32 seed[SS_SEED_LEN / BITS_PER_LONG];
+-#endif
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_stats;
+ };
+@@ -164,7 +148,6 @@ struct sun4i_ss_alg_template {
+ union {
+ struct skcipher_alg crypto;
+ struct ahash_alg hash;
+- struct rng_alg rng;
+ } alg;
+ struct sun4i_ss_ctx *ss;
+ unsigned long stat_req;
+@@ -231,6 +214,3 @@ int sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+ int sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen);
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen);
+--
+2.53.0
+
kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the.patch
nvmet-tcp-check-init_failed-before-nvmet_req_uninit-in-digest-error-path.patch
nvmet-tcp-fix-potential-uaf-when-ddgst-mismatch.patch
+crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
+x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch
+crypto-crypto4xx-remove-ahash-related-code.patch
+crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch
+crypto-hisi-trng-remove-crypto_rng-interface.patch
+bpf-support-for-hardening-against-jit-spraying.patch
+x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch
+bpf-restrict-jit-predictor-flush-to-cbpf.patch
+bpf-skip-redundant-ibpb-in-pack-allocator.patch
+bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch
+bpf-prefer-dirty-packs-for-ebpf-allocations.patch
--- /dev/null
+From f2f311f1a6df8f24e94e0279caf6e207b1a2bd9c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 10:06:00 -0700
+Subject: x86/bugs: Enable IBPB flush on BPF JIT allocation
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+commit a3af84b0fa00ead01fcd0e28b5d773ff25990a0d upstream.
+
+Enable hardening against JIT spraying when Spectre-v2 mitigations are in
+use. Specifically, issue an IBPB flush on BPF JIT memory reuse. Skip
+enabling the IBPB flush if the BPF dispatcher is already using a retpoline
+sequence.
+
+This hardening applies only when BPF-JIT is in use. Guard the enabling
+under CONFIG_BPF_JIT so that bugs.c still builds with CONFIG_BPF_JIT=n.
+
+ [ pawan: Use entry_ibpb() instead of write_ibpb(). JIT hardening enable
+ moved to spectre_v2_select_mitigation() because there is no
+ spectre_v2_apply_mitigation()]
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/include/asm/nospec-branch.h | 4 +++
+ arch/x86/kernel/cpu/bugs.c | 50 +++++++++++++++++++++++++---
+ 2 files changed, 49 insertions(+), 5 deletions(-)
+
+diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h
+index fb469ace38393f..c7d019b0ef4aa5 100644
+--- a/arch/x86/include/asm/nospec-branch.h
++++ b/arch/x86/include/asm/nospec-branch.h
+@@ -418,6 +418,10 @@ extern void srso_alias_untrain_ret(void);
+ extern void entry_untrain_ret(void);
+ extern void entry_ibpb(void);
+
++#ifdef CONFIG_BPF_JIT
++extern void bpf_arch_ibpb(void);
++#endif
++
+ #ifdef CONFIG_X86_64
+ extern void clear_bhb_loop(void);
+ #endif
+diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
+index ef1d3a5024ed4b..32a27c19acde57 100644
+--- a/arch/x86/kernel/cpu/bugs.c
++++ b/arch/x86/kernel/cpu/bugs.c
+@@ -16,6 +16,7 @@
+ #include <linux/sched/smt.h>
+ #include <linux/pgtable.h>
+ #include <linux/bpf.h>
++#include <linux/filter.h>
+
+ #include <asm/spec-ctrl.h>
+ #include <asm/cmdline.h>
+@@ -1360,8 +1361,21 @@ static inline const char *spectre_v2_module_string(void)
+ {
+ return spectre_v2_bad_module ? " - vulnerable module loaded" : "";
+ }
++
++/*
++ * The "retpoline sequence" is the "call;mov;ret" sequence that
++ * replaces normal indirect branch instructions. Differentiate
++ * *the* retpoline sequence from the LFENCE-prefixed indirect
++ * branches that simply use the retpoline infrastructure.
++ */
++static inline bool retpoline_seq_enabled(void)
++{
++ return boot_cpu_has(X86_FEATURE_RETPOLINE) && !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE);
++}
++
+ #else
+ static inline const char *spectre_v2_module_string(void) { return ""; }
++static inline bool retpoline_seq_enabled(void) { return false; }
+ #endif
+
+ #define SPECTRE_V2_LFENCE_MSG "WARNING: LFENCE mitigation is not recommended for this CPU, data leaks possible!\n"
+@@ -1835,8 +1849,7 @@ static void __init bhi_select_mitigation(void)
+ return;
+
+ /* Retpoline mitigates against BHI unless the CPU has RRSBA behavior */
+- if (boot_cpu_has(X86_FEATURE_RETPOLINE) &&
+- !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE)) {
++ if (retpoline_seq_enabled()) {
+ spec_ctrl_disable_kernel_rrsba();
+ if (rrsba_disabled)
+ return;
+@@ -1858,6 +1871,27 @@ static void __init bhi_select_mitigation(void)
+ pr_info("Spectre BHI mitigation: SW BHB clearing on syscall\n");
+ }
+
++#ifdef CONFIG_BPF_JIT
++static void __bpf_arch_ibpb(void *unused)
++{
++ entry_ibpb();
++}
++
++void bpf_arch_ibpb(void)
++{
++ on_each_cpu(__bpf_arch_ibpb, NULL, 1);
++}
++
++static bool __init cpu_wants_ibpb_bpf(void)
++{
++ /* A genuine retpoline already neutralizes ring0 indirect predictions */
++ if (retpoline_seq_enabled())
++ return false;
++
++ return boot_cpu_has(X86_FEATURE_IBPB);
++}
++#endif
++
+ static void __init spectre_v2_select_mitigation(void)
+ {
+ enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
+@@ -2041,6 +2075,14 @@ static void __init spectre_v2_select_mitigation(void)
+ pr_info("Enabling Restricted Speculation for firmware calls\n");
+ }
+
++#ifdef CONFIG_BPF_JIT
++ if (cpu_wants_ibpb_bpf()) {
++ static_call_update(bpf_arch_pred_flush, bpf_arch_ibpb);
++ static_branch_enable(&bpf_pred_flush_enabled);
++ pr_info("Enabling IBPB for BPF\n");
++ }
++#endif
++
+ /* Set up IBPB and STIBP depending on the general spectre V2 command */
+ spectre_v2_cmd = cmd;
+ }
+@@ -3210,9 +3252,7 @@ static const char *spectre_bhi_state(void)
+ return "; BHI: BHI_DIS_S";
+ else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP))
+ return "; BHI: SW loop, KVM: SW loop";
+- else if (boot_cpu_has(X86_FEATURE_RETPOLINE) &&
+- !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE) &&
+- rrsba_disabled)
++ else if (retpoline_seq_enabled() && rrsba_disabled)
+ return "; BHI: Retpoline";
+ else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT))
+ return "; BHI: Vulnerable, KVM: SW loop";
+--
+2.53.0
+
--- /dev/null
+From 6d3c6ae33fa2dfec70b734e928545c30bbe726ea Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jul 2026 12:04:30 -0400
+Subject: x86/mm: Fix check/use ordering in switch_mm_irqs_off()
+
+From: Stephen Dolan <sdolan@janestreet.com>
+
+This is a stable-specific fix. There is no single upstream commit to
+cherry-pick; the equivalent mainline fix is commit 83b0177a6c48
+("x86/mm: Fix SMP ordering in switch_mm_irqs_off()"), which is in
+v6.18 but does not apply to these trees because the surrounding code
+was refactored.
+
+The backports of commit fea4e317f9e7 ("x86/mm: Eliminate window where
+TLB flushes may be inadvertently skipped") -- the fix for
+CVE-2025-37964 -- to the 6.1, 6.6 and 6.12 trees ended up with two
+code blocks in the wrong order relative to mainline. The fix depends
+on setting cpu_tlbstate.loaded_mm to LOADED_MM_SWITCHING *before*
+reading tlb_gen, so that a concurrent TLB shootdown either sees
+LOADED_MM_SWITCHING and sends the IPI, or the switching CPU sees the
+updated tlb_gen. In the stable trees the write of LOADED_MM_SWITCHING
+was placed after the tlb_gen read, so the race window fea4e317f9e7 was
+meant to close is still open and CVE-2025-37964 is unfixed there:
+a process can be left running with stale TLB entries, which typically
+manifests as rare, hard-to-bisect memory corruption or segfaults.
+
+This has been confirmed by several independent parties:
+
+ - reproduced on 6.1.y/6.6.y/6.12.y with the test program in [1],
+ and confirmed fixed by this patch
+ - Seth Forshee saw segfaults on 6.12.y within ~30 minutes of running
+ a test workload; with this patch it ran 18 hours cleanly [2]
+ - Greg Thelen reports 6.6.y- and 6.12.y-based test failures fixed by
+ this patch [3]
+
+Dave Hansen acked the patch [4] and has no objection to it going into
+stable [5].
+
+The patch below is against 6.12.y; the identical change applies to
+6.1.y and 6.6.y. (The cpumask_test_cpu()/smp_mb() portion of the
+mainline fix is not needed here because commit 209954cbc7d0
+("x86/mm/tlb: Update mm_cpumask lazily") was never backported to these
+trees.)
+
+[1] https://lore.kernel.org/lkml/CAHDw0oGd0B4=uuv8NGqbUQ_ZVmSheU2bN70e4QhFXWvuAZdt2w@mail.gmail.com/
+[2] https://lore.kernel.org/lkml/aZYWXe739XUJrBld@do-x1carbon/
+[3] https://lore.kernel.org/lkml/CAHH2K0brx9omC9QYyB6Lio3t_1Lf8v=VaFoiaG23UgQ-aec89Q@mail.gmail.com/
+[4] https://lore.kernel.org/lkml/281e8018-5506-4a79-8775-e0de7e58b95f@intel.com/
+[5] https://lore.kernel.org/lkml/86421ee5-5332-46c2-bb48-d40310b818be@intel.com/
+
+Fixes: fea4e317f9e7 ("x86/mm: Eliminate window where TLB flushes may be inadvertently skipped") # 6.1.y/6.6.y/6.12.y backports
+Acked-by: Dave Hansen <dave.hansen@intel.com>
+Tested-by: Seth Forshee <sforshee@kernel.org>
+Tested-by: Eric Hagberg <ehagberg@janestreet.com>
+Signed-off-by: Stephen Dolan <sdolan@janestreet.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/mm/tlb.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
+index 20ce6a1bd6c57d..19e995f58d6321 100644
+--- a/arch/x86/mm/tlb.c
++++ b/arch/x86/mm/tlb.c
+@@ -612,6 +612,14 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
+ */
+ cond_mitigation(tsk);
+
++ /*
++ * Indicate that CR3 is about to change. nmi_uaccess_okay()
++ * and others are sensitive to the window where mm_cpumask(),
++ * CR3 and cpu_tlbstate.loaded_mm are not all in sync.
++ */
++ this_cpu_write(cpu_tlbstate.loaded_mm, LOADED_MM_SWITCHING);
++ barrier();
++
+ /*
+ * Stop remote flushes for the previous mm.
+ * Skip kernel threads; we never send init_mm TLB flushing IPIs,
+@@ -629,14 +637,6 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
+ next_tlb_gen = atomic64_read(&next->context.tlb_gen);
+
+ choose_new_asid(next, next_tlb_gen, &new_asid, &need_flush);
+-
+- /*
+- * Indicate that CR3 is about to change. nmi_uaccess_okay()
+- * and others are sensitive to the window where mm_cpumask(),
+- * CR3 and cpu_tlbstate.loaded_mm are not all in sync.
+- */
+- this_cpu_write(cpu_tlbstate.loaded_mm, LOADED_MM_SWITCHING);
+- barrier();
+ }
+
+ new_lam = mm_lam_cr3_mask(next);
+--
+2.53.0
+
--- /dev/null
+From 2d24231f6f61609f35fd7e0bbbffde0a722729b4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Jul 2026 20:50:58 -0700
+Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+commit b2c41fa9dd8fc740c489e060b199165771f268d1 upstream.
+
+Remove sun4i_ss_rng, as it is insecure and unused:
+
+- It has multiple vulnerabilities. sun4i_ss_prng_seed() is missing
+ locking and has a buffer overflow. sun4i_ss_prng_generate() fails to
+ fill the entire buffer with cryptographic random bytes, because it
+ rounds the destination length down and also doesn't actually wait for
+ the hardware to be ready before pulling bytes from it.
+
+- No user of this code is known. It's usable only theoretically via the
+ "rng" algorithm type of AF_ALG. But userspace actually just uses the
+ actual Linux RNG (/dev/random etc) instead. And rng_algs don't
+ contribute entropy to the actual Linux RNG either. (This may have
+ been confused with hwrng, which does contribute entropy.)
+
+The sun4i_ss_prng_seed() buffer overflow was reported by Tianchu Chen
+and discovered by Atuin - Automated Vulnerability Discovery Engine
+
+There's no point in fixing all these vulnerabilities individually when
+this is unused code, so let's just remove it.
+
+Fixes: b8ae5c7387ad ("crypto: sun4i-ss - support the Security System PRNG")
+Cc: stable@vger.kernel.org
+Reported-by: Tianchu Chen <flynnnchen@tencent.com>
+Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/
+Acked-by: Corentin LABBE <clabbe.montjoie@gmail.com>
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/configs/sunxi_defconfig | 1 -
+ drivers/crypto/allwinner/Kconfig | 8 ---
+ drivers/crypto/allwinner/sun4i-ss/Makefile | 1 -
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-core.c | 36 ----------
+ .../crypto/allwinner/sun4i-ss/sun4i-ss-prng.c | 69 -------------------
+ drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h | 20 ------
+ 6 files changed, 135 deletions(-)
+ delete mode 100644 drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+
+diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
+index a83d29fed17563..f4b8d8f7dbefbb 100644
+--- a/arch/arm/configs/sunxi_defconfig
++++ b/arch/arm/configs/sunxi_defconfig
+@@ -170,7 +170,6 @@ CONFIG_ROOT_NFS=y
+ CONFIG_NLS_CODEPAGE_437=y
+ CONFIG_NLS_ISO8859_1=y
+ CONFIG_CRYPTO_DEV_SUN4I_SS=y
+-CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG=y
+ CONFIG_CRYPTO_DEV_SUN8I_CE=y
+ CONFIG_CRYPTO_DEV_SUN8I_SS=y
+ CONFIG_DMA_CMA=y
+diff --git a/drivers/crypto/allwinner/Kconfig b/drivers/crypto/allwinner/Kconfig
+index 7270e5fbc57387..1048f8e95ba803 100644
+--- a/drivers/crypto/allwinner/Kconfig
++++ b/drivers/crypto/allwinner/Kconfig
+@@ -25,14 +25,6 @@ config CRYPTO_DEV_SUN4I_SS
+ To compile this driver as a module, choose M here: the module
+ will be called sun4i-ss.
+
+-config CRYPTO_DEV_SUN4I_SS_PRNG
+- bool "Support for Allwinner Security System PRNG"
+- depends on CRYPTO_DEV_SUN4I_SS
+- select CRYPTO_RNG
+- help
+- Select this option if you want to provide kernel-side support for
+- the Pseudo-Random Number Generator found in the Security System.
+-
+ config CRYPTO_DEV_SUN4I_SS_DEBUG
+ bool "Enable sun4i-ss stats"
+ depends on CRYPTO_DEV_SUN4I_SS
+diff --git a/drivers/crypto/allwinner/sun4i-ss/Makefile b/drivers/crypto/allwinner/sun4i-ss/Makefile
+index c0a2797d316827..06a9ae81f9f808 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/Makefile
++++ b/drivers/crypto/allwinner/sun4i-ss/Makefile
+@@ -1,4 +1,3 @@
+ # SPDX-License-Identifier: GPL-2.0-only
+ obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sun4i-ss.o
+ sun4i-ss-y += sun4i-ss-core.o sun4i-ss-hash.o sun4i-ss-cipher.o
+-sun4i-ss-$(CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG) += sun4i-ss-prng.o
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+index 58a76e2ba64e25..35ef0930e77f1a 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+@@ -213,23 +213,6 @@ static struct sun4i_ss_alg_template ss_algs[] = {
+ }
+ }
+ },
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+-{
+- .type = CRYPTO_ALG_TYPE_RNG,
+- .alg.rng = {
+- .base = {
+- .cra_name = "stdrng",
+- .cra_driver_name = "sun4i_ss_rng",
+- .cra_priority = 300,
+- .cra_ctxsize = 0,
+- .cra_module = THIS_MODULE,
+- },
+- .generate = sun4i_ss_prng_generate,
+- .seed = sun4i_ss_prng_seed,
+- .seedsize = SS_SEED_LEN / BITS_PER_BYTE,
+- }
+-},
+-#endif
+ };
+
+ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
+@@ -247,12 +230,6 @@ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
+ ss_algs[i].stat_req, ss_algs[i].stat_opti, ss_algs[i].stat_fb,
+ ss_algs[i].stat_bytes);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",
+- ss_algs[i].alg.rng.base.cra_driver_name,
+- ss_algs[i].alg.rng.base.cra_name,
+- ss_algs[i].stat_req, ss_algs[i].stat_bytes);
+- break;
+ case CRYPTO_ALG_TYPE_AHASH:
+ seq_printf(seq, "%s %s reqs=%lu\n",
+ ss_algs[i].alg.hash.halg.base.cra_driver_name,
+@@ -471,13 +448,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ goto error_alg;
+ }
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- err = crypto_register_rng(&ss_algs[i].alg.rng);
+- if (err) {
+- dev_err(ss->dev, "Fail to register %s\n",
+- ss_algs[i].alg.rng.base.cra_name);
+- }
+- break;
+ }
+ }
+
+@@ -497,9 +467,6 @@ static int sun4i_ss_probe(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+ error_pm:
+@@ -520,9 +487,6 @@ static void sun4i_ss_remove(struct platform_device *pdev)
+ case CRYPTO_ALG_TYPE_AHASH:
+ crypto_unregister_ahash(&ss_algs[i].alg.hash);
+ break;
+- case CRYPTO_ALG_TYPE_RNG:
+- crypto_unregister_rng(&ss_algs[i].alg.rng);
+- break;
+ }
+ }
+
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+deleted file mode 100644
+index 491fcb7b81b40b..00000000000000
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
++++ /dev/null
+@@ -1,69 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0-or-later
+-#include "sun4i-ss.h"
+-
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
+- unsigned int slen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- memcpy(algt->ss->seed, seed, slen);
+-
+- return 0;
+-}
+-
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen)
+-{
+- struct sun4i_ss_alg_template *algt;
+- struct rng_alg *alg = crypto_rng_alg(tfm);
+- int i, err;
+- u32 v;
+- u32 *data = (u32 *)dst;
+- const u32 mode = SS_OP_PRNG | SS_PRNG_CONTINUE | SS_ENABLED;
+- size_t len;
+- struct sun4i_ss_ctx *ss;
+- unsigned int todo = (dlen / 4) * 4;
+-
+- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
+- ss = algt->ss;
+-
+- err = pm_runtime_resume_and_get(ss->dev);
+- if (err < 0)
+- return err;
+-
+- if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) {
+- algt->stat_req++;
+- algt->stat_bytes += todo;
+- }
+-
+- spin_lock_bh(&ss->slock);
+-
+- writel(mode, ss->base + SS_CTL);
+-
+- while (todo > 0) {
+- /* write the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++)
+- writel(ss->seed[i], ss->base + SS_KEY0 + i * 4);
+-
+- /* Read the random data */
+- len = min_t(size_t, SS_DATA_LEN / BITS_PER_BYTE, todo);
+- readsl(ss->base + SS_TXFIFO, data, len / 4);
+- data += len / 4;
+- todo -= len;
+-
+- /* Update the seed */
+- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++) {
+- v = readl(ss->base + SS_KEY0 + i * 4);
+- ss->seed[i] = v;
+- }
+- }
+-
+- writel(0, ss->base + SS_CTL);
+- spin_unlock_bh(&ss->slock);
+-
+- pm_runtime_put(ss->dev);
+-
+- return 0;
+-}
+diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+index 6c5d4aa6453c7f..f7d1c79ac677d8 100644
+--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
++++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+@@ -31,8 +31,6 @@
+ #include <crypto/internal/skcipher.h>
+ #include <crypto/aes.h>
+ #include <crypto/internal/des.h>
+-#include <crypto/internal/rng.h>
+-#include <crypto/rng.h>
+
+ #define SS_CTL 0x00
+ #define SS_KEY0 0x04
+@@ -62,10 +60,6 @@
+
+ /* SS_CTL configuration values */
+
+-/* PRNG generator mode - bit 15 */
+-#define SS_PRNG_ONESHOT (0 << 15)
+-#define SS_PRNG_CONTINUE (1 << 15)
+-
+ /* IV mode for hash */
+ #define SS_IV_ARBITRARY (1 << 14)
+
+@@ -94,14 +88,10 @@
+ #define SS_OP_3DES (2 << 4)
+ #define SS_OP_SHA1 (3 << 4)
+ #define SS_OP_MD5 (4 << 4)
+-#define SS_OP_PRNG (5 << 4)
+
+ /* Data end bit - bit 2 */
+ #define SS_DATA_END (1 << 2)
+
+-/* PRNG start bit - bit 1 */
+-#define SS_PRNG_START (1 << 1)
+-
+ /* SS Enable bit - bit 0 */
+ #define SS_DISABLED (0 << 0)
+ #define SS_ENABLED (1 << 0)
+@@ -128,9 +118,6 @@
+ #define SS_RXFIFO_EMP_INT_ENABLE (1 << 2)
+ #define SS_TXFIFO_AVA_INT_ENABLE (1 << 0)
+
+-#define SS_SEED_LEN 192
+-#define SS_DATA_LEN 160
+-
+ /*
+ * struct ss_variant - Describe SS hardware variant
+ * @sha1_in_be: The SHA1 digest is given by SS in BE, and so need to be inverted.
+@@ -151,9 +138,6 @@ struct sun4i_ss_ctx {
+ char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */
+ char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */
+ spinlock_t slock; /* control the use of the device */
+-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
+- u32 seed[SS_SEED_LEN / BITS_PER_LONG];
+-#endif
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_stats;
+ };
+@@ -164,7 +148,6 @@ struct sun4i_ss_alg_template {
+ union {
+ struct skcipher_alg crypto;
+ struct ahash_alg hash;
+- struct rng_alg rng;
+ } alg;
+ struct sun4i_ss_ctx *ss;
+ unsigned long stat_req;
+@@ -231,6 +214,3 @@ int sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+ int sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen);
+-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
+- unsigned int slen, u8 *dst, unsigned int dlen);
+-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen);
+--
+2.53.0
+
--- /dev/null
+From 93098fcdd29190e0707d1273af749c722d83f14e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Mar 2026 11:58:22 -0400
+Subject: media: uvcvideo: Fix deadlock if uvc_status_stop is called from
+ async_ctrl.work
+
+From: Sean Anderson <sean.anderson@linux.dev>
+
+[ Upstream commit 6d27f92c54ce28cfbd2a8a479a96d6f4a781b7d2 ]
+
+If a UVC camera has an asynchronous control, uvc_status_stop may be
+called from async_ctrl.work:
+
+uvc_ctrl_status_event_work()
+ uvc_ctrl_status_event()
+ uvc_ctrl_clear_handle()
+ uvc_pm_put()
+ uvc_status_put()
+ uvc_status_stop()
+ cancel_work_sync()
+
+This will cause a deadlock, since cancel_work_sync will wait for
+uvc_ctrl_status_event_work to complete before returning.
+
+Fix this by returning early from uvc_status_stop if we are currently in
+the work function. flush_status now remains false until uvc_status_start
+is called again, ensuring that uvc_ctrl_status_event_work won't resubmit
+the URB.
+
+Fixes: a32d9c41bdb8 ("media: uvcvideo: Make power management granular")
+Cc: stable@vger.kernel.org
+Closes: https://lore.kernel.org/all/6733bdfb-3e88-479f-8956-ab09c04c433e@linux.dev/
+Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20260316155823.1855434-1-sean.anderson@linux.dev
+Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
+Tested-by: Ricardo Ribalda <ribalda@chromium.org>
+Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
+Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/usb/uvc/uvc_status.c | 28 +++++++++++++++++++---------
+ 1 file changed, 19 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c
+index 65f5356bebb399..b632cf5e3fe9b2 100644
+--- a/drivers/media/usb/uvc/uvc_status.c
++++ b/drivers/media/usb/uvc/uvc_status.c
+@@ -316,6 +316,16 @@ static int uvc_status_start(struct uvc_device *dev, gfp_t flags)
+ if (!dev->int_urb)
+ return 0;
+
++ /*
++ * If the previous uvc_status_stop() call was from the async work,
++ * the work may still be running. Wait for it to finish before we submit
++ * the urb.
++ */
++ flush_work(&dev->async_ctrl.work);
++
++ /* Clear the flush status if we were previously stopped. */
++ smp_store_release(&dev->flush_status, false);
++
+ return usb_submit_urb(dev->int_urb, flags);
+ }
+
+@@ -336,6 +346,15 @@ static void uvc_status_stop(struct uvc_device *dev)
+ */
+ smp_store_release(&dev->flush_status, true);
+
++ /*
++ * If we are called from the event work function, the URB is guaranteed
++ * to not be in flight as it has completed and has not been resubmitted.
++ * There's no need to cancel the work (which would deadlock), or to kill
++ * the URB.
++ */
++ if (current_work() == &w->work)
++ return;
++
+ /*
+ * Cancel any pending asynchronous work. If any status event was queued,
+ * process it synchronously.
+@@ -354,15 +373,6 @@ static void uvc_status_stop(struct uvc_device *dev)
+ */
+ if (cancel_work_sync(&w->work))
+ uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
+-
+- /*
+- * From this point, there are no events on the queue and the status URB
+- * is dead. No events will be queued until uvc_status_start() is called.
+- * The barrier is needed to make sure that flush_status is visible to
+- * uvc_ctrl_status_event_work() when uvc_status_start() will be called
+- * again.
+- */
+- smp_store_release(&dev->flush_status, false);
+ }
+
+ int uvc_status_resume(struct uvc_device *dev)
+--
+2.53.0
+
crypto-algif_skcipher-force-synchronous-processing.patch
iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch
+crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
+media-uvcvideo-fix-deadlock-if-uvc_status_stop-is-ca.patch