]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for all trees master
authorSasha Levin <sashal@kernel.org>
Sun, 19 Jul 2026 15:00:07 +0000 (11:00 -0400)
committerSasha Levin <sashal@kernel.org>
Sun, 19 Jul 2026 15:00:07 +0000 (11:00 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
64 files changed:
queue-5.10/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch [new file with mode: 0644]
queue-5.10/series
queue-5.15/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch [new file with mode: 0644]
queue-5.15/crypto-crypto4xx-remove-ahash-related-code.patch [new file with mode: 0644]
queue-5.15/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch [new file with mode: 0644]
queue-5.15/crypto-hisi-trng-remove-crypto_rng-interface.patch [new file with mode: 0644]
queue-5.15/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch [new file with mode: 0644]
queue-5.15/series
queue-6.1/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch [new file with mode: 0644]
queue-6.1/crypto-crypto4xx-remove-ahash-related-code.patch [new file with mode: 0644]
queue-6.1/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch [new file with mode: 0644]
queue-6.1/crypto-hisi-trng-remove-crypto_rng-interface.patch [new file with mode: 0644]
queue-6.1/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch [new file with mode: 0644]
queue-6.1/series
queue-6.1/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch [new file with mode: 0644]
queue-6.12/af_unix-don-t-check-sock_dead-in-unix_stream_read_sk.patch [new file with mode: 0644]
queue-6.12/af_unix-don-t-hold-unix_state_lock-in-__unix_dgram_r.patch [new file with mode: 0644]
queue-6.12/af_unix-don-t-use-skb_recv_datagram-in-unix_stream_r.patch [new file with mode: 0644]
queue-6.12/af_unix-drop-all-scm-attributes-for-sockmap.patch [new file with mode: 0644]
queue-6.12/af_unix-scm-fix-whitespace-errors.patch [new file with mode: 0644]
queue-6.12/af_unix-set-drop-reason-in-manage_oob.patch [new file with mode: 0644]
queue-6.12/af_unix-set-drop-reason-in-unix_release_sock.patch [new file with mode: 0644]
queue-6.12/af_unix-set-drop-reason-in-unix_stream_read_skb.patch [new file with mode: 0644]
queue-6.12/crypto-crypto4xx-remove-ahash-related-code.patch [new file with mode: 0644]
queue-6.12/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch [new file with mode: 0644]
queue-6.12/crypto-hisi-trng-remove-crypto_rng-interface.patch [new file with mode: 0644]
queue-6.12/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch [new file with mode: 0644]
queue-6.12/iommu-amd-use-maximum-event-log-buffer-size-when-snp.patch [new file with mode: 0644]
queue-6.12/iommu-amd-use-maximum-ppr-log-buffer-size-when-snp-i.patch [new file with mode: 0644]
queue-6.12/net-dropreason-gather-socket_-drop-reasons.patch [new file with mode: 0644]
queue-6.12/series
queue-6.12/time-jiffies-change-register_refined_jiffies-to-void.patch [new file with mode: 0644]
queue-6.12/time-jiffies-register-jiffies-clocksource-before-usa.patch [new file with mode: 0644]
queue-6.12/vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch [new file with mode: 0644]
queue-6.12/vsock-virtio-fix-zerocopy-completion-for-multi-skb-s.patch [new file with mode: 0644]
queue-6.12/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch [new file with mode: 0644]
queue-6.18/af_unix-drop-all-scm-attributes-for-sockmap.patch [new file with mode: 0644]
queue-6.18/bpf-clear-delta-when-clearing-reg-id-for-non-add-sub.patch [new file with mode: 0644]
queue-6.18/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch [new file with mode: 0644]
queue-6.18/exfat-preserve-benign-secondary-entries-during-renam.patch [new file with mode: 0644]
queue-6.18/iommu-amd-use-maximum-event-log-buffer-size-when-snp.patch [new file with mode: 0644]
queue-6.18/iommu-amd-use-maximum-ppr-log-buffer-size-when-snp-i.patch [new file with mode: 0644]
queue-6.18/media-uvcvideo-fix-deadlock-if-uvc_status_stop-is-ca.patch [new file with mode: 0644]
queue-6.18/selftests-bpf-add-a-test-cases-for-sync_linked_regs-.patch [new file with mode: 0644]
queue-6.18/selftests-bpf-add-test-for-multiple-syncs-from-linke.patch [new file with mode: 0644]
queue-6.18/selftests-bpf-add-tests-for-delta-tracking-when-src_.patch [new file with mode: 0644]
queue-6.18/selftests-bpf-add-tests-for-improved-linked-register.patch [new file with mode: 0644]
queue-6.18/selftests-bpf-add-tests-for-stale-delta-leaking-thro.patch [new file with mode: 0644]
queue-6.18/series
queue-6.6/bpf-prefer-dirty-packs-for-ebpf-allocations.patch [new file with mode: 0644]
queue-6.6/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch [new file with mode: 0644]
queue-6.6/bpf-restrict-jit-predictor-flush-to-cbpf.patch [new file with mode: 0644]
queue-6.6/bpf-skip-redundant-ibpb-in-pack-allocator.patch [new file with mode: 0644]
queue-6.6/bpf-support-for-hardening-against-jit-spraying.patch [new file with mode: 0644]
queue-6.6/crypto-crypto4xx-remove-ahash-related-code.patch [new file with mode: 0644]
queue-6.6/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch [new file with mode: 0644]
queue-6.6/crypto-hisi-trng-remove-crypto_rng-interface.patch [new file with mode: 0644]
queue-6.6/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch [new file with mode: 0644]
queue-6.6/series
queue-6.6/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch [new file with mode: 0644]
queue-6.6/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch [new file with mode: 0644]
queue-7.1/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch [new file with mode: 0644]
queue-7.1/media-uvcvideo-fix-deadlock-if-uvc_status_stop-is-ca.patch [new file with mode: 0644]
queue-7.1/series

diff --git a/queue-5.10/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch b/queue-5.10/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch
new file mode 100644 (file)
index 0000000..e8037cb
--- /dev/null
@@ -0,0 +1,171 @@
+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
+
index 84cef862a5e500246810228882dd8e8cb40794b7..78ab44c8e63cd8a62650f95f6937422b7514ca2d 100644 (file)
@@ -158,3 +158,4 @@ fuse-re-lock-request-before-returning-from-fuse_ref_folio.patch
 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
diff --git a/queue-5.15/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch b/queue-5.15/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch
new file mode 100644 (file)
index 0000000..5129842
--- /dev/null
@@ -0,0 +1,171 @@
+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
+
diff --git a/queue-5.15/crypto-crypto4xx-remove-ahash-related-code.patch b/queue-5.15/crypto-crypto4xx-remove-ahash-related-code.patch
new file mode 100644 (file)
index 0000000..3297ca5
--- /dev/null
@@ -0,0 +1,266 @@
+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
+
diff --git a/queue-5.15/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch b/queue-5.15/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch
new file mode 100644 (file)
index 0000000..4aa9d18
--- /dev/null
@@ -0,0 +1,239 @@
+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
+
diff --git a/queue-5.15/crypto-hisi-trng-remove-crypto_rng-interface.patch b/queue-5.15/crypto-hisi-trng-remove-crypto_rng-interface.patch
new file mode 100644 (file)
index 0000000..1712ba2
--- /dev/null
@@ -0,0 +1,413 @@
+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
+
diff --git a/queue-5.15/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch b/queue-5.15/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
new file mode 100644 (file)
index 0000000..6d4147e
--- /dev/null
@@ -0,0 +1,314 @@
+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
+
index c96f3af1d96a3884ae6f6a2bf8214f8365ada5d8..5ef25f803be19b50bb208c5d0ca0d9c817f79e66 100644 (file)
@@ -200,3 +200,8 @@ 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
 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
diff --git a/queue-6.1/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch b/queue-6.1/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch
new file mode 100644 (file)
index 0000000..03ad44d
--- /dev/null
@@ -0,0 +1,123 @@
+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
+
diff --git a/queue-6.1/crypto-crypto4xx-remove-ahash-related-code.patch b/queue-6.1/crypto-crypto4xx-remove-ahash-related-code.patch
new file mode 100644 (file)
index 0000000..bbd3b66
--- /dev/null
@@ -0,0 +1,266 @@
+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
+
diff --git a/queue-6.1/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch b/queue-6.1/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch
new file mode 100644 (file)
index 0000000..da8f246
--- /dev/null
@@ -0,0 +1,239 @@
+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
+
diff --git a/queue-6.1/crypto-hisi-trng-remove-crypto_rng-interface.patch b/queue-6.1/crypto-hisi-trng-remove-crypto_rng-interface.patch
new file mode 100644 (file)
index 0000000..6eb1f28
--- /dev/null
@@ -0,0 +1,413 @@
+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
+
diff --git a/queue-6.1/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch b/queue-6.1/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
new file mode 100644 (file)
index 0000000..c8736f9
--- /dev/null
@@ -0,0 +1,314 @@
+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
+
index b5ad63414838ab83640ff479ef5d4ea5b172a764..898914cb47b5427ddabda6a6b51b1db55a5e6246 100644 (file)
@@ -259,3 +259,9 @@ tools-mm-slabinfo-fix-total_objects-attribute-name.patch
 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
diff --git a/queue-6.1/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch b/queue-6.1/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch
new file mode 100644 (file)
index 0000000..fc20df6
--- /dev/null
@@ -0,0 +1,97 @@
+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
+
diff --git a/queue-6.12/af_unix-don-t-check-sock_dead-in-unix_stream_read_sk.patch b/queue-6.12/af_unix-don-t-check-sock_dead-in-unix_stream_read_sk.patch
new file mode 100644 (file)
index 0000000..7075afc
--- /dev/null
@@ -0,0 +1,65 @@
+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
+
diff --git a/queue-6.12/af_unix-don-t-hold-unix_state_lock-in-__unix_dgram_r.patch b/queue-6.12/af_unix-don-t-hold-unix_state_lock-in-__unix_dgram_r.patch
new file mode 100644 (file)
index 0000000..692e017
--- /dev/null
@@ -0,0 +1,51 @@
+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
+
diff --git a/queue-6.12/af_unix-don-t-use-skb_recv_datagram-in-unix_stream_r.patch b/queue-6.12/af_unix-don-t-use-skb_recv_datagram-in-unix_stream_r.patch
new file mode 100644 (file)
index 0000000..62ae380
--- /dev/null
@@ -0,0 +1,98 @@
+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
+
diff --git a/queue-6.12/af_unix-drop-all-scm-attributes-for-sockmap.patch b/queue-6.12/af_unix-drop-all-scm-attributes-for-sockmap.patch
new file mode 100644 (file)
index 0000000..c4829ac
--- /dev/null
@@ -0,0 +1,180 @@
+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
+
diff --git a/queue-6.12/af_unix-scm-fix-whitespace-errors.patch b/queue-6.12/af_unix-scm-fix-whitespace-errors.patch
new file mode 100644 (file)
index 0000000..a021660
--- /dev/null
@@ -0,0 +1,74 @@
+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
+
diff --git a/queue-6.12/af_unix-set-drop-reason-in-manage_oob.patch b/queue-6.12/af_unix-set-drop-reason-in-manage_oob.patch
new file mode 100644 (file)
index 0000000..01fdbef
--- /dev/null
@@ -0,0 +1,84 @@
+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
+
diff --git a/queue-6.12/af_unix-set-drop-reason-in-unix_release_sock.patch b/queue-6.12/af_unix-set-drop-reason-in-unix_release_sock.patch
new file mode 100644 (file)
index 0000000..690ea38
--- /dev/null
@@ -0,0 +1,83 @@
+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
+
diff --git a/queue-6.12/af_unix-set-drop-reason-in-unix_stream_read_skb.patch b/queue-6.12/af_unix-set-drop-reason-in-unix_stream_read_skb.patch
new file mode 100644 (file)
index 0000000..159d750
--- /dev/null
@@ -0,0 +1,53 @@
+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
+
diff --git a/queue-6.12/crypto-crypto4xx-remove-ahash-related-code.patch b/queue-6.12/crypto-crypto4xx-remove-ahash-related-code.patch
new file mode 100644 (file)
index 0000000..763b305
--- /dev/null
@@ -0,0 +1,266 @@
+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
+
diff --git a/queue-6.12/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch b/queue-6.12/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch
new file mode 100644 (file)
index 0000000..bca9535
--- /dev/null
@@ -0,0 +1,239 @@
+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
+
diff --git a/queue-6.12/crypto-hisi-trng-remove-crypto_rng-interface.patch b/queue-6.12/crypto-hisi-trng-remove-crypto_rng-interface.patch
new file mode 100644 (file)
index 0000000..94897da
--- /dev/null
@@ -0,0 +1,411 @@
+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
+
diff --git a/queue-6.12/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch b/queue-6.12/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
new file mode 100644 (file)
index 0000000..f43c303
--- /dev/null
@@ -0,0 +1,314 @@
+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
+
diff --git a/queue-6.12/iommu-amd-use-maximum-event-log-buffer-size-when-snp.patch b/queue-6.12/iommu-amd-use-maximum-event-log-buffer-size-when-snp.patch
new file mode 100644 (file)
index 0000000..d740572
--- /dev/null
@@ -0,0 +1,280 @@
+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
+
diff --git a/queue-6.12/iommu-amd-use-maximum-ppr-log-buffer-size-when-snp-i.patch b/queue-6.12/iommu-amd-use-maximum-ppr-log-buffer-size-when-snp-i.patch
new file mode 100644 (file)
index 0000000..223db52
--- /dev/null
@@ -0,0 +1,162 @@
+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
+
diff --git a/queue-6.12/net-dropreason-gather-socket_-drop-reasons.patch b/queue-6.12/net-dropreason-gather-socket_-drop-reasons.patch
new file mode 100644 (file)
index 0000000..d77fd53
--- /dev/null
@@ -0,0 +1,78 @@
+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
+
index 6f88f8f48314be97449627f341c26214ab5c72c6..473dd5b792f7d80b3afb13b846ac4e2b84216e10 100644 (file)
@@ -17,3 +17,23 @@ iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch
 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
diff --git a/queue-6.12/time-jiffies-change-register_refined_jiffies-to-void.patch b/queue-6.12/time-jiffies-change-register_refined_jiffies-to-void.patch
new file mode 100644 (file)
index 0000000..5c713cd
--- /dev/null
@@ -0,0 +1,62 @@
+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
+
diff --git a/queue-6.12/time-jiffies-register-jiffies-clocksource-before-usa.patch b/queue-6.12/time-jiffies-register-jiffies-clocksource-before-usa.patch
new file mode 100644 (file)
index 0000000..0577fc5
--- /dev/null
@@ -0,0 +1,58 @@
+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
+
diff --git a/queue-6.12/vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch b/queue-6.12/vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch
new file mode 100644 (file)
index 0000000..27c13ea
--- /dev/null
@@ -0,0 +1,89 @@
+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
+
diff --git a/queue-6.12/vsock-virtio-fix-zerocopy-completion-for-multi-skb-s.patch b/queue-6.12/vsock-virtio-fix-zerocopy-completion-for-multi-skb-s.patch
new file mode 100644 (file)
index 0000000..78c0a62
--- /dev/null
@@ -0,0 +1,164 @@
+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
+
diff --git a/queue-6.12/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch b/queue-6.12/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch
new file mode 100644 (file)
index 0000000..ee0c88e
--- /dev/null
@@ -0,0 +1,97 @@
+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
+
diff --git a/queue-6.18/af_unix-drop-all-scm-attributes-for-sockmap.patch b/queue-6.18/af_unix-drop-all-scm-attributes-for-sockmap.patch
new file mode 100644 (file)
index 0000000..e10352f
--- /dev/null
@@ -0,0 +1,179 @@
+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
+
diff --git a/queue-6.18/bpf-clear-delta-when-clearing-reg-id-for-non-add-sub.patch b/queue-6.18/bpf-clear-delta-when-clearing-reg-id-for-non-add-sub.patch
new file mode 100644 (file)
index 0000000..095d78f
--- /dev/null
@@ -0,0 +1,168 @@
+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
+
diff --git a/queue-6.18/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch b/queue-6.18/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
new file mode 100644 (file)
index 0000000..239dd3d
--- /dev/null
@@ -0,0 +1,314 @@
+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
+
diff --git a/queue-6.18/exfat-preserve-benign-secondary-entries-during-renam.patch b/queue-6.18/exfat-preserve-benign-secondary-entries-during-renam.patch
new file mode 100644 (file)
index 0000000..6ab493a
--- /dev/null
@@ -0,0 +1,347 @@
+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
+
diff --git a/queue-6.18/iommu-amd-use-maximum-event-log-buffer-size-when-snp.patch b/queue-6.18/iommu-amd-use-maximum-event-log-buffer-size-when-snp.patch
new file mode 100644 (file)
index 0000000..4ee6a22
--- /dev/null
@@ -0,0 +1,316 @@
+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
+
diff --git a/queue-6.18/iommu-amd-use-maximum-ppr-log-buffer-size-when-snp-i.patch b/queue-6.18/iommu-amd-use-maximum-ppr-log-buffer-size-when-snp-i.patch
new file mode 100644 (file)
index 0000000..5093d2a
--- /dev/null
@@ -0,0 +1,150 @@
+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
+
diff --git a/queue-6.18/media-uvcvideo-fix-deadlock-if-uvc_status_stop-is-ca.patch b/queue-6.18/media-uvcvideo-fix-deadlock-if-uvc_status_stop-is-ca.patch
new file mode 100644 (file)
index 0000000..be58ed8
--- /dev/null
@@ -0,0 +1,100 @@
+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
+
diff --git a/queue-6.18/selftests-bpf-add-a-test-cases-for-sync_linked_regs-.patch b/queue-6.18/selftests-bpf-add-a-test-cases-for-sync_linked_regs-.patch
new file mode 100644 (file)
index 0000000..6b54b7f
--- /dev/null
@@ -0,0 +1,190 @@
+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
+
diff --git a/queue-6.18/selftests-bpf-add-test-for-multiple-syncs-from-linke.patch b/queue-6.18/selftests-bpf-add-test-for-multiple-syncs-from-linke.patch
new file mode 100644 (file)
index 0000000..55f4f62
--- /dev/null
@@ -0,0 +1,74 @@
+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
+
diff --git a/queue-6.18/selftests-bpf-add-tests-for-delta-tracking-when-src_.patch b/queue-6.18/selftests-bpf-add-tests-for-delta-tracking-when-src_.patch
new file mode 100644 (file)
index 0000000..ce2ccaf
--- /dev/null
@@ -0,0 +1,119 @@
+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
+
diff --git a/queue-6.18/selftests-bpf-add-tests-for-improved-linked-register.patch b/queue-6.18/selftests-bpf-add-tests-for-improved-linked-register.patch
new file mode 100644 (file)
index 0000000..93da659
--- /dev/null
@@ -0,0 +1,352 @@
+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
+
diff --git a/queue-6.18/selftests-bpf-add-tests-for-stale-delta-leaking-thro.patch b/queue-6.18/selftests-bpf-add-tests-for-stale-delta-leaking-thro.patch
new file mode 100644 (file)
index 0000000..dbb2cdc
--- /dev/null
@@ -0,0 +1,118 @@
+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
+
index 3b1010d9cfb22bddf7e539563fe7a28e595e959e..c174d9aa444ef3aeb9a333982fdedd041a076e34 100644 (file)
@@ -6,3 +6,15 @@ kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch
 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
diff --git a/queue-6.6/bpf-prefer-dirty-packs-for-ebpf-allocations.patch b/queue-6.6/bpf-prefer-dirty-packs-for-ebpf-allocations.patch
new file mode 100644 (file)
index 0000000..688c300
--- /dev/null
@@ -0,0 +1,49 @@
+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
+
diff --git a/queue-6.6/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch b/queue-6.6/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch
new file mode 100644 (file)
index 0000000..e4608d0
--- /dev/null
@@ -0,0 +1,88 @@
+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
+
diff --git a/queue-6.6/bpf-restrict-jit-predictor-flush-to-cbpf.patch b/queue-6.6/bpf-restrict-jit-predictor-flush-to-cbpf.patch
new file mode 100644 (file)
index 0000000..ee9e813
--- /dev/null
@@ -0,0 +1,152 @@
+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
+
diff --git a/queue-6.6/bpf-skip-redundant-ibpb-in-pack-allocator.patch b/queue-6.6/bpf-skip-redundant-ibpb-in-pack-allocator.patch
new file mode 100644 (file)
index 0000000..4bf9cca
--- /dev/null
@@ -0,0 +1,81 @@
+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
+
diff --git a/queue-6.6/bpf-support-for-hardening-against-jit-spraying.patch b/queue-6.6/bpf-support-for-hardening-against-jit-spraying.patch
new file mode 100644 (file)
index 0000000..d69ed57
--- /dev/null
@@ -0,0 +1,120 @@
+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
+
diff --git a/queue-6.6/crypto-crypto4xx-remove-ahash-related-code.patch b/queue-6.6/crypto-crypto4xx-remove-ahash-related-code.patch
new file mode 100644 (file)
index 0000000..be67f29
--- /dev/null
@@ -0,0 +1,266 @@
+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
+
diff --git a/queue-6.6/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch b/queue-6.6/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch
new file mode 100644 (file)
index 0000000..860d4cd
--- /dev/null
@@ -0,0 +1,239 @@
+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
+
diff --git a/queue-6.6/crypto-hisi-trng-remove-crypto_rng-interface.patch b/queue-6.6/crypto-hisi-trng-remove-crypto_rng-interface.patch
new file mode 100644 (file)
index 0000000..b58359f
--- /dev/null
@@ -0,0 +1,413 @@
+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
+
diff --git a/queue-6.6/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch b/queue-6.6/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
new file mode 100644 (file)
index 0000000..e4f0a7c
--- /dev/null
@@ -0,0 +1,314 @@
+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
+
index 8e1583d151f14661b5d5294b5cef50f1006f8dde..f69152770e6917580e6f6d0866c52895fbb4b945 100644 (file)
@@ -331,3 +331,14 @@ kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch
 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
diff --git a/queue-6.6/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch b/queue-6.6/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch
new file mode 100644 (file)
index 0000000..a2bf524
--- /dev/null
@@ -0,0 +1,147 @@
+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
+
diff --git a/queue-6.6/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch b/queue-6.6/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch
new file mode 100644 (file)
index 0000000..98755c6
--- /dev/null
@@ -0,0 +1,97 @@
+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
+
diff --git a/queue-7.1/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch b/queue-7.1/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch
new file mode 100644 (file)
index 0000000..4480a99
--- /dev/null
@@ -0,0 +1,314 @@
+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
+
diff --git a/queue-7.1/media-uvcvideo-fix-deadlock-if-uvc_status_stop-is-ca.patch b/queue-7.1/media-uvcvideo-fix-deadlock-if-uvc_status_stop-is-ca.patch
new file mode 100644 (file)
index 0000000..cd9cd04
--- /dev/null
@@ -0,0 +1,100 @@
+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
+
index 60b2d456c87f209a8adc3fe197b9557622f3caf8..f5353d34dac5ac621325f93f3b1822db19151e89 100644 (file)
@@ -1,2 +1,4 @@
 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