From: Sasha Levin Date: Sun, 19 Jul 2026 15:00:07 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a2202e76c8257df1c054029b38f73a032b35c60a;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- 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 index 0000000000..e8037cb677 --- /dev/null +++ b/queue-5.10/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch @@ -0,0 +1,171 @@ +From 29f275c3a7c05d81c1b34dc36b9c6f2c1fdebfa8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:34:03 -0700 +Subject: crypto: af_alg - Remove zero-copy support from skcipher and aead + +From: Eric Biggers + +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 +Closes: https://lore.kernel.org/r/afYcc-tZFwvZZo76@ans-MacBook-Pro.local +Reviewed-by: Demi Marie Obenour +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.10/series b/queue-5.10/series index 84cef862a5..78ab44c8e6 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -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 index 0000000000..51298421bf --- /dev/null +++ b/queue-5.15/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch @@ -0,0 +1,171 @@ +From 2e37a8290326763845d58269349557f0ddbd5edd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:34:03 -0700 +Subject: crypto: af_alg - Remove zero-copy support from skcipher and aead + +From: Eric Biggers + +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 +Closes: https://lore.kernel.org/r/afYcc-tZFwvZZo76@ans-MacBook-Pro.local +Reviewed-by: Demi Marie Obenour +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..3297ca58c7 --- /dev/null +++ b/queue-5.15/crypto-crypto4xx-remove-ahash-related-code.patch @@ -0,0 +1,266 @@ +From 0718d9735384ebc3ddb4911f47722ad272ebd9d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 19:44:02 -0700 +Subject: crypto: crypto4xx - Remove ahash-related code + +From: Herbert Xu + +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 +Signed-off-by: Eric Biggers +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include +-#include +-#include + #include + #include + #include +@@ -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 + #include + #include +-#include + #include + #include + #include +@@ -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 index 0000000000..4aa9d18ddd --- /dev/null +++ b/queue-5.15/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch @@ -0,0 +1,239 @@ +From 96395e918b3d29b44713f0625bcf65c7171ecbfe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 19:44:03 -0700 +Subject: crypto: crypto4xx - Remove insecure and unused rng_alg + +From: Eric Biggers + +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 +Acked-by: Christian Lamparter +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include + #include + #include + #include +-#include + #include + #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 +-#include + #include + #include +-#include + #include + #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 index 0000000000..1712ba21cb --- /dev/null +++ b/queue-5.15/crypto-hisi-trng-remove-crypto_rng-interface.patch @@ -0,0 +1,413 @@ +From 174413dd28cf0812cc8e11896f9a4c8f5c83e175 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:42:54 -0700 +Subject: crypto: hisi-trng - Remove crypto_rng interface + +From: Eric Biggers + +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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include +-#include + #include + #include + #include + #include + #include +-#include + #include +-#include + #include + #include + + #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 index 0000000000..6d4147ed32 --- /dev/null +++ b/queue-5.15/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch @@ -0,0 +1,314 @@ +From 96a0b608f4d5b3dcc8f0ee6a89f112a826252177 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:52:28 -0700 +Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg + +From: Eric Biggers + +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 +Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/ +Acked-by: Corentin LABBE +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include +-#include + + #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 + diff --git a/queue-5.15/series b/queue-5.15/series index c96f3af1d9..5ef25f803b 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -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 index 0000000000..03ad44d39f --- /dev/null +++ b/queue-6.1/crypto-af_alg-remove-zero-copy-support-from-skcipher.patch @@ -0,0 +1,123 @@ +From 59ab8631c060e1bdf6a9d6d0f9f82e71a2410756 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:33:12 -0700 +Subject: crypto: af_alg - Remove zero-copy support from skcipher and aead + +From: Eric Biggers + +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 +Closes: https://lore.kernel.org/r/afYcc-tZFwvZZo76@ans-MacBook-Pro.local +Reviewed-by: Demi Marie Obenour +Cc: stable@vger.kernel.org +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +[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 +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..bbd3b669d6 --- /dev/null +++ b/queue-6.1/crypto-crypto4xx-remove-ahash-related-code.patch @@ -0,0 +1,266 @@ +From ab565e6498a241fd2d01f56eaf6b31358e99a6ed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 19:44:02 -0700 +Subject: crypto: crypto4xx - Remove ahash-related code + +From: Herbert Xu + +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 +Signed-off-by: Eric Biggers +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include +-#include +-#include + #include + #include + #include +@@ -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 + #include + #include +-#include + #include + #include + #include +@@ -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 index 0000000000..da8f246019 --- /dev/null +++ b/queue-6.1/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch @@ -0,0 +1,239 @@ +From d3f415a7be6398620138e72be0c204a73d3c206c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 19:44:03 -0700 +Subject: crypto: crypto4xx - Remove insecure and unused rng_alg + +From: Eric Biggers + +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 +Acked-by: Christian Lamparter +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include + #include + #include + #include +-#include + #include + #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 +-#include + #include + #include +-#include + #include + #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 index 0000000000..6eb1f2845c --- /dev/null +++ b/queue-6.1/crypto-hisi-trng-remove-crypto_rng-interface.patch @@ -0,0 +1,413 @@ +From 5b9da4dfe92071ca9cc8931956375077495fce67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:42:54 -0700 +Subject: crypto: hisi-trng - Remove crypto_rng interface + +From: Eric Biggers + +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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include +-#include + #include + #include + #include + #include + #include +-#include + #include +-#include + #include + #include + + #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 index 0000000000..c8736f9d9e --- /dev/null +++ b/queue-6.1/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch @@ -0,0 +1,314 @@ +From 554317153efcfafd2222d23599e6b664f2001d73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:50:58 -0700 +Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg + +From: Eric Biggers + +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 +Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/ +Acked-by: Corentin LABBE +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include +-#include + + #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.1/series b/queue-6.1/series index b5ad634148..898914cb47 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -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 index 0000000000..fc20df6179 --- /dev/null +++ b/queue-6.1/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch @@ -0,0 +1,97 @@ +From a2b9962b96dd02e316e920c871329de562a19af0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 12:04:30 -0400 +Subject: x86/mm: Fix check/use ordering in switch_mm_irqs_off() + +From: Stephen Dolan + +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 +Tested-by: Seth Forshee +Tested-by: Eric Hagberg +Signed-off-by: Stephen Dolan +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..7075afc8b2 --- /dev/null +++ b/queue-6.12/af_unix-don-t-check-sock_dead-in-unix_stream_read_sk.patch @@ -0,0 +1,65 @@ +From 1dc25d36dd60d94844a53f31401e3557b73b06c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20250702223606.1054680-3-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..692e017056 --- /dev/null +++ b/queue-6.12/af_unix-don-t-hold-unix_state_lock-in-__unix_dgram_r.patch @@ -0,0 +1,51 @@ +From f71d457b4a0a913b683e633c3711847d15d54b3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Willem de Bruijn +Link: https://patch.msgid.link/20250702223606.1054680-2-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..62ae3809d9 --- /dev/null +++ b/queue-6.12/af_unix-don-t-use-skb_recv_datagram-in-unix_stream_r.patch @@ -0,0 +1,98 @@ +From e5b6125d20982675dafda33db0e9b73759272ed9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20250702223606.1054680-4-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..c4829ac25f --- /dev/null +++ b/queue-6.12/af_unix-drop-all-scm-attributes-for-sockmap.patch @@ -0,0 +1,180 @@ +From f15c5996e25b5ea3d3a65a3b05aa2757bea462e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 19:29:22 +0200 +Subject: af_unix: Drop all SCM attributes for SOCKMAP. + +From: Kuniyuki Iwashima + +[ 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: + + 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) + + +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 +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260415184830.3988432-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..a021660f10 --- /dev/null +++ b/queue-6.12/af_unix-scm-fix-whitespace-errors.patch @@ -0,0 +1,74 @@ +From 87d0eb85095af94f60d0625df2ffe6d3eb407ac8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 19:29:18 +0200 +Subject: af_unix/scm: fix whitespace errors + +From: Alexander Mikhalitsyn + +[ Upstream commit 2b9996417e4ec231c91818f9ea8107ae62ef75ad ] + +Fix whitespace/formatting errors. + +Cc: linux-kernel@vger.kernel.org +Cc: netdev@vger.kernel.org +Cc: David S. Miller +Cc: Eric Dumazet +Cc: Jakub Kicinski +Cc: Paolo Abeni +Cc: Simon Horman +Cc: Leon Romanovsky +Cc: Arnd Bergmann +Cc: Christian Brauner +Cc: Kuniyuki Iwashima +Cc: Lennart Poettering +Cc: Luca Boccassi +Cc: David Rheinsberg +Signed-off-by: Alexander Mikhalitsyn +Link: https://lore.kernel.org/20250703222314.309967-5-aleksandr.mikhalitsyn@canonical.com +Reviewed-by: Kuniyuki Iwashima +Signed-off-by: Christian Brauner +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..01fdbeff19 --- /dev/null +++ b/queue-6.12/af_unix-set-drop-reason-in-manage_oob.patch @@ -0,0 +1,84 @@ +From e7b28c778b4c2e2eae8afcf895d3ddf04b0dd2c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 19:29:16 +0200 +Subject: af_unix: Set drop reason in manage_oob(). + +From: Kuniyuki Iwashima + +[ 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 +Link: https://patch.msgid.link/20250116053441.5758-6-kuniyu@amazon.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..690ea38a08 --- /dev/null +++ b/queue-6.12/af_unix-set-drop-reason-in-unix_release_sock.patch @@ -0,0 +1,83 @@ +From 7481c982ea9c600faf01bb9be36c2e7a737e426c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 19:29:15 +0200 +Subject: af_unix: Set drop reason in unix_release_sock(). + +From: Kuniyuki Iwashima + +[ 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 +Link: https://patch.msgid.link/20250116053441.5758-3-kuniyu@amazon.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..159d750811 --- /dev/null +++ b/queue-6.12/af_unix-set-drop-reason-in-unix_stream_read_skb.patch @@ -0,0 +1,53 @@ +From 886edfbb011bdeb86e01984f71eb05019e8269c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 19:29:17 +0200 +Subject: af_unix: Set drop reason in unix_stream_read_skb(). + +From: Kuniyuki Iwashima + +[ 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 +Link: https://patch.msgid.link/20250116053441.5758-7-kuniyu@amazon.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..763b30542c --- /dev/null +++ b/queue-6.12/crypto-crypto4xx-remove-ahash-related-code.patch @@ -0,0 +1,266 @@ +From 5ada1a17fdc2d98c1925346f80730095d978f0ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 19:44:02 -0700 +Subject: crypto: crypto4xx - Remove ahash-related code + +From: Herbert Xu + +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 +Signed-off-by: Eric Biggers +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include +-#include +-#include + #include + #include + #include +@@ -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 + #include + #include +-#include + #include + #include + #include +@@ -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 index 0000000000..bca95356cd --- /dev/null +++ b/queue-6.12/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch @@ -0,0 +1,239 @@ +From 7018150c83466d055aecb362de0fc918822b74a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 19:44:03 -0700 +Subject: crypto: crypto4xx - Remove insecure and unused rng_alg + +From: Eric Biggers + +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 +Acked-by: Christian Lamparter +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include + #include + #include + #include +-#include + #include + #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 +-#include + #include + #include +-#include + #include + #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 index 0000000000..94897da05e --- /dev/null +++ b/queue-6.12/crypto-hisi-trng-remove-crypto_rng-interface.patch @@ -0,0 +1,411 @@ +From 7e09bb70f1d85203470334bec6c6155536f65f41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:39:07 -0700 +Subject: crypto: hisi-trng - Remove crypto_rng interface + +From: Eric Biggers + +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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include +-#include + #include + #include + #include + #include + #include +-#include + #include +-#include + #include + #include + + #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 index 0000000000..f43c303f51 --- /dev/null +++ b/queue-6.12/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch @@ -0,0 +1,314 @@ +From 4b94a416450ad97d9f3684429b91bbdf5f96646e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:50:58 -0700 +Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg + +From: Eric Biggers + +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 +Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/ +Acked-by: Corentin LABBE +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include +-#include + + #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 index 0000000000..d740572b31 --- /dev/null +++ b/queue-6.12/iommu-amd-use-maximum-event-log-buffer-size-when-snp.patch @@ -0,0 +1,280 @@ +From 3af17077d7caa49d66f29e81d90e9a1920d62647 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +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 +Cc: Suravee Suthikulpanit +Cc: Joerg Roedel +Signed-off-by: Vasant Hegde +Tested-by: Dheeraj Kumar Srivastava +Signed-off-by: Joerg Roedel +(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 +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 index 0000000000..223db52782 --- /dev/null +++ b/queue-6.12/iommu-amd-use-maximum-ppr-log-buffer-size-when-snp-i.patch @@ -0,0 +1,162 @@ +From d98101ff66d81b332e60156f95b85e54f0d25564 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +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 +Cc: Suravee Suthikulpanit +Cc: Joerg Roedel +Signed-off-by: Vasant Hegde +Tested-by: Dheeraj Kumar Srivastava +Signed-off-by: Joerg Roedel +(cherry picked from commit 1f44aab79bac31f459422dfb213e907bb386509c) +[ Modify amd_iommu_free_ppr_log() due to different iommu_free_pages() API. ] +Signed-off-by: Liam Merwick +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..d77fd53917 --- /dev/null +++ b/queue-6.12/net-dropreason-gather-socket_-drop-reasons.patch @@ -0,0 +1,78 @@ +From 6856200fdf5a645c13b0b35a123b92188f320a3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 19:29:14 +0200 +Subject: net: dropreason: Gather SOCKET_ drop reasons. + +From: Kuniyuki Iwashima + +[ 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 +Link: https://patch.msgid.link/20250116053441.5758-2-kuniyu@amazon.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/series b/queue-6.12/series index 6f88f8f483..473dd5b792 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -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 index 0000000000..5c713cdc12 --- /dev/null +++ b/queue-6.12/time-jiffies-change-register_refined_jiffies-to-void.patch @@ -0,0 +1,62 @@ +From 87e8dd8f2eb92ca175214275d0b3c6cc43e596d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Apr 2025 11:27:32 +0800 +Subject: time/jiffies: Change register_refined_jiffies() to void __init + +From: Su Hui + +[ 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 +Signed-off-by: Thomas Gleixner +Link: https://lore.kernel.org/all/20250430032734.2079290-2-suhui@nfschina.com +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..0577fc5dbe --- /dev/null +++ b/queue-6.12/time-jiffies-register-jiffies-clocksource-before-usa.patch @@ -0,0 +1,58 @@ +From d71c42f5c266d9e03155ee8575196cab78b9a28f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Jun 2026 17:14:45 +0200 +Subject: time/jiffies: Register jiffies clocksource before usage + +From: Thomas Gleixner + +[ 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 +Signed-off-by: Thomas Gleixner +Tested-by: Teddy Astie +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 +--- + 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 index 0000000000..27c13ea65e --- /dev/null +++ b/queue-6.12/vsock-virtio-bind-uarg-before-filling-zerocopy-skb.patch @@ -0,0 +1,89 @@ +From 0fea85e11c69abf6dced5b779b3d4727776ab20d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 May 2026 10:33:01 +0800 +Subject: vsock/virtio: bind uarg before filling zerocopy skb + +From: Jingguo Tan + +[ 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 +Signed-off-by: Rongzhen Cui +Signed-off-by: Jingguo Tan +Acked-by: Arseniy Krasnov +Acked-by: Michael S. Tsirkin +Reviewed-by: Stefano Garzarella +Link: https://patch.msgid.link/20260527023301.1075581-1-malin89@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..78c0a62f6f --- /dev/null +++ b/queue-6.12/vsock-virtio-fix-zerocopy-completion-for-multi-skb-s.patch @@ -0,0 +1,164 @@ +From c3b9d59752084c6e16945d671ebf1407a1f92327 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 19:35:59 +0300 +Subject: vsock/virtio: fix zerocopy completion for multi-skb sends + +From: Stefano Garzarella + +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 +Signed-off-by: Stefano Garzarella +Acked-by: Michael S. Tsirkin +Acked-by: Arseniy Krasnov +Link: https://patch.msgid.link/20260514092948.268720-1-sgarzare@redhat.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Alexander Martyniuk +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..ee0c88ee8e --- /dev/null +++ b/queue-6.12/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch @@ -0,0 +1,97 @@ +From e7532e903b5167e00693a66acc994cacecdb2650 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 12:04:30 -0400 +Subject: x86/mm: Fix check/use ordering in switch_mm_irqs_off() + +From: Stephen Dolan + +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 +Tested-by: Seth Forshee +Tested-by: Eric Hagberg +Signed-off-by: Stephen Dolan +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..e10352f044 --- /dev/null +++ b/queue-6.18/af_unix-drop-all-scm-attributes-for-sockmap.patch @@ -0,0 +1,179 @@ +From b206dc73e3ee5e222a2211e38f6e1fe95cc9ddf6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Apr 2026 18:48:29 +0000 +Subject: af_unix: Drop all SCM attributes for SOCKMAP. + +From: Kuniyuki Iwashima + +[ 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: + + 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) + + +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 +Signed-off-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20260415184830.3988432-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..095d78fa8b --- /dev/null +++ b/queue-6.18/bpf-clear-delta-when-clearing-reg-id-for-non-add-sub.patch @@ -0,0 +1,168 @@ +From ef65a09d670e123f65ae4839058302666bc22a1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +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 +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260407192421.508817-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +[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 +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..239dd3dce5 --- /dev/null +++ b/queue-6.18/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch @@ -0,0 +1,314 @@ +From 2e2fc7864acf998cb8f618832a317fe577b14cd8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:50:58 -0700 +Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg + +From: Eric Biggers + +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 +Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/ +Acked-by: Corentin LABBE +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include +-#include + + #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 index 0000000000..6ab493ad18 --- /dev/null +++ b/queue-6.18/exfat-preserve-benign-secondary-entries-during-renam.patch @@ -0,0 +1,347 @@ +From 5d037460a1553fa9dd96a682e176a7fdcee26381 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 09:51:27 -0700 +Subject: exfat: preserve benign secondary entries during rename and move + +From: Rochan Avlur + +[ 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 +Reviewed-by: Yuezhang Mo +Signed-off-by: Namjae Jeon +Signed-off-by: Rochan Avlur +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..4ee6a229b2 --- /dev/null +++ b/queue-6.18/iommu-amd-use-maximum-event-log-buffer-size-when-snp.patch @@ -0,0 +1,316 @@ +From f44c0f3d62cc2559cdb912ca4a326e1430f9ab87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Suravee Suthikulpanit +Cc: Joerg Roedel +Signed-off-by: Vasant Hegde +Tested-by: Dheeraj Kumar Srivastava +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 index 0000000000..5093d2a11e --- /dev/null +++ b/queue-6.18/iommu-amd-use-maximum-ppr-log-buffer-size-when-snp-i.patch @@ -0,0 +1,150 @@ +From e7634cef1b1b11e6adf1f8691ef804575af6e8b1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Suravee Suthikulpanit +Cc: Joerg Roedel +Signed-off-by: Vasant Hegde +Tested-by: Dheeraj Kumar Srivastava +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..be58ed8dd3 --- /dev/null +++ b/queue-6.18/media-uvcvideo-fix-deadlock-if-uvc_status_stop-is-ca.patch @@ -0,0 +1,100 @@ +From 2faa78fee2c57bdb841cfbbf997c9dabfd4a778a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20260316155823.1855434-1-sean.anderson@linux.dev +Reviewed-by: Ricardo Ribalda +Tested-by: Ricardo Ribalda +Reviewed-by: Laurent Pinchart +Signed-off-by: Hans de Goede +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..6b54b7fc39 --- /dev/null +++ b/queue-6.18/selftests-bpf-add-a-test-cases-for-sync_linked_regs-.patch @@ -0,0 +1,190 @@ +From cbb9b65df986529605db80d2fabd47015c6aebe1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +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 +Signed-off-by: Puranjay Mohan +Signed-off-by: Daniel Borkmann +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260319211507.213816-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + .../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 index 0000000000..55f4f622fd --- /dev/null +++ b/queue-6.18/selftests-bpf-add-test-for-multiple-syncs-from-linke.patch @@ -0,0 +1,74 @@ +From 0ac64faf1b50975df6b9adbd5433482ad7d27798 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 12:47:24 +0800 +Subject: selftests: bpf: Add test for multiple syncs from linked register + +From: Puranjay Mohan + +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 +Tested-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260115151143.1344724-3-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + .../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 index 0000000000..ce2ccaf7e4 --- /dev/null +++ b/queue-6.18/selftests-bpf-add-tests-for-delta-tracking-when-src_.patch @@ -0,0 +1,119 @@ +From 9ce1ac53fc343f67d932b809113759467ea9b8a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +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 +Link: https://lore.kernel.org/r/20260407192421.508817-3-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +[shung-hsi.yu: missing context from commit 223ffb6a3d05 ("selftests/bpf: add +reproducer for spurious precision propagation through calls").] +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + .../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 index 0000000000..93da659008 --- /dev/null +++ b/queue-6.18/selftests-bpf-add-tests-for-improved-linked-register.patch @@ -0,0 +1,352 @@ +From e564e04547b2fc4dd3b8b370bf7a4a91bd80460b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 12:47:25 +0800 +Subject: selftests/bpf: Add tests for improved linked register tracking + +From: Puranjay Mohan + +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 +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20260204151741.2678118-3-puranjay@kernel.org +Signed-off-by: Alexei Starovoitov +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + .../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 ++#include + #include + #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 index 0000000000..dbb2cdc2ad --- /dev/null +++ b/queue-6.18/selftests-bpf-add-tests-for-stale-delta-leaking-thro.patch @@ -0,0 +1,118 @@ +From 1ac77f3711f74f800e767647bceba2d40bbf8b41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 12:47:29 +0800 +Subject: selftests/bpf: Add tests for stale delta leaking through id + reassignment + +From: Daniel Borkmann + +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 +Link: https://lore.kernel.org/r/20260407192421.508817-4-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + .../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 + diff --git a/queue-6.18/series b/queue-6.18/series index 3b1010d9cf..c174d9aa44 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -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 index 0000000000..688c3005de --- /dev/null +++ b/queue-6.6/bpf-prefer-dirty-packs-for-ebpf-allocations.patch @@ -0,0 +1,49 @@ +From 81baa16a9ae3bcffa75f207ce7359a773a40dded Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 10:07:01 -0700 +Subject: bpf: Prefer dirty packs for eBPF allocations + +From: Pawan Gupta + +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 +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..e4608d0025 --- /dev/null +++ b/queue-6.6/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch @@ -0,0 +1,88 @@ +From 1781114de228c3d2f9162fa2c95d57c1c942b130 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +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 +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..ee9e8130e6 --- /dev/null +++ b/queue-6.6/bpf-restrict-jit-predictor-flush-to-cbpf.patch @@ -0,0 +1,152 @@ +From d087786ab8abdc6fb77574ca92b784a5950de88d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 10:06:16 -0700 +Subject: bpf: Restrict JIT predictor flush to cBPF + +From: Pawan Gupta + +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 +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..4bf9cca2f3 --- /dev/null +++ b/queue-6.6/bpf-skip-redundant-ibpb-in-pack-allocator.patch @@ -0,0 +1,81 @@ +From 7a8ed9a43bd1484265a037867860372ff67b5ce3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 10:06:31 -0700 +Subject: bpf: Skip redundant IBPB in pack allocator + +From: Pawan Gupta + +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 +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..d69ed57308 --- /dev/null +++ b/queue-6.6/bpf-support-for-hardening-against-jit-spraying.patch @@ -0,0 +1,120 @@ +From a13b06faceb9e9dddd541386228940a7ee1bec4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 10:05:45 -0700 +Subject: bpf: Support for hardening against JIT spraying + +From: Pawan Gupta + +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 +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + + #include +@@ -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 + #include + #include ++#include + + #include + #include +@@ -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 index 0000000000..be67f29b22 --- /dev/null +++ b/queue-6.6/crypto-crypto4xx-remove-ahash-related-code.patch @@ -0,0 +1,266 @@ +From 3a8abfee4a7efe326df871b4c55f1920175c75fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 19:44:02 -0700 +Subject: crypto: crypto4xx - Remove ahash-related code + +From: Herbert Xu + +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 +Signed-off-by: Eric Biggers +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include +-#include +-#include + #include + #include + #include +@@ -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 + #include + #include +-#include + #include + #include + #include +@@ -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 index 0000000000..860d4cd23a --- /dev/null +++ b/queue-6.6/crypto-crypto4xx-remove-insecure-and-unused-rng_alg.patch @@ -0,0 +1,239 @@ +From 70b711ee4fafb3c6009f6dd6a219d07764f016aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 19:44:03 -0700 +Subject: crypto: crypto4xx - Remove insecure and unused rng_alg + +From: Eric Biggers + +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 +Acked-by: Christian Lamparter +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include + #include + #include + #include +-#include + #include + #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 +-#include + #include + #include +-#include + #include + #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 index 0000000000..b58359f3bb --- /dev/null +++ b/queue-6.6/crypto-hisi-trng-remove-crypto_rng-interface.patch @@ -0,0 +1,413 @@ +From bcff38f085826344f211b89c3fa59bb03f18caba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:42:54 -0700 +Subject: crypto: hisi-trng - Remove crypto_rng interface + +From: Eric Biggers + +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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include +-#include + #include + #include + #include + #include + #include +-#include + #include +-#include + #include + #include + + #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 index 0000000000..e4f0a7c0aa --- /dev/null +++ b/queue-6.6/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch @@ -0,0 +1,314 @@ +From 215a56756795604a7b890c43ecf4fafa8c6e3269 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:50:58 -0700 +Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg + +From: Eric Biggers + +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 +Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/ +Acked-by: Corentin LABBE +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include +-#include + + #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.6/series b/queue-6.6/series index 8e1583d151..f69152770e 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -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 index 0000000000..a2bf524efe --- /dev/null +++ b/queue-6.6/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch @@ -0,0 +1,147 @@ +From f2f311f1a6df8f24e94e0279caf6e207b1a2bd9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 10:06:00 -0700 +Subject: x86/bugs: Enable IBPB flush on BPF JIT allocation + +From: Pawan Gupta + +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 +Acked-by: Daniel Borkmann +Acked-by: Dave Hansen +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + + #include + #include +@@ -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 index 0000000000..98755c612e --- /dev/null +++ b/queue-6.6/x86-mm-fix-check-use-ordering-in-switch_mm_irqs_off.patch @@ -0,0 +1,97 @@ +From 6d3c6ae33fa2dfec70b734e928545c30bbe726ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Jul 2026 12:04:30 -0400 +Subject: x86/mm: Fix check/use ordering in switch_mm_irqs_off() + +From: Stephen Dolan + +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 +Tested-by: Seth Forshee +Tested-by: Eric Hagberg +Signed-off-by: Stephen Dolan +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..4480a992ec --- /dev/null +++ b/queue-7.1/crypto-sun4i-ss-remove-insecure-and-unused-rng_alg.patch @@ -0,0 +1,314 @@ +From 2d24231f6f61609f35fd7e0bbbffde0a722729b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 20:50:58 -0700 +Subject: crypto: sun4i-ss - Remove insecure and unused rng_alg + +From: Eric Biggers + +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 +Closes: https://lore.kernel.org/r/af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev/ +Acked-by: Corentin LABBE +Signed-off-by: Eric Biggers +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include + #include +-#include +-#include + + #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 index 0000000000..cd9cd04e23 --- /dev/null +++ b/queue-7.1/media-uvcvideo-fix-deadlock-if-uvc_status_stop-is-ca.patch @@ -0,0 +1,100 @@ +From 93098fcdd29190e0707d1273af749c722d83f14e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20260316155823.1855434-1-sean.anderson@linux.dev +Reviewed-by: Ricardo Ribalda +Tested-by: Ricardo Ribalda +Reviewed-by: Laurent Pinchart +Signed-off-by: Hans de Goede +Signed-off-by: Hans Verkuil +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/series b/queue-7.1/series index 60b2d456c8..f5353d34da 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -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