Linux cryptographic layer development
 help / color / mirror / Atom feed
* [PATCH] crypto: testmgr - allow authenc(hmac(sha{256,384}),cts(cbc(aes))) in FIPS mode
From: Ilya Dryomov @ 2026-06-03 15:50 UTC (permalink / raw)
  To: Herbert Xu; +Cc: David Howells, linux-crypto, ceph-devel, linux-kernel

hmac(sha256), hmac(sha384) and cts(cbc(aes)) algorithms have been
marked as FIPS allowed for years.  Mark the respective authenc()
constructions per RFC 8009 ("AES Encryption with HMAC-SHA2 for
Kerberos 5") as such as well.

SP 800-57 Part 3 Rev. 1 from Jan 2015 [1] links the draft of what
became RFC 8009 in Oct 2016 as approved in section 6.3 Procurement
Guidance (item/recommendation 3).

[1] https://csrc.nist.gov/pubs/sp/800/57/pt3/r1/final

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
 crypto/testmgr.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 4d86efae65b2..7788e6fa80ce 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -4215,6 +4215,7 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.alg = "authenc(hmac(sha256),cts(cbc(aes)))",
 		.generic_driver = "authenc(hmac-sha256-lib,cts(cbc(aes-lib)))",
 		.test = alg_test_aead,
+		.fips_allowed = 1,
 		.suite = {
 			.aead = __VECS(krb5_test_aes128_cts_hmac_sha256_128)
 		}
@@ -4256,6 +4257,7 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.alg = "authenc(hmac(sha384),cts(cbc(aes)))",
 		.generic_driver = "authenc(hmac-sha384-lib,cts(cbc(aes-lib)))",
 		.test = alg_test_aead,
+		.fips_allowed = 1,
 		.suite = {
 			.aead = __VECS(krb5_test_aes256_cts_hmac_sha384_192)
 		}
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH 2/3] AF_ALG: Drop support for off-CPU cryptography
From: Harald Freudenberger @ 2026-06-03 13:33 UTC (permalink / raw)
  To: devnull+demiobenour.gmail.com
  Cc: acme, adrian.hunter, alexander.shishkin, ardb, axboe, corbet,
	davem, demiobenour, ebiggers, edumazet, herbert, horms, io-uring,
	irogers, james.clark, jolsa, kuba, kuniyu, linux-crypto,
	linux-doc, linux-kernel, linux-perf-users, mark.rutland, mingo,
	namhyung, netdev, pabeni, peterz, skhan, willemb, linux-s390
In-Reply-To: <20260523-af-alg-harden-v1-2-c76755c3a5c5@gmail.com>

> AF_ALG is deprecated and exposed to unprivileged userspace.  Only
> use the least buggy algorithm implementations: the pure software ones.
>

I thought AF_ALG is marked as deprecated but still usable. This patch
now actively disables groups of crypto implementations. Also it just
assumes that all algorithms which are asynchronously implemented or
do not have a fallback are to be disabled via AF_ALG.

There are may reasons for not having a synchronous implementation. For
example if you need to fetch (asynch) some information from a HSM before
doing the job of the algorithm. Also all secure key operations can't
by definition run directly on the CPU but need to be fed into some
hardware. Same is true with just acceleration - and acceleration via
special hardware (crypto hw, or AI hardware for example) is very common
on platforms priced by CPU cycles.

I also can't find any arguments for the statement 'Hardware accelerator
drivers are frequently buggy.' Does this mean that the linux kernel
from now on will not accept any hardware accelerator drivers any more?
Statements about code quality should be addressed to the driver
maintainer but not lead to tagging of groups of drivers.

I can understand that the AF_ALG shall be deprecated and fade away.
But this patch out of the sudden disables the long standing AF_ALG
interface at least for testing purpose and causes some failures in
the s390 crypto test area without any chance to react at all.

> This removes one of the main advantages of AF_ALG, which is the
> ability to use it with off-CPU accelerators.  However, using off-CPU
> accelerators has huge overheads, both in performance and attack surface.
> I have yet to see real-world, performance-critical workloads where using
> an accelerator via AF_ALG is actually a win over doing cryptography in
> userspace.
>
> If using an off-CPU accelerator really does turn out to be a win, a new
> API should be developed that is actually a good fit for it.
>
> Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
> ---
>  Documentation/crypto/userspace-if.rst |  7 ++++++-
>  crypto/af_alg.c                       |  2 +-
>  crypto/algif_aead.c                   |  4 ++--
>  crypto/algif_hash.c                   |  4 ++--
>  crypto/algif_rng.c                    |  4 ++--
>  crypto/algif_skcipher.c               |  4 ++--
>  include/crypto/if_alg.h               | 14 +++++++++++++-
>  7 files changed, 28 insertions(+), 11 deletions(-)
>
> diff --git a/Documentation/crypto/userspace-if.rst b/Documentation/crypto/userspace-if.rst
> index ea1b1b3f4049fd4673528dc2a6234f6376a3489f..b31117d4415dda6ad6ca36275e615bec7df9552e 100644
> --- a/Documentation/crypto/userspace-if.rst
> +++ b/Documentation/crypto/userspace-if.rst
> @@ -9,7 +9,8 @@ symmetric cipher, AEAD, and RNG algorithms that are implemented in kernel-mode
>  code.
>
>  AF_ALG is insecure and is deprecated. Originally added to the kernel in 2010,
> -most kernel developers now consider it to be a mistake.
> +most kernel developers now consider it to be a mistake. Support for hardware
> +accelerators, which was the original purpose of AF_ALG, has been removed.
>
>  AF_ALG continues to be supported only for backwards compatibility. On systems
>  where no programs using AF_ALG remain, the support for it should be disabled by
> @@ -59,6 +60,10 @@ Some of the examples include:
>  - CVE-2013-7421
>  - CVE-2011-4081
>
> +Hardware accelerator drivers are frequently buggy. To reduce attack surface,
> +AF_ALG now only provides access to algorithms implemented in software. This
> +means that AF_ALG no longer fulfills its original purpose.
> +
>  It is recommended that, whenever possible, userspace programs be migrated to
>  userspace crypto code (which again, is what is normally used anyway) and
>  ``CONFIG_CRYPTO_USER_API_*`` be disabled.  On systems that use SELinux, SELinux
> diff --git a/crypto/af_alg.c b/crypto/af_alg.c
> index 8ccf7a737cd6ca9a5d5bf47050c9afea0dfd61bf..cce000e8590e469927b5a5a0ceccfdf0ef54633d 100644
> --- a/crypto/af_alg.c
> +++ b/crypto/af_alg.c
> @@ -181,7 +181,7 @@ static int alg_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int add
>	if (IS_ERR(type))
>		return PTR_ERR(type);
>
> -	private = type->bind(sa->salg_name, sa->salg_feat, sa->salg_mask);
> +	private = type->bind(sa->salg_name);
>	if (IS_ERR(private)) {
>		module_put(type->owner);
>		return PTR_ERR(private);
> diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
> index 60f06597cb0b13036bc975641a0b02ea8a41ad03..787aac8aeb24eed128f08345ba730478113919b3 100644
> --- a/crypto/algif_aead.c
> +++ b/crypto/algif_aead.c
> @@ -342,9 +342,9 @@ static struct proto_ops algif_aead_ops_nokey = {
>	.poll		=	af_alg_poll,
>  };
>
> -static void *aead_bind(const char *name, u32 type, u32 mask)
> +static void *aead_bind(const char *name)
>  {
> -	return crypto_alloc_aead(name, type, mask);
> +	return crypto_alloc_aead(name, 0, AF_ALG_CRYPTOAPI_MASK);
>  }
>
>  static void aead_release(void *private)
> diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
> index 4d3dfc60a16a6d8b677d903d209df18d67202c98..5452ad6c15069c3cb0ff78fe58868fe7ce4b0fc3 100644
> --- a/crypto/algif_hash.c
> +++ b/crypto/algif_hash.c
> @@ -380,9 +380,9 @@ static struct proto_ops algif_hash_ops_nokey = {
>	.accept		=	hash_accept_nokey,
>  };
>
> -static void *hash_bind(const char *name, u32 type, u32 mask)
> +static void *hash_bind(const char *name)
>  {
> -	return crypto_alloc_ahash(name, type, mask);
> +	return crypto_alloc_ahash(name, 0, AF_ALG_CRYPTOAPI_MASK);
>  }
>
>  static void hash_release(void *private)
> diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c
> index a9fb492e929a70c94476f296f5f5e7c42f0313b7..4dfe7899f8fa4ce82d5f2236297230fb44bc35d6 100644
> --- a/crypto/algif_rng.c
> +++ b/crypto/algif_rng.c
> @@ -197,7 +197,7 @@ static struct proto_ops __maybe_unused algif_rng_test_ops = {
>	.sendmsg	=	rng_test_sendmsg,
>  };
>
> -static void *rng_bind(const char *name, u32 type, u32 mask)
> +static void *rng_bind(const char *name)
>  {
>	struct rng_parent_ctx *pctx;
>	struct crypto_rng *rng;
> @@ -206,7 +206,7 @@ static void *rng_bind(const char *name, u32 type, u32 mask)
>	if (!pctx)
>		return ERR_PTR(-ENOMEM);
>
> -	rng = crypto_alloc_rng(name, type, mask);
> +	rng = crypto_alloc_rng(name, 0, AF_ALG_CRYPTOAPI_MASK);
>	if (IS_ERR(rng)) {
>		kfree(pctx);
>		return ERR_CAST(rng);
> diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
> index 9dbccabd87b13920c27aff5a450a235cc6a27d59..df20bdfe1f1f4e453782dee3b743dd1939ab4c6c 100644
> --- a/crypto/algif_skcipher.c
> +++ b/crypto/algif_skcipher.c
> @@ -307,9 +307,9 @@ static struct proto_ops algif_skcipher_ops_nokey = {
>	.poll		=	af_alg_poll,
>  };
>
> -static void *skcipher_bind(const char *name, u32 type, u32 mask)
> +static void *skcipher_bind(const char *name)
>  {
> -	return crypto_alloc_skcipher(name, type, mask);
> +	return crypto_alloc_skcipher(name, 0, AF_ALG_CRYPTOAPI_MASK);
>  }
>
>  static void skcipher_release(void *private)
> diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
> index 62867daca47d76c9ea1a7ed233188788c5f6c3c0..7643ba954125aba0c06aaf19de087985325885ad 100644
> --- a/include/crypto/if_alg.h
> +++ b/include/crypto/if_alg.h
> @@ -41,7 +41,7 @@ struct af_alg_control {
>  };
>
>  struct af_alg_type {
> -	void *(*bind)(const char *name, u32 type, u32 mask);
> +	void *(*bind)(const char *name);
>	void (*release)(void *private);
>	int (*setkey)(void *private, const u8 *key, unsigned int keylen);
>	int (*setentropy)(void *private, sockptr_t entropy, unsigned int len);
> @@ -243,4 +243,16 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags,
>		    struct af_alg_async_req *areq, size_t maxsize,
>		    size_t *outlen);
>
> +/*
> + * Mask used to disable unsupported algorithm implementations.
> + *
> + * This is the same as FSCRYPT_CRYPTOAPI_MASK in fs/crypto/fscrypt_private.h.
> + * In additions to the motivations there, this API is exposed to userspace
> + * that might not be fully trusted.
> + */
> +#define AF_ALG_CRYPTOAPI_MASK                             \
> +	(CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY | \
> +	 CRYPTO_ALG_KERN_DRIVER_ONLY)
> +
> +
>  #endif	/* _CRYPTO_IF_ALG_H */
>
> --
> 2.54.0
>

Harald Freudenberger

^ permalink raw reply

* Re: [PATCH] MAINTAINERS: make myself the maintainer of the Qualcomm QCE driver
From: Konrad Dybcio @ 2026-06-03 11:35 UTC (permalink / raw)
  To: Bartosz Golaszewski, Demi Marie Obenour, Herbert Xu,
	David S. Miller, Thara Gopinath, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, Russell King,
	Eric Biggers, Ard Biesheuvel, Kuldeep Singh
  Cc: linux-crypto, linux-arm-msm, linux-kernel, brgl
In-Reply-To: <20260602-qcom-qce-broken-v1-1-a4ef756089e0@oss.qualcomm.com>



On 02-Jun-26 14:46, Bartosz Golaszewski wrote:
> Qualcomm wants to keep supporting and extending the crypto engine driver.
> Thara has not been active for many months, so change the maintainer to
> myself and upgrade the driver to Supported.
> 
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> ---

Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

Konrad

^ permalink raw reply

* [PATCH] hwrng: jh7110: fix refcount leak in starfive_trng_read()
From: Wentao Liang @ 2026-06-03 11:03 UTC (permalink / raw)
  To: jiajie.ho, olivia, herbert
  Cc: linux-crypto, linux-kernel, Wentao Liang, stable

The starfive_trng_read() function acquires a runtime PM reference
via pm_runtime_get_sync() but fails to release it on two error
paths.  If starfive_trng_wait_idle() or starfive_trng_cmd() returns
an error, the function exits without calling
pm_runtime_put_sync_autosuspend(), leaving the runtime PM usage
counter permanently elevated and preventing the device from entering
runtime suspend.

Refactor the function to use a unified error path that calls
pm_runtime_put_sync_autosuspend() before returning.

Cc: stable@vger.kernel.org
Fixes: c388f458bc34 ("hwrng: starfive - Add TRNG driver for StarFive SoC")
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
---
 drivers/char/hw_random/jh7110-trng.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/char/hw_random/jh7110-trng.c b/drivers/char/hw_random/jh7110-trng.c
index 9776f4daa044..4712c3c530e4 100644
--- a/drivers/char/hw_random/jh7110-trng.c
+++ b/drivers/char/hw_random/jh7110-trng.c
@@ -256,19 +256,22 @@ static int starfive_trng_read(struct hwrng *rng, void *buf, size_t max, bool wai
 
 	if (wait) {
 		ret = starfive_trng_wait_idle(trng);
-		if (ret)
-			return -ETIMEDOUT;
+		if (ret) {
+			ret = -ETIMEDOUT;
+			goto out_put;
+		}
 	}
 
 	ret = starfive_trng_cmd(trng, STARFIVE_CTRL_GENE_RANDNUM, wait);
 	if (ret)
-		return ret;
+		goto out_put;
 
 	memcpy_fromio(buf, trng->base + STARFIVE_RAND0, max);
+	ret = max;
 
+out_put:
 	pm_runtime_put_sync_autosuspend(trng->dev);
-
-	return max;
+	return ret;
 }
 
 static int starfive_trng_probe(struct platform_device *pdev)
-- 
2.34.1


^ permalink raw reply related

* [PATCH 5.10] crypto: lzo - Fix compression buffer overrun
From: Viktoriya Danchenko @ 2026-06-03  9:42 UTC (permalink / raw)
  To: lvc-project, David S. Miller, David Sterba, Herbert Xu,
	linux-crypto

From: Herbert Xu <herbert@gondor.apana.org.au>

[ Upstream commit cc47f07234f72cbd8e2c973cdbf2a6730660a463 ]

Unlike the decompression code, the compression code in LZO never
checked for output overruns.  It instead assumes that the caller
always provides enough buffer space, disregarding the buffer length
provided by the caller.

Add a safe compression interface that checks for the end of buffer
before each write.  Use the safe interface in crypto/lzo.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Roman Smirnov <r.smirnov@omp.ru>
Fixes: 64c70b1cf43d ("Add LZO1X algorithm to the kernel")
Signed-off-by: Viktoriya Danchenko <v.danchenko@omp.ru>
---
Backport fix for CVE-2025-38068
---
 crypto/lzo-rle.c              |   2 +-
 crypto/lzo.c                  |   2 +-
 include/linux/lzo.h           |   8 +++
 lib/lzo/Makefile              |   2 +-
 lib/lzo/lzo1x_compress.c      | 101 +++++++++++++++++++++++++---------
 lib/lzo/lzo1x_compress_safe.c |  18 ++++++
 6 files changed, 105 insertions(+), 28 deletions(-)
 create mode 100644 lib/lzo/lzo1x_compress_safe.c

diff --git a/crypto/lzo-rle.c b/crypto/lzo-rle.c
index 0631d975bfac..0abc2d87f042 100644
--- a/crypto/lzo-rle.c
+++ b/crypto/lzo-rle.c
@@ -55,7 +55,7 @@ static int __lzorle_compress(const u8 *src, unsigned int slen,
 	size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
 	int err;
 
-	err = lzorle1x_1_compress(src, slen, dst, &tmp_len, ctx);
+	err = lzorle1x_1_compress_safe(src, slen, dst, &tmp_len, ctx);
 
 	if (err != LZO_E_OK)
 		return -EINVAL;
diff --git a/crypto/lzo.c b/crypto/lzo.c
index ebda132dd22b..8338851c7406 100644
--- a/crypto/lzo.c
+++ b/crypto/lzo.c
@@ -55,7 +55,7 @@ static int __lzo_compress(const u8 *src, unsigned int slen,
 	size_t tmp_len = *dlen; /* size_t(ulong) <-> uint on 64 bit */
 	int err;
 
-	err = lzo1x_1_compress(src, slen, dst, &tmp_len, ctx);
+	err = lzo1x_1_compress_safe(src, slen, dst, &tmp_len, ctx);
 
 	if (err != LZO_E_OK)
 		return -EINVAL;
diff --git a/include/linux/lzo.h b/include/linux/lzo.h
index e95c7d1092b2..4d30e3624acd 100644
--- a/include/linux/lzo.h
+++ b/include/linux/lzo.h
@@ -24,10 +24,18 @@
 int lzo1x_1_compress(const unsigned char *src, size_t src_len,
 		     unsigned char *dst, size_t *dst_len, void *wrkmem);
 
+/* Same as above but does not write more than dst_len to dst. */
+int lzo1x_1_compress_safe(const unsigned char *src, size_t src_len,
+			  unsigned char *dst, size_t *dst_len, void *wrkmem);
+
 /* This requires 'wrkmem' of size LZO1X_1_MEM_COMPRESS */
 int lzorle1x_1_compress(const unsigned char *src, size_t src_len,
 		     unsigned char *dst, size_t *dst_len, void *wrkmem);
 
+/* Same as above but does not write more than dst_len to dst. */
+int lzorle1x_1_compress_safe(const unsigned char *src, size_t src_len,
+			     unsigned char *dst, size_t *dst_len, void *wrkmem);
+
 /* safe decompression with overrun testing */
 int lzo1x_decompress_safe(const unsigned char *src, size_t src_len,
 			  unsigned char *dst, size_t *dst_len);
diff --git a/lib/lzo/Makefile b/lib/lzo/Makefile
index 2f58fafbbddd..fc7b2b7ef4b2 100644
--- a/lib/lzo/Makefile
+++ b/lib/lzo/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-lzo_compress-objs := lzo1x_compress.o
+lzo_compress-objs := lzo1x_compress.o lzo1x_compress_safe.o
 lzo_decompress-objs := lzo1x_decompress_safe.o
 
 obj-$(CONFIG_LZO_COMPRESS) += lzo_compress.o
diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c
index 8ad5ba2b86e2..941d7337f273 100644
--- a/lib/lzo/lzo1x_compress.c
+++ b/lib/lzo/lzo1x_compress.c
@@ -18,11 +18,22 @@
 #include <linux/lzo.h>
 #include "lzodefs.h"
 
-static noinline size_t
-lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
-		    unsigned char *out, size_t *out_len,
-		    size_t ti, void *wrkmem, signed char *state_offset,
-		    const unsigned char bitstream_version)
+#undef LZO_UNSAFE
+
+#ifndef LZO_SAFE
+#define LZO_UNSAFE 1
+#define LZO_SAFE(name) name
+#define HAVE_OP(x) 1
+#endif
+
+#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun
+
+static noinline int
+LZO_SAFE(lzo1x_1_do_compress)(const unsigned char *in, size_t in_len,
+			      unsigned char **out, unsigned char *op_end,
+			      size_t *tp, void *wrkmem,
+			      signed char *state_offset,
+			      const unsigned char bitstream_version)
 {
 	const unsigned char *ip;
 	unsigned char *op;
@@ -30,8 +41,9 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
 	const unsigned char * const ip_end = in + in_len - 20;
 	const unsigned char *ii;
 	lzo_dict_t * const dict = (lzo_dict_t *) wrkmem;
+	size_t ti = *tp;
 
-	op = out;
+	op = *out;
 	ip = in;
 	ii = ip;
 	ip += ti < 4 ? 4 - ti : 0;
@@ -118,25 +130,32 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
 		if (t != 0) {
 			if (t <= 3) {
 				op[*state_offset] |= t;
+				NEED_OP(4);
 				COPY4(op, ii);
 				op += t;
 			} else if (t <= 16) {
+				NEED_OP(17);
 				*op++ = (t - 3);
 				COPY8(op, ii);
 				COPY8(op + 8, ii + 8);
 				op += t;
 			} else {
 				if (t <= 18) {
+					NEED_OP(1);
 					*op++ = (t - 3);
 				} else {
 					size_t tt = t - 18;
+					NEED_OP(1);
 					*op++ = 0;
 					while (unlikely(tt > 255)) {
 						tt -= 255;
+						NEED_OP(1);
 						*op++ = 0;
 					}
+					NEED_OP(1);
 					*op++ = tt;
 				}
+				NEED_OP(t);
 				do {
 					COPY8(op, ii);
 					COPY8(op + 8, ii + 8);
@@ -153,6 +172,7 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
 		if (unlikely(run_length)) {
 			ip += run_length;
 			run_length -= MIN_ZERO_RUN_LENGTH;
+			NEED_OP(4);
 			put_unaligned_le32((run_length << 21) | 0xfffc18
 					   | (run_length & 0x7), op);
 			op += 4;
@@ -245,10 +265,12 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
 		ip += m_len;
 		if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {
 			m_off -= 1;
+			NEED_OP(2);
 			*op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2));
 			*op++ = (m_off >> 3);
 		} else if (m_off <= M3_MAX_OFFSET) {
 			m_off -= 1;
+			NEED_OP(1);
 			if (m_len <= M3_MAX_LEN)
 				*op++ = (M3_MARKER | (m_len - 2));
 			else {
@@ -256,14 +278,18 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
 				*op++ = M3_MARKER | 0;
 				while (unlikely(m_len > 255)) {
 					m_len -= 255;
+					NEED_OP(1);
 					*op++ = 0;
 				}
+				NEED_OP(1);
 				*op++ = (m_len);
 			}
+			NEED_OP(2);
 			*op++ = (m_off << 2);
 			*op++ = (m_off >> 6);
 		} else {
 			m_off -= 0x4000;
+			NEED_OP(1);
 			if (m_len <= M4_MAX_LEN)
 				*op++ = (M4_MARKER | ((m_off >> 11) & 8)
 						| (m_len - 2));
@@ -284,11 +310,14 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
 				m_len -= M4_MAX_LEN;
 				*op++ = (M4_MARKER | ((m_off >> 11) & 8));
 				while (unlikely(m_len > 255)) {
+					NEED_OP(1);
 					m_len -= 255;
 					*op++ = 0;
 				}
+				NEED_OP(1);
 				*op++ = (m_len);
 			}
+			NEED_OP(2);
 			*op++ = (m_off << 2);
 			*op++ = (m_off >> 6);
 		}
@@ -297,14 +326,20 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len,
 		ii = ip;
 		goto next;
 	}
-	*out_len = op - out;
-	return in_end - (ii - ti);
+	*out = op;
+	*tp = in_end - (ii - ti);
+	return LZO_E_OK;
+
+output_overrun:
+	return LZO_E_OUTPUT_OVERRUN;
 }
 
-int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
-		     unsigned char *out, size_t *out_len,
-		     void *wrkmem, const unsigned char bitstream_version)
+static int LZO_SAFE(lzogeneric1x_1_compress)(
+	const unsigned char *in, size_t in_len,
+	unsigned char *out, size_t *out_len,
+	void *wrkmem, const unsigned char bitstream_version)
 {
+	unsigned char * const op_end = out + *out_len;
 	const unsigned char *ip = in;
 	unsigned char *op = out;
 	unsigned char *data_start;
@@ -312,6 +347,7 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
 	size_t t = 0;
 	signed char state_offset = -2;
 	unsigned int m4_max_offset;
+	int err;
 
 	// LZO v0 will never write 17 as first byte (except for zero-length
 	// input), so this is used to version the bitstream
@@ -332,10 +368,12 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
 			break;
 		BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS);
 		memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t));
-		t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem,
-					&state_offset, bitstream_version);
+		err = LZO_SAFE(lzo1x_1_do_compress)(
+			ip, ll, &op, op_end, &t, wrkmem,
+			&state_offset, bitstream_version);
+		if (err != LZO_E_OK)
+			return err;
 		ip += ll;
-		op += *out_len;
 		l  -= ll;
 	}
 	t += l;
@@ -344,20 +382,26 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
 		const unsigned char *ii = in + in_len - t;
 
 		if (op == data_start && t <= 238) {
+			NEED_OP(1);
 			*op++ = (17 + t);
 		} else if (t <= 3) {
 			op[state_offset] |= t;
 		} else if (t <= 18) {
+			NEED_OP(1);
 			*op++ = (t - 3);
 		} else {
 			size_t tt = t - 18;
+			NEED_OP(1);
 			*op++ = 0;
 			while (tt > 255) {
 				tt -= 255;
+				NEED_OP(1);
 				*op++ = 0;
 			}
+			NEED_OP(1);
 			*op++ = tt;
 		}
+		NEED_OP(t);
 		if (t >= 16) do {
 			COPY8(op, ii);
 			COPY8(op + 8, ii + 8);
@@ -370,31 +414,38 @@ int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len,
 		} while (--t > 0);
 	}
 
+	NEED_OP(3);
 	*op++ = M4_MARKER | 1;
 	*op++ = 0;
 	*op++ = 0;
 
 	*out_len = op - out;
 	return LZO_E_OK;
+
+output_overrun:
+	return LZO_E_OUTPUT_OVERRUN;
 }
 
-int lzo1x_1_compress(const unsigned char *in, size_t in_len,
-		     unsigned char *out, size_t *out_len,
-		     void *wrkmem)
+int LZO_SAFE(lzo1x_1_compress)(const unsigned char *in, size_t in_len,
+			       unsigned char *out, size_t *out_len,
+			       void *wrkmem)
 {
-	return lzogeneric1x_1_compress(in, in_len, out, out_len, wrkmem, 0);
+	return LZO_SAFE(lzogeneric1x_1_compress)(
+		in, in_len, out, out_len, wrkmem, 0);
 }
 
-int lzorle1x_1_compress(const unsigned char *in, size_t in_len,
-		     unsigned char *out, size_t *out_len,
-		     void *wrkmem)
+int LZO_SAFE(lzorle1x_1_compress)(const unsigned char *in, size_t in_len,
+				  unsigned char *out, size_t *out_len,
+				  void *wrkmem)
 {
-	return lzogeneric1x_1_compress(in, in_len, out, out_len,
-				       wrkmem, LZO_VERSION);
+	return LZO_SAFE(lzogeneric1x_1_compress)(
+		in, in_len, out, out_len, wrkmem, LZO_VERSION);
 }
 
-EXPORT_SYMBOL_GPL(lzo1x_1_compress);
-EXPORT_SYMBOL_GPL(lzorle1x_1_compress);
+EXPORT_SYMBOL_GPL(LZO_SAFE(lzo1x_1_compress));
+EXPORT_SYMBOL_GPL(LZO_SAFE(lzorle1x_1_compress));
 
+#ifndef LZO_UNSAFE
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("LZO1X-1 Compressor");
+#endif
diff --git a/lib/lzo/lzo1x_compress_safe.c b/lib/lzo/lzo1x_compress_safe.c
new file mode 100644
index 000000000000..371c9f849492
--- /dev/null
+++ b/lib/lzo/lzo1x_compress_safe.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  LZO1X Compressor from LZO
+ *
+ *  Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <markus@oberhumer.com>
+ *
+ *  The full LZO package can be found at:
+ *  http://www.oberhumer.com/opensource/lzo/
+ *
+ *  Changed for Linux kernel use by:
+ *  Nitin Gupta <nitingupta910@gmail.com>
+ *  Richard Purdie <rpurdie@openedhand.com>
+ */
+
+#define LZO_SAFE(name) name##_safe
+#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x))
+
+#include "lzo1x_compress.c"
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH] crypto: use two-argument strscpy where destination size is known
From: David Laight @ 2026-06-03  9:45 UTC (permalink / raw)
  To: Thorsten Blum
  Cc: Herbert Xu, David S. Miller, Tom Lendacky, John Allen, Weili Qian,
	Zhou Wang, Giovanni Cabiddu, Srujana Challa, Bharat Bhushan,
	linux-crypto, linux-kernel, qat-linux
In-Reply-To: <20260525103038.825690-4-thorsten.blum@linux.dev>

On Mon, 25 May 2026 12:30:41 +0200
Thorsten Blum <thorsten.blum@linux.dev> wrote:

> To simplify the code, drop explicit and hard-coded size arguments from
> strscpy() where the destination buffer has a fixed size and strscpy()
> can automatically determine it using sizeof().

I'm not entirely sure these changes are worth the churn.

A more interesting exercise might be to get the compiler to look
for places when the three argument form is used with the destination
being an array and the length a constant that doesn't match the
size of the array.
There might be some false positives, but the size shouldn't be larger.

Note that you can't rely on builtin_sizeof() to give you the actual
size of an array.
It just lets you overrun past the end of an array that ends and the
end of a structure you have a pointer to.
The size has to come from sizeof() as in the 2 argument form.

-- David

> 
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> ---
>  crypto/api.c                                             | 2 +-
>  crypto/crypto_user.c                                     | 9 ++++-----
>  crypto/hctr2.c                                           | 3 +--
>  crypto/lrw.c                                             | 2 +-
>  crypto/lskcipher.c                                       | 3 +--
>  crypto/xts.c                                             | 3 ++-
>  drivers/crypto/cavium/nitrox/nitrox_hal.c                | 3 ++-
>  drivers/crypto/ccp/ccp-crypto-sha.c                      | 2 +-
>  drivers/crypto/hisilicon/qm.c                            | 5 +----
>  drivers/crypto/intel/qat/qat_common/adf_cfg.c            | 7 ++++---
>  drivers/crypto/intel/qat/qat_common/adf_cfg_services.c   | 2 +-
>  drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c        | 3 ++-
>  drivers/crypto/intel/qat/qat_common/adf_mstate_mgr.c     | 3 ++-
>  .../crypto/intel/qat/qat_common/adf_transport_debug.c    | 3 ++-
>  drivers/crypto/intel/qat/qat_common/qat_compression.c    | 3 ++-
>  drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c        | 6 +++---
>  drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c      | 4 ++--
>  17 files changed, 32 insertions(+), 31 deletions(-)
> 
> diff --git a/crypto/api.c b/crypto/api.c
> index 74e17d5049c9..040b7a965c2f 100644
> --- a/crypto/api.c
> +++ b/crypto/api.c
> @@ -116,7 +116,7 @@ struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask)
>  	larval->alg.cra_priority = -1;
>  	larval->alg.cra_destroy = crypto_larval_destroy;
>  
> -	strscpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
> +	strscpy(larval->alg.cra_name, name);
>  	init_completion(&larval->completion);
>  
>  	return larval;
> diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
> index e8b6ae75f31f..d3ccb507153b 100644
> --- a/crypto/crypto_user.c
> +++ b/crypto/crypto_user.c
> @@ -11,6 +11,7 @@
>  #include <linux/cryptouser.h>
>  #include <linux/sched.h>
>  #include <linux/security.h>
> +#include <linux/string.h>
>  #include <net/netlink.h>
>  #include <net/net_namespace.h>
>  #include <net/sock.h>
> @@ -87,11 +88,9 @@ static int crypto_report_one(struct crypto_alg *alg,
>  {
>  	memset(ualg, 0, sizeof(*ualg));
>  
> -	strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
> -	strscpy(ualg->cru_driver_name, alg->cra_driver_name,
> -		sizeof(ualg->cru_driver_name));
> -	strscpy(ualg->cru_module_name, module_name(alg->cra_module),
> -		sizeof(ualg->cru_module_name));
> +	strscpy(ualg->cru_name, alg->cra_name);
> +	strscpy(ualg->cru_driver_name, alg->cra_driver_name);
> +	strscpy(ualg->cru_module_name, module_name(alg->cra_module));
>  
>  	ualg->cru_type = 0;
>  	ualg->cru_mask = 0;
> diff --git a/crypto/hctr2.c b/crypto/hctr2.c
> index ad5edf9366ac..cfc2343bcc1c 100644
> --- a/crypto/hctr2.c
> +++ b/crypto/hctr2.c
> @@ -354,8 +354,7 @@ static int hctr2_create_common(struct crypto_template *tmpl, struct rtattr **tb,
>  	err = -EINVAL;
>  	if (strncmp(xctr_alg->base.cra_name, "xctr(", 5))
>  		goto err_free_inst;
> -	len = strscpy(blockcipher_name, xctr_alg->base.cra_name + 5,
> -		      sizeof(blockcipher_name));
> +	len = strscpy(blockcipher_name, xctr_alg->base.cra_name + 5);
>  	if (len < 1)
>  		goto err_free_inst;
>  	if (blockcipher_name[len - 1] != ')')
> diff --git a/crypto/lrw.c b/crypto/lrw.c
> index aa31ab03a597..e306e85d7ced 100644
> --- a/crypto/lrw.c
> +++ b/crypto/lrw.c
> @@ -359,7 +359,7 @@ static int lrw_create(struct crypto_template *tmpl, struct rtattr **tb)
>  	if (!memcmp(cipher_name, "ecb(", 4)) {
>  		int len;
>  
> -		len = strscpy(ecb_name, cipher_name + 4, sizeof(ecb_name));
> +		len = strscpy(ecb_name, cipher_name + 4);
>  		if (len < 2)
>  			goto err_free_inst;
>  
> diff --git a/crypto/lskcipher.c b/crypto/lskcipher.c
> index e4328df6e26c..d7ec215e2b3a 100644
> --- a/crypto/lskcipher.c
> +++ b/crypto/lskcipher.c
> @@ -528,8 +528,7 @@ struct lskcipher_instance *lskcipher_alloc_instance_simple(
>  		int len;
>  
>  		err = -EINVAL;
> -		len = strscpy(ecb_name, &cipher_alg->co.base.cra_name[4],
> -			      sizeof(ecb_name));
> +		len = strscpy(ecb_name, &cipher_alg->co.base.cra_name[4]);
>  		if (len < 2)
>  			goto err_free_inst;
>  
> diff --git a/crypto/xts.c b/crypto/xts.c
> index ad97c8091582..1dc948745444 100644
> --- a/crypto/xts.c
> +++ b/crypto/xts.c
> @@ -16,6 +16,7 @@
>  #include <linux/module.h>
>  #include <linux/scatterlist.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  
>  #include <crypto/xts.h>
>  #include <crypto/b128ops.h>
> @@ -400,7 +401,7 @@ static int xts_create(struct crypto_template *tmpl, struct rtattr **tb)
>  	if (!memcmp(cipher_name, "ecb(", 4)) {
>  		int len;
>  
> -		len = strscpy(name, cipher_name + 4, sizeof(name));
> +		len = strscpy(name, cipher_name + 4);
>  		if (len < 2)
>  			goto err_free_inst;
>  
> diff --git a/drivers/crypto/cavium/nitrox/nitrox_hal.c b/drivers/crypto/cavium/nitrox/nitrox_hal.c
> index 1b5abdb6cc5e..e36c1741bb78 100644
> --- a/drivers/crypto/cavium/nitrox/nitrox_hal.c
> +++ b/drivers/crypto/cavium/nitrox/nitrox_hal.c
> @@ -1,5 +1,6 @@
>  // SPDX-License-Identifier: GPL-2.0
>  #include <linux/delay.h>
> +#include <linux/string.h>
>  
>  #include "nitrox_dev.h"
>  #include "nitrox_csr.h"
> @@ -647,7 +648,7 @@ void nitrox_get_hwinfo(struct nitrox_device *ndev)
>  		 ndev->hw.revision_id);
>  
>  	/* copy partname */
> -	strscpy(ndev->hw.partname, name, sizeof(ndev->hw.partname));
> +	strscpy(ndev->hw.partname, name);
>  }
>  
>  void enable_pf2vf_mbox_interrupts(struct nitrox_device *ndev)
> diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c
> index 85058a89f35b..ff9bb253dbb2 100644
> --- a/drivers/crypto/ccp/ccp-crypto-sha.c
> +++ b/drivers/crypto/ccp/ccp-crypto-sha.c
> @@ -426,7 +426,7 @@ static int ccp_register_hmac_alg(struct list_head *head,
>  	*ccp_alg = *base_alg;
>  	INIT_LIST_HEAD(&ccp_alg->entry);
>  
> -	strscpy(ccp_alg->child_alg, def->name, CRYPTO_MAX_ALG_NAME);
> +	strscpy(ccp_alg->child_alg, def->name);
>  
>  	alg = &ccp_alg->alg;
>  	alg->setkey = ccp_sha_setkey;
> diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
> index 3ca47e2a9719..0c8cc0d7a82a 100644
> --- a/drivers/crypto/hisilicon/qm.c
> +++ b/drivers/crypto/hisilicon/qm.c
> @@ -2870,11 +2870,8 @@ static int qm_alloc_uacce(struct hisi_qm *qm)
>  		.flags = UACCE_DEV_SVA,
>  		.ops = &uacce_qm_ops,
>  	};
> -	int ret;
>  
> -	ret = strscpy(interface.name, dev_driver_string(&pdev->dev),
> -		      sizeof(interface.name));
> -	if (ret < 0)
> +	if (strscpy(interface.name, dev_driver_string(&pdev->dev)) < 0)
>  		return -ENAMETOOLONG;
>  
>  	uacce = uacce_alloc(&pdev->dev, &interface);
> diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg.c b/drivers/crypto/intel/qat/qat_common/adf_cfg.c
> index c202209f17d5..24c2618af68d 100644
> --- a/drivers/crypto/intel/qat/qat_common/adf_cfg.c
> +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg.c
> @@ -2,6 +2,7 @@
>  /* Copyright(c) 2014 - 2020 Intel Corporation */
>  #include <linux/mutex.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include <linux/list.h>
>  #include <linux/seq_file.h>
>  #include "adf_accel_devices.h"
> @@ -294,13 +295,13 @@ int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev,
>  		return -ENOMEM;
>  
>  	INIT_LIST_HEAD(&key_val->list);
> -	strscpy(key_val->key, key, sizeof(key_val->key));
> +	strscpy(key_val->key, key);
>  
>  	if (type == ADF_DEC) {
>  		snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
>  			 "%ld", (*((long *)val)));
>  	} else if (type == ADF_STR) {
> -		strscpy(key_val->val, (char *)val, sizeof(key_val->val));
> +		strscpy(key_val->val, (char *)val);
>  	} else if (type == ADF_HEX) {
>  		snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
>  			 "0x%lx", (unsigned long)val);
> @@ -360,7 +361,7 @@ int adf_cfg_section_add(struct adf_accel_dev *accel_dev, const char *name)
>  	if (!sec)
>  		return -ENOMEM;
>  
> -	strscpy(sec->name, name, sizeof(sec->name));
> +	strscpy(sec->name, name);
>  	INIT_LIST_HEAD(&sec->param_head);
>  	down_write(&cfg->lock);
>  	list_add_tail(&sec->list, &cfg->sec_list);
> diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c
> index 7d00bcb41ce7..11cba347d12d 100644
> --- a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c
> +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c
> @@ -60,7 +60,7 @@ static int adf_service_string_to_mask(struct adf_accel_dev *accel_dev, const cha
>  	if (len > ADF_CFG_MAX_VAL_LEN_IN_BYTES - 1)
>  		return -EINVAL;
>  
> -	strscpy(services, buf, ADF_CFG_MAX_VAL_LEN_IN_BYTES);
> +	strscpy(services, buf);
>  	substr = services;
>  
>  	while ((token = strsep(&substr, ADF_SERVICES_DELIMITER))) {
> diff --git a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c
> index c2e6f0cb7480..ae10b91da5ba 100644
> --- a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c
> +++ b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c
> @@ -5,6 +5,7 @@
>  #include <linux/module.h>
>  #include <linux/mutex.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include <linux/fs.h>
>  #include <linux/bitops.h>
>  #include <linux/pci.h>
> @@ -350,7 +351,7 @@ static int adf_ctl_ioctl_get_status(struct file *fp, unsigned int cmd,
>  	dev_info.num_logical_accel = hw_data->num_logical_accel;
>  	dev_info.banks_per_accel = hw_data->num_banks
>  					/ hw_data->num_logical_accel;
> -	strscpy(dev_info.name, hw_data->dev_class->name, sizeof(dev_info.name));
> +	strscpy(dev_info.name, hw_data->dev_class->name);
>  	dev_info.instance_id = hw_data->instance_id;
>  	dev_info.type = hw_data->dev_class->type;
>  	dev_info.bus = accel_to_pci_dev(accel_dev)->bus->number;
> diff --git a/drivers/crypto/intel/qat/qat_common/adf_mstate_mgr.c b/drivers/crypto/intel/qat/qat_common/adf_mstate_mgr.c
> index f9017e03ec0f..32aeb795cc03 100644
> --- a/drivers/crypto/intel/qat/qat_common/adf_mstate_mgr.c
> +++ b/drivers/crypto/intel/qat/qat_common/adf_mstate_mgr.c
> @@ -2,6 +2,7 @@
>  /* Copyright(c) 2024 Intel Corporation */
>  
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include <linux/types.h>
>  #include "adf_mstate_mgr.h"
>  
> @@ -158,7 +159,7 @@ static struct adf_mstate_sect_h *adf_mstate_sect_add_header(struct adf_mstate_mg
>  		return NULL;
>  	}
>  
> -	strscpy(sect->id, id, sizeof(sect->id));
> +	strscpy(sect->id, id);
>  	sect->size = 0;
>  	sect->sub_sects = 0;
>  	mgr->state += sizeof(*sect);
> diff --git a/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c b/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c
> index a8f853516a3f..fc5d88a2bb17 100644
> --- a/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c
> +++ b/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c
> @@ -2,6 +2,7 @@
>  /* Copyright(c) 2014 - 2020 Intel Corporation */
>  #include <linux/mutex.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include <linux/seq_file.h>
>  #include "adf_accel_devices.h"
>  #include "adf_transport_internal.h"
> @@ -103,7 +104,7 @@ int adf_ring_debugfs_add(struct adf_etr_ring_data *ring, const char *name)
>  	if (!ring_debug)
>  		return -ENOMEM;
>  
> -	strscpy(ring_debug->ring_name, name, sizeof(ring_debug->ring_name));
> +	strscpy(ring_debug->ring_name, name);
>  	snprintf(entry_name, sizeof(entry_name), "ring_%02d",
>  		 ring->ring_number);
>  
> diff --git a/drivers/crypto/intel/qat/qat_common/qat_compression.c b/drivers/crypto/intel/qat/qat_common/qat_compression.c
> index 1424d7a9bcd3..8129ad0c32d8 100644
> --- a/drivers/crypto/intel/qat/qat_common/qat_compression.c
> +++ b/drivers/crypto/intel/qat/qat_common/qat_compression.c
> @@ -2,6 +2,7 @@
>  /* Copyright(c) 2022 Intel Corporation */
>  #include <linux/module.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include "adf_accel_devices.h"
>  #include "adf_common_drv.h"
>  #include "adf_transport.h"
> @@ -144,7 +145,7 @@ static int qat_compression_create_instances(struct adf_accel_dev *accel_dev)
>  	int i;
>  
>  	INIT_LIST_HEAD(&accel_dev->compression_list);
> -	strscpy(key, ADF_NUM_DC, sizeof(key));
> +	strscpy(key, ADF_NUM_DC);
>  	ret = adf_cfg_get_param_value(accel_dev, SEC, key, val);
>  	if (ret)
>  		return ret;
> diff --git a/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c b/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c
> index e0f38d32bc93..5c3636080757 100644
> --- a/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c
> +++ b/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c
> @@ -99,7 +99,7 @@ static int dev_supports_eng_type(struct otx_cpt_eng_grps *eng_grps,
>  static void set_ucode_filename(struct otx_cpt_ucode *ucode,
>  			       const char *filename)
>  {
> -	strscpy(ucode->filename, filename, OTX_CPT_UCODE_NAME_LENGTH);
> +	strscpy(ucode->filename, filename);
>  }
>  
>  static char *get_eng_type_str(int eng_type)
> @@ -140,7 +140,7 @@ static int get_ucode_type(struct otx_cpt_ucode_hdr *ucode_hdr, int *ucode_type)
>  	u32 i, val = 0;
>  	u8 nn;
>  
> -	strscpy(tmp_ver_str, ucode_hdr->ver_str, OTX_CPT_UCODE_VER_STR_SZ);
> +	strscpy(tmp_ver_str, ucode_hdr->ver_str);
>  	for (i = 0; i < strlen(tmp_ver_str); i++)
>  		tmp_ver_str[i] = tolower(tmp_ver_str[i]);
>  
> @@ -1331,7 +1331,7 @@ static ssize_t ucode_load_store(struct device *dev,
>  
>  	eng_grps = container_of(attr, struct otx_cpt_eng_grps, ucode_load_attr);
>  	err_msg = "Invalid engine group format";
> -	strscpy(tmp_buf, buf, OTX_CPT_UCODE_NAME_LENGTH);
> +	strscpy(tmp_buf, buf);
>  	start = tmp_buf;
>  
>  	has_se = has_ie = has_ae = false;
> diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
> index 9b0887d7e62c..465f00e74623 100644
> --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
> +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
> @@ -74,7 +74,7 @@ static int is_2nd_ucode_used(struct otx2_cpt_eng_grp_info *eng_grp)
>  static void set_ucode_filename(struct otx2_cpt_ucode *ucode,
>  			       const char *filename)
>  {
> -	strscpy(ucode->filename, filename, OTX2_CPT_NAME_LENGTH);
> +	strscpy(ucode->filename, filename);
>  }
>  
>  static char *get_eng_type_str(int eng_type)
> @@ -130,7 +130,7 @@ static int get_ucode_type(struct device *dev,
>  	int i, val = 0;
>  	u8 nn;
>  
> -	strscpy(tmp_ver_str, ucode_hdr->ver_str, OTX2_CPT_UCODE_VER_STR_SZ);
> +	strscpy(tmp_ver_str, ucode_hdr->ver_str);
>  	for (i = 0; i < strlen(tmp_ver_str); i++)
>  		tmp_ver_str[i] = tolower(tmp_ver_str[i]);
>  
> 


^ permalink raw reply

* [PATCH v3] crypto/algapi: fix refcount leak in crypto_register_alg()
From: Wentao Liang @ 2026-06-03  8:21 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, linux-kernel, Wentao Liang, stable

When crypto_register_alg() calls crypto_check_alg() successfully,
the algorithm's refcount is set to one.  If the subsequent handling
for CRYPTO_ALG_DUP_FIRST fails with ENOMEM due to a kmemdup()
error, the function returns without decrementing the refcount.
This leaves the algorithm forever pinned with a leaked reference.

Fix it by calling crypto_alg_put() on the kmemdup() failure path,
matching the error handling used elsewhere in the function.

Cc: stable@vger.kernel.org
Fixes: f1440a90465b ("crypto: api - Add support for duplicating algorithms before registration")
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>

---
Changes in v2:
- Clarify the refcount lifecycle.
- Fix code error.
---
 crypto/algapi.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/crypto/algapi.c b/crypto/algapi.c
index 37de377719ae..260d03b328ec 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -446,8 +446,10 @@ int crypto_register_alg(struct crypto_alg *alg)
 		u8 *p = (u8 *)alg - algsize;
 
 		p = kmemdup(p, algsize + sizeof(*alg), GFP_KERNEL);
-		if (!p)
+		if (!p) {
+			crypto_alg_put(alg);
 			return -ENOMEM;
+		}
 
 		alg = (void *)(p + algsize);
 		alg->cra_destroy = crypto_free_alg;
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2] crypto: fix refcount leak in crypto_register_alg()
From: Wentao Liang @ 2026-06-03  8:15 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, linux-kernel, Wentao Liang, stable

When crypto_check_alg() succeeds it sets the algorithm's refcount
to 1. In crypto_register_alg(), if the algorithm type requires
duplication (CRYPTO_ALG_DUP_FIRST), the code attempts a kmemdup of
the algorithm descriptor. If that allocation fails the function
returns -ENOMEM without calling crypto_alg_put() to release the
reference obtained by crypto_check_alg(), resulting in a refcount
leak.

Fix this by adding the missing crypto_alg_put() before the early
return, matching the handling of the other error paths in the
function.

Cc: stable@vger.kernel.org
Fixes: f1440a90465b ("crypto: api - Add support for duplicating algorithms before registration")
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
---
Changes in v2:
- Clarify the refcount lifecycle.
- Fix code error.
---
 crypto/algapi.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/crypto/algapi.c b/crypto/algapi.c
index b0e4b13131c3..260d03b328ec 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -446,9 +446,10 @@ int crypto_register_alg(struct crypto_alg *alg)
 		u8 *p = (u8 *)alg - algsize;
 
 		p = kmemdup(p, algsize + sizeof(*alg), GFP_KERNEL);
-		if (!p)
+		if (!p) {
 			crypto_alg_put(alg);
 			return -ENOMEM;
+		}
 
 		alg = (void *)(p + algsize);
 		alg->cra_destroy = crypto_free_alg;
-- 
2.34.1


^ permalink raw reply related

* 回复: [PATCH v3 1/2] dt-bindings: rng: starfive,jh7110-trng: add jhb100, drop jh8100
From: Lianfeng Ouyang @ 2026-06-03  5:29 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Olivia Mackall, Herbert Xu, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, linux-crypto@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <20260602-staple-rehire-00045d4cb667@spud>



> -----邮件原件-----
> 发件人: Conor Dooley <conor@kernel.org>
> 发送时间: 2026年6月3日 0:59
> 收件人: Lianfeng Ouyang <lianfeng.ouyang@starfivetech.com>
> 抄送: Olivia Mackall <olivia@selenic.com>; Herbert Xu
> <herbert@gondor.apana.org.au>; Rob Herring <robh@kernel.org>; Krzysztof
> Kozlowski <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Philipp
> Zabel <p.zabel@pengutronix.de>; linux-crypto@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org
> 主题: Re: [PATCH v3 1/2] dt-bindings: rng: starfive,jh7110-trng: add jhb100, drop
> jh8100
> 
> On Mon, Jun 01, 2026 at 05:37:43PM +0800, lianfeng.ouyang wrote:
> > From: Lianfeng Ouyang <lianfeng.ouyang@starfivetech.com>
> >
> > - Drop "starfive,jh8100-trng" since JH8100 SoC is no longer
> >   supported
> > - Add "starfive,jhb100-trng" for the JHB100 SoC TRNG.
> > - Update maintainer to current owner
> >
> > Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang@starfivetech.com>
> 
> Acked-by: Conor Dooley <conor.dooley@microchip.com>
> pw-bot: not-applicable
> 
> Although, commit messages really should not be bullet point lists,
> please keep that in mind for the future.


Thanks for the review. I'll make some changes

Best Regards,
Lianfeng Ouyang

^ permalink raw reply

* Re: [PATCH net-next v2 0/5] Consolidate FCrypt and PCBC code into net/rxrpc/
From: Eric Biggers @ 2026-06-03  5:05 UTC (permalink / raw)
  To: Marc Dionne
  Cc: netdev, linux-afs, David Howells, linux-crypto, linux-kernel,
	David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman
In-Reply-To: <CAB9dFduBir-41_Ef4noEJPHsFU-++JHDxMU-6S7B8pBYynvadA@mail.gmail.com>

On Fri, May 22, 2026 at 10:06:49AM -0300, Marc Dionne wrote:
> On Fri, May 22, 2026 at 2:07 AM Eric Biggers <ebiggers@kernel.org> wrote:
> >
> > The FCrypt "block cipher" and the PCBC mode of operation are obsolete
> > and insecure.  Since their only user is net/rxrpc/, they belong there,
> > not in the crypto API.
> >
> > Therefore, this series removes these algorithms from the crypto API and
> > replaces them with local implementations in net/rxrpc/.
> >
> > The local implementations are simpler too, as they avoid the crypto API
> > boilerplate.
> >
> > I don't know how to test all the code in net/rxrpc/, but everything
> > should still work.  I added a KUnit test for the crypto functions.
> >
> > Changed in v2:
> >     - Added missing export of fcrypt_preparekey().
> >     - Write "RxRPC crypto KUnit test" instead of "RxRPC KUnit test".
> >     - Rebased onto latest net-next where decryption now happens in the
> >       linear buffer rxrpc_call::rx_dec_buffer, simplifying the code.
> 
> Looks good in testing with our kafs test suite, forcing the use of
> rxkad with encryption.
> 
> Feel free to add for the series:
> Tested-by: Marc Dionne <marc.dionne@auristor.com>

Thanks!

If there's no more feedback, could this be applied to net-next?

- Eric

^ permalink raw reply

* Re: [PATCH] crypto/algapi: fix refcount leak in crypto_register_alg()
From: Herbert Xu @ 2026-06-03  2:47 UTC (permalink / raw)
  To: Wentao Liang; +Cc: davem, linux-crypto, linux-kernel, stable
In-Reply-To: <20260603024119.3693829-1-vulab@iscas.ac.cn>

On Wed, Jun 03, 2026 at 02:41:19AM +0000, Wentao Liang wrote:
> In crypto_register_alg(), if the algorithm registration fails after
> a successful crypto_alg_get() on the template algorithm, the acquired
> reference is never released. This can occur when the new algorithm is
> not allowed to be registered due to a constraint check failure.
> 
> Fix the leak by adding a corresponding crypto_alg_put() call in the
> error path before returning.
> 
> Cc: stable@vger.kernel.org
> Fixes: f1440a90465b ("crypto: api - Add support for duplicating algorithms before registration")
> Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
> ---
>  crypto/algapi.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/crypto/algapi.c b/crypto/algapi.c
> index 37de377719ae..b0e4b13131c3 100644
> --- a/crypto/algapi.c
> +++ b/crypto/algapi.c
> @@ -447,6 +447,7 @@ int crypto_register_alg(struct crypto_alg *alg)
>  
>  		p = kmemdup(p, algsize + sizeof(*alg), GFP_KERNEL);
>  		if (!p)
> +			crypto_alg_put(alg);
>  			return -ENOMEM;

Where is this reference count coming from?
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* [PATCH] crypto/algapi: fix refcount leak in crypto_register_alg()
From: Wentao Liang @ 2026-06-03  2:41 UTC (permalink / raw)
  To: herbert, davem; +Cc: linux-crypto, linux-kernel, Wentao Liang, stable

In crypto_register_alg(), if the algorithm registration fails after
a successful crypto_alg_get() on the template algorithm, the acquired
reference is never released. This can occur when the new algorithm is
not allowed to be registered due to a constraint check failure.

Fix the leak by adding a corresponding crypto_alg_put() call in the
error path before returning.

Cc: stable@vger.kernel.org
Fixes: f1440a90465b ("crypto: api - Add support for duplicating algorithms before registration")
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
---
 crypto/algapi.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/crypto/algapi.c b/crypto/algapi.c
index 37de377719ae..b0e4b13131c3 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -447,6 +447,7 @@ int crypto_register_alg(struct crypto_alg *alg)
 
 		p = kmemdup(p, algsize + sizeof(*alg), GFP_KERNEL);
 		if (!p)
+			crypto_alg_put(alg);
 			return -ENOMEM;
 
 		alg = (void *)(p + algsize);
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 4/4] crypto: ccp: Fix memory leak in SEV INIT_EX path
From: Atish Patra @ 2026-06-02 22:36 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini, Borislav Petkov, Dave Hansen,
	x86, H. Peter Anvin, Tom Lendacky, Peter Gonda, Brijesh Singh,
	Youngjae Lee, Ashish Kalra, Michael Roth, John Allen, Herbert Xu
  Cc: clm, kvm, linux-kernel, linux-crypto, stable, Atish Patra,
	Sashiko
In-Reply-To: <20260602-sev_snp_fixes-v3-0-24bfd3ae047c@meta.com>

From: Atish Patra <atishp@meta.com>

allocated pages in _init_ext_path are never freed and sev_init_ex_buffer
is left pointing at the leaked memory in case of any failures during the
function..

Fix by adding an error path that frees the pages and clears
sev_init_ex_buffer. Make sure we only free the memory if the failure
happens before the conversion. Otherwise, we may end up trying to free
up converted pages in case of reclaim failure. rmp_mark_pages_firmware
failures should be rare enough to avoid more code complexity to track
down which pages were reclaimed/leaked vs which are not.

Fixes: 7364a6fbca45 ("crypto: ccp: Handle non-volatile INIT_EX data when SNP is enabled")

Reported-by: Sashiko <sashiko-bot@kernel.org>
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Atish Patra <atishp@meta.com>
---
 drivers/crypto/ccp/sev-dev.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index 3d4793e8e34b..57b4c1e79589 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -1540,7 +1540,7 @@ static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
 	if (sev_init_ex_buffer)
 		return 0;
 
-	page = alloc_pages(GFP_KERNEL, get_order(NV_LENGTH));
+	page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(NV_LENGTH));
 	if (!page) {
 		dev_err(sev->dev, "SEV: INIT_EX NV memory allocation failed\n");
 		return -ENOMEM;
@@ -1550,7 +1550,7 @@ static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
 
 	rc = sev_read_init_ex_file();
 	if (rc)
-		return rc;
+		goto err_free;
 
 	/* If SEV-SNP is initialized, transition to firmware page. */
 	if (sev->snp_initialized) {
@@ -1559,11 +1559,22 @@ static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
 		npages = 1UL << get_order(NV_LENGTH);
 		if (rmp_mark_pages_firmware(__pa(sev_init_ex_buffer), npages, true)) {
 			dev_err(sev->dev, "SEV: INIT_EX NV memory page state change failed.\n");
-			return -ENOMEM;
+			rc = -ENOMEM;
+			/*
+			 * Pages can be in an inconsistent state, don't release them back to the
+			 * system.
+			 */
+			goto err_reset;
 		}
 	}
 
 	return 0;
+
+err_free:
+	__free_pages(page, get_order(NV_LENGTH));
+err_reset:
+	sev_init_ex_buffer = NULL;
+	return rc;
 }
 
 static int __sev_platform_init_locked(int *error)

-- 
2.53.0-Meta


^ permalink raw reply related

* [PATCH v3 3/4] crypto: ccp: Fix possible deadlock in SEV init failure path
From: Atish Patra @ 2026-06-02 22:36 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini, Borislav Petkov, Dave Hansen,
	x86, H. Peter Anvin, Tom Lendacky, Peter Gonda, Brijesh Singh,
	Youngjae Lee, Ashish Kalra, Michael Roth, John Allen, Herbert Xu
  Cc: clm, kvm, linux-kernel, linux-crypto, stable, Atish Patra
In-Reply-To: <20260602-sev_snp_fixes-v3-0-24bfd3ae047c@meta.com>

From: Atish Patra <atishp@meta.com>

__sev_platform_init_handle_init_ex_path() calls
rmp_mark_pages_firmware() with locked=false while the parent
function of init_ex_path already acquired the sev_cmd_mutex.
In the case of an RMPUPDATE failure for any page after the first, the cleanup
path would invoke reclaim pages which would result in a deadlock in
sev_do_cmd.

Pass locked=true to honor the lock status of the parent function.

Fixes: 7364a6fbca45 ("crypto: ccp: Handle non-volatile INIT_EX data when SNP is enabled")

Reported-by: Chris Mason <clm@meta.com>
Assisted-by: Claude:claude-opus-4-6
Fixes: 7364a6fbca45 ("crypto: ccp: Handle non-volatile INIT_EX data when SNP is enabled")
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Atish Patra <atishp@meta.com>
---
 drivers/crypto/ccp/sev-dev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index d1e9e0ac63b6..3d4793e8e34b 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -1557,7 +1557,7 @@ static int __sev_platform_init_handle_init_ex_path(struct sev_device *sev)
 		unsigned long npages;
 
 		npages = 1UL << get_order(NV_LENGTH);
-		if (rmp_mark_pages_firmware(__pa(sev_init_ex_buffer), npages, false)) {
+		if (rmp_mark_pages_firmware(__pa(sev_init_ex_buffer), npages, true)) {
 			dev_err(sev->dev, "SEV: INIT_EX NV memory page state change failed.\n");
 			return -ENOMEM;
 		}

-- 
2.53.0-Meta


^ permalink raw reply related

* [PATCH v3 2/4] KVM: selftests: Verify SNP VMs are rejected from migration and mirroring
From: Atish Patra @ 2026-06-02 22:36 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini, Borislav Petkov, Dave Hansen,
	x86, H. Peter Anvin, Tom Lendacky, Peter Gonda, Brijesh Singh,
	Youngjae Lee, Ashish Kalra, Michael Roth, John Allen, Herbert Xu
  Cc: clm, kvm, linux-kernel, linux-crypto, stable, Atish Patra
In-Reply-To: <20260602-sev_snp_fixes-v3-0-24bfd3ae047c@meta.com>

From: Atish Patra <atishp@meta.com>

Migration and mirroring of SEV-SNP VMs are not supported yet.

Add two selftests that verify KVM rejects intra-host migration and
mirroring when the source VM is an SNP VM, so the restriction stays enforced
until proper SNP state transfer is implemented.

Signed-off-by: Atish Patra <atishp@meta.com>
---
 .../testing/selftests/kvm/x86/sev_migrate_tests.c  | 47 ++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/tools/testing/selftests/kvm/x86/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86/sev_migrate_tests.c
index 6b0928e69051..acef6ab26d3d 100644
--- a/tools/testing/selftests/kvm/x86/sev_migrate_tests.c
+++ b/tools/testing/selftests/kvm/x86/sev_migrate_tests.c
@@ -313,6 +313,49 @@ static void test_sev_mirror_parameters(void)
 	kvm_vm_free(vm_no_vcpu);
 }
 
+static void test_sev_snp_migrate_reject(void)
+{
+	struct kvm_vm *src_vm, *dst_vm;
+	int ret;
+
+	src_vm = vm_create_barebones_type(KVM_X86_SNP_VM);
+	snp_vm_init(src_vm);
+	__vm_vcpu_add(src_vm, 0);
+	vm_sev_launch(src_vm, snp_default_policy(), NULL);
+
+	dst_vm = vm_create_barebones_type(KVM_X86_SNP_VM);
+	__vm_vcpu_add(dst_vm, 0);
+
+	ret = __sev_migrate_from(dst_vm, src_vm);
+	TEST_ASSERT(ret == -1 && errno == EINVAL,
+		    "SNP VM migration should be rejected. ret: %d, errno: %d",
+		    ret, errno);
+
+	kvm_vm_free(src_vm);
+	kvm_vm_free(dst_vm);
+}
+
+static void test_sev_snp_mirror_reject(void)
+{
+	struct kvm_vm *src_vm, *dst_vm;
+	int ret;
+
+	src_vm = vm_create_barebones_type(KVM_X86_SNP_VM);
+	snp_vm_init(src_vm);
+	__vm_vcpu_add(src_vm, 0);
+	vm_sev_launch(src_vm, snp_default_policy(), NULL);
+
+	dst_vm = aux_vm_create(false);
+
+	ret = __sev_mirror_create(dst_vm, src_vm);
+	TEST_ASSERT(ret == -1 && errno == EINVAL,
+		    "SNP VM mirroring should be rejected. ret: %d, errno: %d",
+		    ret, errno);
+
+	kvm_vm_free(src_vm);
+	kvm_vm_free(dst_vm);
+}
+
 static void test_sev_move_copy(void)
 {
 	struct kvm_vm *dst_vm, *dst2_vm, *dst3_vm, *sev_vm, *mirror_vm,
@@ -384,12 +427,16 @@ int main(int argc, char *argv[])
 		test_sev_migrate_parameters();
 		if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM))
 			test_sev_move_copy();
+		if (kvm_cpu_has(X86_FEATURE_SEV_SNP))
+			test_sev_snp_migrate_reject();
 	}
 	if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) {
 		test_sev_mirror(/* es= */ false);
 		if (have_sev_es)
 			test_sev_mirror(/* es= */ true);
 		test_sev_mirror_parameters();
+		if (kvm_cpu_has(X86_FEATURE_SEV_SNP))
+			test_sev_snp_mirror_reject();
 	}
 	return 0;
 }

-- 
2.53.0-Meta


^ permalink raw reply related

* [PATCH v3 1/4] KVM: SEV: Do not allow intra-host migration/mirroring of SNP VMs
From: Atish Patra @ 2026-06-02 22:36 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini, Borislav Petkov, Dave Hansen,
	x86, H. Peter Anvin, Tom Lendacky, Peter Gonda, Brijesh Singh,
	Youngjae Lee, Ashish Kalra, Michael Roth, John Allen, Herbert Xu
  Cc: clm, kvm, linux-kernel, linux-crypto, stable, Atish Patra,
	Sashiko
In-Reply-To: <20260602-sev_snp_fixes-v3-0-24bfd3ae047c@meta.com>

From: Atish Patra <atishp@meta.com>

The intra-host migration/mirroring feature is not fully implemented for
SEV-SNP VMs. The proper migration requires additional SNP-specific
state such as guest_req_mutex, guest_req_buf, and guest_resp_buf to be
transferred or initialized on the destination.

The SNP VM mirroring requires vmsa features to be copied as well otherwise
ASID would be bound to SNP range while VM is detected as a SEV VM.

Reject SNP source VMs in migration/mirroring until proper SNP state
transfer is implemented.

Fixes: 1dfe571c12cf ("KVM: SEV: Add initial SEV-SNP support")

Reported-by: Chris Mason <clm@meta.com>
Reported-by: Sashiko <sashiko-bot@kernel.org>
Assisted-by: Claude:claude-opus-4-6
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Atish Patra <atishp@meta.com>
---
 arch/x86/kvm/svm/sev.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index c2126b3c3072..a34326a77290 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -2141,8 +2141,10 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd)
 	if (ret)
 		return ret;
 
+	/* Do not allow SNP VM migration until additional state transfer is implemented  */
 	if (kvm->arch.vm_type != source_kvm->arch.vm_type ||
-	    sev_guest(kvm) || !sev_guest(source_kvm)) {
+	    sev_guest(kvm) || !sev_guest(source_kvm) ||
+	    sev_snp_guest(source_kvm)) {
 		ret = -EINVAL;
 		goto out_unlock;
 	}
@@ -2863,8 +2865,10 @@ int sev_vm_copy_enc_context_from(struct kvm *kvm, unsigned int source_fd)
 	 * disallow out-of-band SEV/SEV-ES init if the target is already an
 	 * SEV guest, or if vCPUs have been created.  KVM relies on vCPUs being
 	 * created after SEV/SEV-ES initialization, e.g. to init intercepts.
+	 * Also do not allow SNP VM mirroring until additional state transfer is implemented.
 	 */
 	if (sev_guest(kvm) || !sev_guest(source_kvm) ||
+	    sev_snp_guest(source_kvm) ||
 	    is_mirroring_enc_context(source_kvm) || kvm->created_vcpus) {
 		ret = -EINVAL;
 		goto e_unlock;

-- 
2.53.0-Meta


^ permalink raw reply related

* [PATCH v3 0/4] KVM: Miscellaneous SEV/SNP related fixes
From: Atish Patra @ 2026-06-02 22:36 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini, Borislav Petkov, Dave Hansen,
	x86, H. Peter Anvin, Tom Lendacky, Peter Gonda, Brijesh Singh,
	Youngjae Lee, Ashish Kalra, Michael Roth, John Allen, Herbert Xu
  Cc: clm, kvm, linux-kernel, linux-crypto, stable, Atish Patra,
	Sashiko

This series addresses a few issues found during code audit of the
KVM SEV/SNP and CCP driver code. The fixes include a incorrect lock state
and incomplete state handling during intra-host migration for SNP VMs.

To: Sean Christopherson <seanjc@google.com>
To: Paolo Bonzini <pbonzini@redhat.com>
To: Borislav Petkov <bp@alien8.de>
To: Dave Hansen <dave.hansen@linux.intel.com>
To: x86@kernel.org
To: H. Peter Anvin <hpa@zytor.com>
To: Tom Lendacky <thomas.lendacky@amd.com>
To: Peter Gonda <pgonda@google.com>
To: Brijesh Singh <brijesh.singh@amd.com>
To: Youngjae Lee <youngjaelee@meta.com>
To: Ashish Kalra <ashish.kalra@amd.com>
To: Michael Roth <michael.roth@amd.com>
To: John Allen <john.allen@amd.com>
To: Herbert Xu <herbert@gondor.apana.org.au>
Cc: clm@meta.com
Cc: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-crypto@vger.kernel.org
Cc: stable@vger.kernel.org

Signed-off-by: Atish Patra <atishp@meta.com>
---
Changes in v3:
- Added comments, fixed commit messages and fixes tag as per discussions on v2. 
- sev_init_ex_buffer initialized with zero at allocation to prevent any kernel
  data leak in case of init_ex_file is not present. Reported by Sashiko
- Link to v2: https://lore.kernel.org/r/20260601-sev_snp_fixes-v2-0-611891b28a86@meta.com

Changes in v2:
- Added fixes based on the reports by Sashiko. 
- Added a kselftest for validating SNP VM mirroring/migration rejection. 
- Link to v1: https://lore.kernel.org/r/20260528-sev_snp_fixes-v1-0-d67a08151779@meta.com

---
Atish Patra (4):
      KVM: SEV: Do not allow intra-host migration/mirroring of SNP VMs
      KVM: selftests: Verify SNP VMs are rejected from migration and mirroring
      crypto: ccp: Fix possible deadlock in SEV init failure path
      crypto: ccp: Fix memory leak in SEV INIT_EX path

 arch/x86/kvm/svm/sev.c                             |  6 ++-
 drivers/crypto/ccp/sev-dev.c                       | 19 +++++++--
 .../testing/selftests/kvm/x86/sev_migrate_tests.c  | 47 ++++++++++++++++++++++
 3 files changed, 67 insertions(+), 5 deletions(-)
---
base-commit: e7ae89a0c97ce2b68b0983cd01eda67cf373517d
change-id: 20260525-sev_snp_fixes-0b73789c1a91

Best regards,
-- 
Atish Patra <atishp@meta.com>


^ permalink raw reply

* [PATCH] crypto: atmel-ecc - drop dead code in atmel_ecdh_max_size
From: Thorsten Blum @ 2026-06-02 22:25 UTC (permalink / raw)
  To: Thorsten Blum, Herbert Xu, David S. Miller, Nicolas Ferre,
	Alexandre Belloni, Claudiu Beznea
  Cc: linux-crypto, linux-arm-kernel, linux-kernel

atmel_ecdh_init_tfm() always allocates ctx->fallback, so it is never
NULL in atmel_ecdh_max_size(). Remove the dead code and return
crypto_kpp_maxsize() directly.

Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
 drivers/crypto/atmel-ecc.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 9c380351d2f9..6a1716175b30 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -284,15 +284,7 @@ static unsigned int atmel_ecdh_max_size(struct crypto_kpp *tfm)
 {
 	struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
 
-	if (ctx->fallback)
-		return crypto_kpp_maxsize(ctx->fallback);
-
-	/*
-	 * The device only supports NIST P256 ECC keys. The public key size will
-	 * always be the same. Use a macro for the key size to avoid unnecessary
-	 * computations.
-	 */
-	return ATMEL_ECC_PUBKEY_SIZE;
+	return crypto_kpp_maxsize(ctx->fallback);
 }
 
 static struct kpp_alg atmel_ecdh_nist_p256 = {

^ permalink raw reply related

* Re: [PATCH] crypto: use two-argument strscpy where destination size is known
From: Tom Lendacky @ 2026-06-02 20:58 UTC (permalink / raw)
  To: Thorsten Blum
  Cc: Herbert Xu, David S. Miller, John Allen, Weili Qian, Zhou Wang,
	Giovanni Cabiddu, Srujana Challa, Bharat Bhushan, linux-crypto,
	linux-kernel, qat-linux
In-Reply-To: <ah9CMYSp27OSPxkv@linux.dev>

On 6/2/26 15:50, Thorsten Blum wrote:
> Hi Tom,
> 
> On Tue, Jun 02, 2026 at 03:24:06PM -0500, Tom Lendacky wrote:
>> On 5/25/26 05:30, Thorsten Blum wrote:
>>> To simplify the code, drop explicit and hard-coded size arguments from
>>> strscpy() where the destination buffer has a fixed size and strscpy()
>>> can automatically determine it using sizeof().
>>>
>>> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
>>
>> For the CCP driver changes:
>>
>> Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
> 
> Thanks.
> 
>> But I noticed that there are a few other places in the driver that I think
>> can be changed to use the two argument strscpy - essentially the strscpy's
>> that involve "cra_name" and "cra_driver_name" in
>> drivers/crypto/ccp/{ccp-crypto-aes-galois.c,ccp-crypto-aes-xts.c,ccp-crypto-aes.c,ccp-crypto-des3.c,ccp-crypto-rsa.c,ccp-crypto-sha.c}.
> 
> They already use the 2-arg strscpy(), except for the one in this patch:
> 
> $ git grep -n strscpy drivers/crypto/ccp/
> drivers/crypto/ccp/ccp-crypto-aes-galois.c:227: strscpy(alg->base.cra_name, def->name);
> drivers/crypto/ccp/ccp-crypto-aes-galois.c:228: strscpy(alg->base.cra_driver_name, def->driver_name);
> drivers/crypto/ccp/ccp-crypto-aes-xts.c:243:    strscpy(alg->base.cra_name, def->name);
> drivers/crypto/ccp/ccp-crypto-aes-xts.c:244:    strscpy(alg->base.cra_driver_name, def->drv_name);
> drivers/crypto/ccp/ccp-crypto-aes.c:311:        strscpy(alg->base.cra_name, def->name);
> drivers/crypto/ccp/ccp-crypto-aes.c:312:        strscpy(alg->base.cra_driver_name, def->driver_name);
> drivers/crypto/ccp/ccp-crypto-des3.c:196:       strscpy(alg->base.cra_name, def->name);
> drivers/crypto/ccp/ccp-crypto-des3.c:197:       strscpy(alg->base.cra_driver_name, def->driver_name);
> drivers/crypto/ccp/ccp-crypto-rsa.c:261:        strscpy(alg->base.cra_name, def->name);
> drivers/crypto/ccp/ccp-crypto-rsa.c:262:        strscpy(alg->base.cra_driver_name, def->driver_name);
> drivers/crypto/ccp/ccp-crypto-sha.c:429:        strscpy(ccp_alg->child_alg, def->name, CRYPTO_MAX_ALG_NAME);
> drivers/crypto/ccp/ccp-crypto-sha.c:487:        strscpy(base->cra_name, def->name);
> drivers/crypto/ccp/ccp-crypto-sha.c:488:        strscpy(base->cra_driver_name, def->drv_name);

Gah, I was looking at an old tree. Sorry for the noise.

Thanks,
Tom


^ permalink raw reply

* Re: [PATCH] crypto: use two-argument strscpy where destination size is known
From: Thorsten Blum @ 2026-06-02 20:50 UTC (permalink / raw)
  To: Tom Lendacky
  Cc: Herbert Xu, David S. Miller, John Allen, Weili Qian, Zhou Wang,
	Giovanni Cabiddu, Srujana Challa, Bharat Bhushan, linux-crypto,
	linux-kernel, qat-linux
In-Reply-To: <e94278a8-52df-4758-98fc-e6d7e5b55491@amd.com>

Hi Tom,

On Tue, Jun 02, 2026 at 03:24:06PM -0500, Tom Lendacky wrote:
> On 5/25/26 05:30, Thorsten Blum wrote:
> > To simplify the code, drop explicit and hard-coded size arguments from
> > strscpy() where the destination buffer has a fixed size and strscpy()
> > can automatically determine it using sizeof().
> > 
> > Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> 
> For the CCP driver changes:
> 
> Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>

Thanks.

> But I noticed that there are a few other places in the driver that I think
> can be changed to use the two argument strscpy - essentially the strscpy's
> that involve "cra_name" and "cra_driver_name" in
> drivers/crypto/ccp/{ccp-crypto-aes-galois.c,ccp-crypto-aes-xts.c,ccp-crypto-aes.c,ccp-crypto-des3.c,ccp-crypto-rsa.c,ccp-crypto-sha.c}.

They already use the 2-arg strscpy(), except for the one in this patch:

$ git grep -n strscpy drivers/crypto/ccp/
drivers/crypto/ccp/ccp-crypto-aes-galois.c:227: strscpy(alg->base.cra_name, def->name);
drivers/crypto/ccp/ccp-crypto-aes-galois.c:228: strscpy(alg->base.cra_driver_name, def->driver_name);
drivers/crypto/ccp/ccp-crypto-aes-xts.c:243:    strscpy(alg->base.cra_name, def->name);
drivers/crypto/ccp/ccp-crypto-aes-xts.c:244:    strscpy(alg->base.cra_driver_name, def->drv_name);
drivers/crypto/ccp/ccp-crypto-aes.c:311:        strscpy(alg->base.cra_name, def->name);
drivers/crypto/ccp/ccp-crypto-aes.c:312:        strscpy(alg->base.cra_driver_name, def->driver_name);
drivers/crypto/ccp/ccp-crypto-des3.c:196:       strscpy(alg->base.cra_name, def->name);
drivers/crypto/ccp/ccp-crypto-des3.c:197:       strscpy(alg->base.cra_driver_name, def->driver_name);
drivers/crypto/ccp/ccp-crypto-rsa.c:261:        strscpy(alg->base.cra_name, def->name);
drivers/crypto/ccp/ccp-crypto-rsa.c:262:        strscpy(alg->base.cra_driver_name, def->driver_name);
drivers/crypto/ccp/ccp-crypto-sha.c:429:        strscpy(ccp_alg->child_alg, def->name, CRYPTO_MAX_ALG_NAME);
drivers/crypto/ccp/ccp-crypto-sha.c:487:        strscpy(base->cra_name, def->name);
drivers/crypto/ccp/ccp-crypto-sha.c:488:        strscpy(base->cra_driver_name, def->drv_name);

^ permalink raw reply

* Re: [PATCH] crypto: use two-argument strscpy where destination size is known
From: Tom Lendacky @ 2026-06-02 20:24 UTC (permalink / raw)
  To: Thorsten Blum, Herbert Xu, David S. Miller, John Allen,
	Weili Qian, Zhou Wang, Giovanni Cabiddu, Srujana Challa,
	Bharat Bhushan
  Cc: linux-crypto, linux-kernel, qat-linux
In-Reply-To: <20260525103038.825690-4-thorsten.blum@linux.dev>

On 5/25/26 05:30, Thorsten Blum wrote:
> To simplify the code, drop explicit and hard-coded size arguments from
> strscpy() where the destination buffer has a fixed size and strscpy()
> can automatically determine it using sizeof().
> 
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>

For the CCP driver changes:

Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>

But I noticed that there are a few other places in the driver that I think
can be changed to use the two argument strscpy - essentially the strscpy's
that involve "cra_name" and "cra_driver_name" in
drivers/crypto/ccp/{ccp-crypto-aes-galois.c,ccp-crypto-aes-xts.c,ccp-crypto-aes.c,ccp-crypto-des3.c,ccp-crypto-rsa.c,ccp-crypto-sha.c}.

> ---
>  crypto/api.c                                             | 2 +-
>  crypto/crypto_user.c                                     | 9 ++++-----
>  crypto/hctr2.c                                           | 3 +--
>  crypto/lrw.c                                             | 2 +-
>  crypto/lskcipher.c                                       | 3 +--
>  crypto/xts.c                                             | 3 ++-
>  drivers/crypto/cavium/nitrox/nitrox_hal.c                | 3 ++-
>  drivers/crypto/ccp/ccp-crypto-sha.c                      | 2 +-
>  drivers/crypto/hisilicon/qm.c                            | 5 +----
>  drivers/crypto/intel/qat/qat_common/adf_cfg.c            | 7 ++++---
>  drivers/crypto/intel/qat/qat_common/adf_cfg_services.c   | 2 +-
>  drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c        | 3 ++-
>  drivers/crypto/intel/qat/qat_common/adf_mstate_mgr.c     | 3 ++-
>  .../crypto/intel/qat/qat_common/adf_transport_debug.c    | 3 ++-
>  drivers/crypto/intel/qat/qat_common/qat_compression.c    | 3 ++-
>  drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c        | 6 +++---
>  drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c      | 4 ++--
>  17 files changed, 32 insertions(+), 31 deletions(-)
> 
> diff --git a/crypto/api.c b/crypto/api.c
> index 74e17d5049c9..040b7a965c2f 100644
> --- a/crypto/api.c
> +++ b/crypto/api.c
> @@ -116,7 +116,7 @@ struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask)
>  	larval->alg.cra_priority = -1;
>  	larval->alg.cra_destroy = crypto_larval_destroy;
>  
> -	strscpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
> +	strscpy(larval->alg.cra_name, name);
>  	init_completion(&larval->completion);
>  
>  	return larval;
> diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c
> index e8b6ae75f31f..d3ccb507153b 100644
> --- a/crypto/crypto_user.c
> +++ b/crypto/crypto_user.c
> @@ -11,6 +11,7 @@
>  #include <linux/cryptouser.h>
>  #include <linux/sched.h>
>  #include <linux/security.h>
> +#include <linux/string.h>
>  #include <net/netlink.h>
>  #include <net/net_namespace.h>
>  #include <net/sock.h>
> @@ -87,11 +88,9 @@ static int crypto_report_one(struct crypto_alg *alg,
>  {
>  	memset(ualg, 0, sizeof(*ualg));
>  
> -	strscpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
> -	strscpy(ualg->cru_driver_name, alg->cra_driver_name,
> -		sizeof(ualg->cru_driver_name));
> -	strscpy(ualg->cru_module_name, module_name(alg->cra_module),
> -		sizeof(ualg->cru_module_name));
> +	strscpy(ualg->cru_name, alg->cra_name);
> +	strscpy(ualg->cru_driver_name, alg->cra_driver_name);
> +	strscpy(ualg->cru_module_name, module_name(alg->cra_module));
>  
>  	ualg->cru_type = 0;
>  	ualg->cru_mask = 0;
> diff --git a/crypto/hctr2.c b/crypto/hctr2.c
> index ad5edf9366ac..cfc2343bcc1c 100644
> --- a/crypto/hctr2.c
> +++ b/crypto/hctr2.c
> @@ -354,8 +354,7 @@ static int hctr2_create_common(struct crypto_template *tmpl, struct rtattr **tb,
>  	err = -EINVAL;
>  	if (strncmp(xctr_alg->base.cra_name, "xctr(", 5))
>  		goto err_free_inst;
> -	len = strscpy(blockcipher_name, xctr_alg->base.cra_name + 5,
> -		      sizeof(blockcipher_name));
> +	len = strscpy(blockcipher_name, xctr_alg->base.cra_name + 5);
>  	if (len < 1)
>  		goto err_free_inst;
>  	if (blockcipher_name[len - 1] != ')')
> diff --git a/crypto/lrw.c b/crypto/lrw.c
> index aa31ab03a597..e306e85d7ced 100644
> --- a/crypto/lrw.c
> +++ b/crypto/lrw.c
> @@ -359,7 +359,7 @@ static int lrw_create(struct crypto_template *tmpl, struct rtattr **tb)
>  	if (!memcmp(cipher_name, "ecb(", 4)) {
>  		int len;
>  
> -		len = strscpy(ecb_name, cipher_name + 4, sizeof(ecb_name));
> +		len = strscpy(ecb_name, cipher_name + 4);
>  		if (len < 2)
>  			goto err_free_inst;
>  
> diff --git a/crypto/lskcipher.c b/crypto/lskcipher.c
> index e4328df6e26c..d7ec215e2b3a 100644
> --- a/crypto/lskcipher.c
> +++ b/crypto/lskcipher.c
> @@ -528,8 +528,7 @@ struct lskcipher_instance *lskcipher_alloc_instance_simple(
>  		int len;
>  
>  		err = -EINVAL;
> -		len = strscpy(ecb_name, &cipher_alg->co.base.cra_name[4],
> -			      sizeof(ecb_name));
> +		len = strscpy(ecb_name, &cipher_alg->co.base.cra_name[4]);
>  		if (len < 2)
>  			goto err_free_inst;
>  
> diff --git a/crypto/xts.c b/crypto/xts.c
> index ad97c8091582..1dc948745444 100644
> --- a/crypto/xts.c
> +++ b/crypto/xts.c
> @@ -16,6 +16,7 @@
>  #include <linux/module.h>
>  #include <linux/scatterlist.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  
>  #include <crypto/xts.h>
>  #include <crypto/b128ops.h>
> @@ -400,7 +401,7 @@ static int xts_create(struct crypto_template *tmpl, struct rtattr **tb)
>  	if (!memcmp(cipher_name, "ecb(", 4)) {
>  		int len;
>  
> -		len = strscpy(name, cipher_name + 4, sizeof(name));
> +		len = strscpy(name, cipher_name + 4);
>  		if (len < 2)
>  			goto err_free_inst;
>  
> diff --git a/drivers/crypto/cavium/nitrox/nitrox_hal.c b/drivers/crypto/cavium/nitrox/nitrox_hal.c
> index 1b5abdb6cc5e..e36c1741bb78 100644
> --- a/drivers/crypto/cavium/nitrox/nitrox_hal.c
> +++ b/drivers/crypto/cavium/nitrox/nitrox_hal.c
> @@ -1,5 +1,6 @@
>  // SPDX-License-Identifier: GPL-2.0
>  #include <linux/delay.h>
> +#include <linux/string.h>
>  
>  #include "nitrox_dev.h"
>  #include "nitrox_csr.h"
> @@ -647,7 +648,7 @@ void nitrox_get_hwinfo(struct nitrox_device *ndev)
>  		 ndev->hw.revision_id);
>  
>  	/* copy partname */
> -	strscpy(ndev->hw.partname, name, sizeof(ndev->hw.partname));
> +	strscpy(ndev->hw.partname, name);
>  }
>  
>  void enable_pf2vf_mbox_interrupts(struct nitrox_device *ndev)
> diff --git a/drivers/crypto/ccp/ccp-crypto-sha.c b/drivers/crypto/ccp/ccp-crypto-sha.c
> index 85058a89f35b..ff9bb253dbb2 100644
> --- a/drivers/crypto/ccp/ccp-crypto-sha.c
> +++ b/drivers/crypto/ccp/ccp-crypto-sha.c
> @@ -426,7 +426,7 @@ static int ccp_register_hmac_alg(struct list_head *head,
>  	*ccp_alg = *base_alg;
>  	INIT_LIST_HEAD(&ccp_alg->entry);
>  
> -	strscpy(ccp_alg->child_alg, def->name, CRYPTO_MAX_ALG_NAME);
> +	strscpy(ccp_alg->child_alg, def->name);
>  
>  	alg = &ccp_alg->alg;
>  	alg->setkey = ccp_sha_setkey;
> diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c
> index 3ca47e2a9719..0c8cc0d7a82a 100644
> --- a/drivers/crypto/hisilicon/qm.c
> +++ b/drivers/crypto/hisilicon/qm.c
> @@ -2870,11 +2870,8 @@ static int qm_alloc_uacce(struct hisi_qm *qm)
>  		.flags = UACCE_DEV_SVA,
>  		.ops = &uacce_qm_ops,
>  	};
> -	int ret;
>  
> -	ret = strscpy(interface.name, dev_driver_string(&pdev->dev),
> -		      sizeof(interface.name));
> -	if (ret < 0)
> +	if (strscpy(interface.name, dev_driver_string(&pdev->dev)) < 0)
>  		return -ENAMETOOLONG;
>  
>  	uacce = uacce_alloc(&pdev->dev, &interface);
> diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg.c b/drivers/crypto/intel/qat/qat_common/adf_cfg.c
> index c202209f17d5..24c2618af68d 100644
> --- a/drivers/crypto/intel/qat/qat_common/adf_cfg.c
> +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg.c
> @@ -2,6 +2,7 @@
>  /* Copyright(c) 2014 - 2020 Intel Corporation */
>  #include <linux/mutex.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include <linux/list.h>
>  #include <linux/seq_file.h>
>  #include "adf_accel_devices.h"
> @@ -294,13 +295,13 @@ int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev,
>  		return -ENOMEM;
>  
>  	INIT_LIST_HEAD(&key_val->list);
> -	strscpy(key_val->key, key, sizeof(key_val->key));
> +	strscpy(key_val->key, key);
>  
>  	if (type == ADF_DEC) {
>  		snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
>  			 "%ld", (*((long *)val)));
>  	} else if (type == ADF_STR) {
> -		strscpy(key_val->val, (char *)val, sizeof(key_val->val));
> +		strscpy(key_val->val, (char *)val);
>  	} else if (type == ADF_HEX) {
>  		snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
>  			 "0x%lx", (unsigned long)val);
> @@ -360,7 +361,7 @@ int adf_cfg_section_add(struct adf_accel_dev *accel_dev, const char *name)
>  	if (!sec)
>  		return -ENOMEM;
>  
> -	strscpy(sec->name, name, sizeof(sec->name));
> +	strscpy(sec->name, name);
>  	INIT_LIST_HEAD(&sec->param_head);
>  	down_write(&cfg->lock);
>  	list_add_tail(&sec->list, &cfg->sec_list);
> diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c
> index 7d00bcb41ce7..11cba347d12d 100644
> --- a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c
> +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c
> @@ -60,7 +60,7 @@ static int adf_service_string_to_mask(struct adf_accel_dev *accel_dev, const cha
>  	if (len > ADF_CFG_MAX_VAL_LEN_IN_BYTES - 1)
>  		return -EINVAL;
>  
> -	strscpy(services, buf, ADF_CFG_MAX_VAL_LEN_IN_BYTES);
> +	strscpy(services, buf);
>  	substr = services;
>  
>  	while ((token = strsep(&substr, ADF_SERVICES_DELIMITER))) {
> diff --git a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c
> index c2e6f0cb7480..ae10b91da5ba 100644
> --- a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c
> +++ b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c
> @@ -5,6 +5,7 @@
>  #include <linux/module.h>
>  #include <linux/mutex.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include <linux/fs.h>
>  #include <linux/bitops.h>
>  #include <linux/pci.h>
> @@ -350,7 +351,7 @@ static int adf_ctl_ioctl_get_status(struct file *fp, unsigned int cmd,
>  	dev_info.num_logical_accel = hw_data->num_logical_accel;
>  	dev_info.banks_per_accel = hw_data->num_banks
>  					/ hw_data->num_logical_accel;
> -	strscpy(dev_info.name, hw_data->dev_class->name, sizeof(dev_info.name));
> +	strscpy(dev_info.name, hw_data->dev_class->name);
>  	dev_info.instance_id = hw_data->instance_id;
>  	dev_info.type = hw_data->dev_class->type;
>  	dev_info.bus = accel_to_pci_dev(accel_dev)->bus->number;
> diff --git a/drivers/crypto/intel/qat/qat_common/adf_mstate_mgr.c b/drivers/crypto/intel/qat/qat_common/adf_mstate_mgr.c
> index f9017e03ec0f..32aeb795cc03 100644
> --- a/drivers/crypto/intel/qat/qat_common/adf_mstate_mgr.c
> +++ b/drivers/crypto/intel/qat/qat_common/adf_mstate_mgr.c
> @@ -2,6 +2,7 @@
>  /* Copyright(c) 2024 Intel Corporation */
>  
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include <linux/types.h>
>  #include "adf_mstate_mgr.h"
>  
> @@ -158,7 +159,7 @@ static struct adf_mstate_sect_h *adf_mstate_sect_add_header(struct adf_mstate_mg
>  		return NULL;
>  	}
>  
> -	strscpy(sect->id, id, sizeof(sect->id));
> +	strscpy(sect->id, id);
>  	sect->size = 0;
>  	sect->sub_sects = 0;
>  	mgr->state += sizeof(*sect);
> diff --git a/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c b/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c
> index a8f853516a3f..fc5d88a2bb17 100644
> --- a/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c
> +++ b/drivers/crypto/intel/qat/qat_common/adf_transport_debug.c
> @@ -2,6 +2,7 @@
>  /* Copyright(c) 2014 - 2020 Intel Corporation */
>  #include <linux/mutex.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include <linux/seq_file.h>
>  #include "adf_accel_devices.h"
>  #include "adf_transport_internal.h"
> @@ -103,7 +104,7 @@ int adf_ring_debugfs_add(struct adf_etr_ring_data *ring, const char *name)
>  	if (!ring_debug)
>  		return -ENOMEM;
>  
> -	strscpy(ring_debug->ring_name, name, sizeof(ring_debug->ring_name));
> +	strscpy(ring_debug->ring_name, name);
>  	snprintf(entry_name, sizeof(entry_name), "ring_%02d",
>  		 ring->ring_number);
>  
> diff --git a/drivers/crypto/intel/qat/qat_common/qat_compression.c b/drivers/crypto/intel/qat/qat_common/qat_compression.c
> index 1424d7a9bcd3..8129ad0c32d8 100644
> --- a/drivers/crypto/intel/qat/qat_common/qat_compression.c
> +++ b/drivers/crypto/intel/qat/qat_common/qat_compression.c
> @@ -2,6 +2,7 @@
>  /* Copyright(c) 2022 Intel Corporation */
>  #include <linux/module.h>
>  #include <linux/slab.h>
> +#include <linux/string.h>
>  #include "adf_accel_devices.h"
>  #include "adf_common_drv.h"
>  #include "adf_transport.h"
> @@ -144,7 +145,7 @@ static int qat_compression_create_instances(struct adf_accel_dev *accel_dev)
>  	int i;
>  
>  	INIT_LIST_HEAD(&accel_dev->compression_list);
> -	strscpy(key, ADF_NUM_DC, sizeof(key));
> +	strscpy(key, ADF_NUM_DC);
>  	ret = adf_cfg_get_param_value(accel_dev, SEC, key, val);
>  	if (ret)
>  		return ret;
> diff --git a/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c b/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c
> index e0f38d32bc93..5c3636080757 100644
> --- a/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c
> +++ b/drivers/crypto/marvell/octeontx/otx_cptpf_ucode.c
> @@ -99,7 +99,7 @@ static int dev_supports_eng_type(struct otx_cpt_eng_grps *eng_grps,
>  static void set_ucode_filename(struct otx_cpt_ucode *ucode,
>  			       const char *filename)
>  {
> -	strscpy(ucode->filename, filename, OTX_CPT_UCODE_NAME_LENGTH);
> +	strscpy(ucode->filename, filename);
>  }
>  
>  static char *get_eng_type_str(int eng_type)
> @@ -140,7 +140,7 @@ static int get_ucode_type(struct otx_cpt_ucode_hdr *ucode_hdr, int *ucode_type)
>  	u32 i, val = 0;
>  	u8 nn;
>  
> -	strscpy(tmp_ver_str, ucode_hdr->ver_str, OTX_CPT_UCODE_VER_STR_SZ);
> +	strscpy(tmp_ver_str, ucode_hdr->ver_str);
>  	for (i = 0; i < strlen(tmp_ver_str); i++)
>  		tmp_ver_str[i] = tolower(tmp_ver_str[i]);
>  
> @@ -1331,7 +1331,7 @@ static ssize_t ucode_load_store(struct device *dev,
>  
>  	eng_grps = container_of(attr, struct otx_cpt_eng_grps, ucode_load_attr);
>  	err_msg = "Invalid engine group format";
> -	strscpy(tmp_buf, buf, OTX_CPT_UCODE_NAME_LENGTH);
> +	strscpy(tmp_buf, buf);
>  	start = tmp_buf;
>  
>  	has_se = has_ie = has_ae = false;
> diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
> index 9b0887d7e62c..465f00e74623 100644
> --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
> +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c
> @@ -74,7 +74,7 @@ static int is_2nd_ucode_used(struct otx2_cpt_eng_grp_info *eng_grp)
>  static void set_ucode_filename(struct otx2_cpt_ucode *ucode,
>  			       const char *filename)
>  {
> -	strscpy(ucode->filename, filename, OTX2_CPT_NAME_LENGTH);
> +	strscpy(ucode->filename, filename);
>  }
>  
>  static char *get_eng_type_str(int eng_type)
> @@ -130,7 +130,7 @@ static int get_ucode_type(struct device *dev,
>  	int i, val = 0;
>  	u8 nn;
>  
> -	strscpy(tmp_ver_str, ucode_hdr->ver_str, OTX2_CPT_UCODE_VER_STR_SZ);
> +	strscpy(tmp_ver_str, ucode_hdr->ver_str);
>  	for (i = 0; i < strlen(tmp_ver_str); i++)
>  		tmp_ver_str[i] = tolower(tmp_ver_str[i]);
>  


^ permalink raw reply

* [PATCH v6 6/6] x86/sev: Add debugfs support for RMPOPT
From: Ashish Kalra @ 2026-06-02 20:02 UTC (permalink / raw)
  To: tglx, mingo, bp, dave.hansen, x86, hpa, seanjc, peterz,
	thomas.lendacky, herbert, davem, ardb
  Cc: pbonzini, aik, Michael.Roth, KPrateek.Nayak, Tycho.Andersen,
	Nathan.Fontenot, ackerleytng, jackyli, pgonda, rientjes, jacobhxu,
	xin, pawan.kumar.gupta, babu.moger, dyoung, nikunj, john.allen,
	darwi, linux-kernel, linux-crypto, kvm, linux-coco
In-Reply-To: <cover.1780427587.git.ashish.kalra@amd.com>

From: Ashish Kalra <ashish.kalra@amd.com>

Add a debugfs interface to report per-CPU RMPOPT status across all
system RAM.

To dump the per-CPU RMPOPT status for all system RAM:

/sys/kernel/debug/rmpopt# cat rmpopt-table

Memory @  0GB: CPU(s): none
Memory @  1GB: CPU(s): none
Memory @  2GB: CPU(s): 0-1023
Memory @  3GB: CPU(s): 0-1023
Memory @  4GB: CPU(s): none
Memory @  5GB: CPU(s): 0-1023
Memory @  6GB: CPU(s): 0-1023
Memory @  7GB: CPU(s): 0-1023
...
Memory @1025GB: CPU(s): 0-1023
Memory @1026GB: CPU(s): 0-1023
Memory @1027GB: CPU(s): 0-1023
Memory @1028GB: CPU(s): 0-1023
Memory @1029GB: CPU(s): 0-1023
Memory @1030GB: CPU(s): 0-1023
Memory @1031GB: CPU(s): 0-1023
Memory @1032GB: CPU(s): 0-1023
Memory @1033GB: CPU(s): 0-1023
Memory @1034GB: CPU(s): 0-1023
Memory @1035GB: CPU(s): 0-1023
Memory @1036GB: CPU(s): 0-1023
Memory @1037GB: CPU(s): 0-1023
Memory @1038GB: CPU(s): none

Suggested-by: Thomas Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
 arch/x86/virt/svm/sev.c | 128 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/arch/x86/virt/svm/sev.c b/arch/x86/virt/svm/sev.c
index 4442ecae3d18..29695bb18991 100644
--- a/arch/x86/virt/svm/sev.c
+++ b/arch/x86/virt/svm/sev.c
@@ -20,6 +20,8 @@
 #include <linux/amd-iommu.h>
 #include <linux/nospec.h>
 #include <linux/workqueue.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include <asm/sev.h>
 #include <asm/processor.h>
@@ -144,6 +146,15 @@ static DEFINE_SPINLOCK(snp_leaked_pages_list_lock);
 
 static unsigned long snp_nr_leaked_pages;
 
+/* All users of rmpopt_report_cpumask must hold rmpopt_show_mutex. */
+static cpumask_t rmpopt_report_cpumask;
+static struct dentry *rmpopt_debugfs;
+static DEFINE_MUTEX(rmpopt_show_mutex);
+
+struct seq_paddr {
+	phys_addr_t next_seq_paddr;
+};
+
 #undef pr_fmt
 #define pr_fmt(fmt)	"SEV-SNP: " fmt
 
@@ -585,6 +596,8 @@ static void rmpopt_cleanup(void)
 
 	cancel_delayed_work_sync(&rmpopt_delayed_work);
 	destroy_workqueue(rmpopt_wq);
+	debugfs_remove_recursive(rmpopt_debugfs);
+	rmpopt_debugfs = NULL;
 
 	cpus_read_lock();
 
@@ -622,6 +635,10 @@ static inline bool __rmpopt(u64 pa_start, u64 op_type)
 		     : "a" (pa_start), "c" (op_type)
 		     : "memory", "cc");
 
+	if (op_type == RMPOPT_FUNC_REPORT_STATUS)
+		assign_cpu(smp_processor_id(), &rmpopt_report_cpumask,
+			   optimized);
+
 	return optimized;
 }
 
@@ -641,6 +658,115 @@ static void rmpopt_smp(void *val)
 	rmpopt((u64)val);
 }
 
+/*
+ * 'val' is a system physical address.
+ */
+static void rmpopt_report_status(void *val)
+{
+	u64 pa_start = ALIGN_DOWN((u64)val, SZ_1G);
+	u64 op_type = RMPOPT_FUNC_REPORT_STATUS;
+
+	__rmpopt(pa_start, op_type);
+}
+
+/*
+ * start() can be called multiple times if allocated buffer has overflowed
+ * and bigger buffer is allocated.
+ */
+static void *rmpopt_table_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	phys_addr_t end_paddr = rmpopt_pa_end;
+	struct seq_paddr *p = seq->private;
+
+	if (*pos == 0) {
+		p->next_seq_paddr = rmpopt_pa_start;
+		if (p->next_seq_paddr >= end_paddr)
+			return NULL;
+		return &p->next_seq_paddr;
+	}
+
+	if (p->next_seq_paddr >= end_paddr)
+		return NULL;
+
+	return &p->next_seq_paddr;
+}
+
+static void *rmpopt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	phys_addr_t end_paddr = rmpopt_pa_end;
+	phys_addr_t *curr_paddr = v;
+
+	(*pos)++;
+	*curr_paddr += SZ_1G;
+	if (*curr_paddr >= end_paddr)
+		return NULL;
+
+	return curr_paddr;
+}
+
+static void rmpopt_table_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int rmpopt_table_seq_show(struct seq_file *seq, void *v)
+{
+	phys_addr_t *curr_paddr = v;
+
+	guard(mutex)(&rmpopt_show_mutex);
+
+	seq_printf(seq, "Memory @%3lluGB: ",
+		   *curr_paddr >> (get_order(SZ_1G) + PAGE_SHIFT));
+
+	/*
+	 * Query all online CPUs rather than just rmpopt_cpumask (primary
+	 * threads only). The RMPOPT instruction only needs to run on one
+	 * thread per core for the optimization to take effect, but debugfs
+	 * reporting requires the RMPOPT status across all CPUs.
+	 * Performance is not a concern for this diagnostic interface.
+	 *
+	 * This is safe because RMPOPT_BASE MSR is per-core and
+	 * snp_prepare() ensures all CPUs are online when the MSR is
+	 * programmed during snp_setup_rmpopt().
+	 */
+	cpumask_clear(&rmpopt_report_cpumask);
+	on_each_cpu_mask(cpu_online_mask, rmpopt_report_status,
+			 (void *)*curr_paddr, true);
+
+	if (cpumask_empty(&rmpopt_report_cpumask))
+		seq_puts(seq, "CPU(s): none\n");
+	else
+		seq_printf(seq, "CPU(s): %*pbl\n", cpumask_pr_args(&rmpopt_report_cpumask));
+
+	return 0;
+}
+
+static const struct seq_operations rmpopt_table_seq_ops = {
+	.start = rmpopt_table_seq_start,
+	.next = rmpopt_table_seq_next,
+	.stop = rmpopt_table_seq_stop,
+	.show = rmpopt_table_seq_show
+};
+
+static int rmpopt_table_open(struct inode *inode, struct file *file)
+{
+	return seq_open_private(file, &rmpopt_table_seq_ops, sizeof(struct seq_paddr));
+}
+
+static const struct file_operations rmpopt_table_fops = {
+	.open = rmpopt_table_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release_private,
+};
+
+static void rmpopt_debugfs_setup(void)
+{
+	rmpopt_debugfs = debugfs_create_dir("rmpopt", arch_debugfs_dir);
+
+	debugfs_create_file("rmpopt-table", 0400, rmpopt_debugfs,
+			    NULL, &rmpopt_table_fops);
+}
+
 /*
  * RMPOPT optimizations skip RMP checks at 1GB granularity if this
  * range of memory does not contain any SNP guest memory.
@@ -833,6 +959,8 @@ void snp_setup_rmpopt(void)
 	 * optimizations on all physical memory.
 	 */
 	queue_delayed_work(rmpopt_wq, &rmpopt_delayed_work, 0);
+
+	rmpopt_debugfs_setup();
 }
 EXPORT_SYMBOL_FOR_MODULES(snp_setup_rmpopt, "ccp");
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH v6 5/6] KVM: SEV: Perform RMP optimizations on SNP guest shutdown
From: Ashish Kalra @ 2026-06-02 20:02 UTC (permalink / raw)
  To: tglx, mingo, bp, dave.hansen, x86, hpa, seanjc, peterz,
	thomas.lendacky, herbert, davem, ardb
  Cc: pbonzini, aik, Michael.Roth, KPrateek.Nayak, Tycho.Andersen,
	Nathan.Fontenot, ackerleytng, jackyli, pgonda, rientjes, jacobhxu,
	xin, pawan.kumar.gupta, babu.moger, dyoung, nikunj, john.allen,
	darwi, linux-kernel, linux-crypto, kvm, linux-coco
In-Reply-To: <cover.1780427587.git.ashish.kalra@amd.com>

From: Ashish Kalra <ashish.kalra@amd.com>

Pages are converted from shared to private as SNP guests are launched.
This destroys exisiting RMPOPT optimizations in the regions where
pages are converted.

Conversely, guest pages are converted back to shared during SNP guest
termination and their region may become eligible for RMPOPT
optimization.

To take advantage of this, perform RMPOPT after guest termination.
Do it after a delay so that a single RMPOPT pass can be done if
multiple guests terminate in a short period of time.

Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
 arch/x86/kvm/svm/sev.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index e107f368ed2d..29af6f6e603c 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -3005,6 +3005,8 @@ void sev_vm_destroy(struct kvm *kvm)
 		 */
 		if (snp_decommission_context(kvm))
 			return;
+
+		snp_rmpopt_all_physmem();
 	} else {
 		sev_unbind_asid(kvm, sev->handle);
 	}
-- 
2.43.0


^ permalink raw reply related

* [PATCH v6 4/6] x86/sev: Add interface to re-enable RMP optimizations.
From: Ashish Kalra @ 2026-06-02 20:01 UTC (permalink / raw)
  To: tglx, mingo, bp, dave.hansen, x86, hpa, seanjc, peterz,
	thomas.lendacky, herbert, davem, ardb
  Cc: pbonzini, aik, Michael.Roth, KPrateek.Nayak, Tycho.Andersen,
	Nathan.Fontenot, ackerleytng, jackyli, pgonda, rientjes, jacobhxu,
	xin, pawan.kumar.gupta, babu.moger, dyoung, nikunj, john.allen,
	darwi, linux-kernel, linux-crypto, kvm, linux-coco
In-Reply-To: <cover.1780427587.git.ashish.kalra@amd.com>

From: Ashish Kalra <ashish.kalra@amd.com>

RMPOPT table is a per-CPU table which indicates if 1GB regions of
physical memory are entirely hypervisor-owned or not.

When performing host memory accesses in hypervisor mode as well as
non-SNP guest mode, the processor may consult the RMPOPT table to
potentially skip an RMP access and improve performance.

Events such as RMPUPDATE can clear RMP optimizations. Add an interface
to re-enable those optimizations.

Reviewed-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
 arch/x86/include/asm/sev.h |  2 ++
 arch/x86/virt/svm/sev.c    | 15 +++++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index 6fd72a44a51e..09b1c5d33790 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -662,6 +662,7 @@ static inline void snp_leak_pages(u64 pfn, unsigned int pages)
 	__snp_leak_pages(pfn, pages, true);
 }
 int snp_prepare(void);
+void snp_rmpopt_all_physmem(void);
 void snp_setup_rmpopt(void);
 void snp_shutdown(void);
 #else
@@ -681,6 +682,7 @@ static inline void snp_leak_pages(u64 pfn, unsigned int npages) {}
 static inline void kdump_sev_callback(void) { }
 static inline void snp_fixup_e820_tables(void) {}
 static inline int snp_prepare(void) { return -ENODEV; }
+static inline void snp_rmpopt_all_physmem(void) {}
 static inline void snp_setup_rmpopt(void) {}
 static inline void snp_shutdown(void) {}
 #endif
diff --git a/arch/x86/virt/svm/sev.c b/arch/x86/virt/svm/sev.c
index d7e40a5fe5ca..4442ecae3d18 100644
--- a/arch/x86/virt/svm/sev.c
+++ b/arch/x86/virt/svm/sev.c
@@ -741,6 +741,21 @@ static void rmpopt_work_handler(struct work_struct *work)
 	free_cpumask_var(follower_mask);
 }
 
+void snp_rmpopt_all_physmem(void)
+{
+	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+		return;
+
+	guard(mutex)(&rmpopt_wq_mutex);
+
+	if (!rmpopt_wq)
+		return;
+
+	queue_delayed_work(rmpopt_wq, &rmpopt_delayed_work,
+			   msecs_to_jiffies(RMPOPT_WORK_TIMEOUT));
+}
+EXPORT_SYMBOL_GPL(snp_rmpopt_all_physmem);
+
 void snp_setup_rmpopt(void)
 {
 	u64 rmpopt_base;
-- 
2.43.0


^ permalink raw reply related

* [PATCH v6 3/6] x86/sev: Add support to perform RMP optimizations asynchronously
From: Ashish Kalra @ 2026-06-02 20:01 UTC (permalink / raw)
  To: tglx, mingo, bp, dave.hansen, x86, hpa, seanjc, peterz,
	thomas.lendacky, herbert, davem, ardb
  Cc: pbonzini, aik, Michael.Roth, KPrateek.Nayak, Tycho.Andersen,
	Nathan.Fontenot, ackerleytng, jackyli, pgonda, rientjes, jacobhxu,
	xin, pawan.kumar.gupta, babu.moger, dyoung, nikunj, john.allen,
	darwi, linux-kernel, linux-crypto, kvm, linux-coco
In-Reply-To: <cover.1780427587.git.ashish.kalra@amd.com>

From: Ashish Kalra <ashish.kalra@amd.com>

When SEV-SNP is enabled, all writes to memory are checked to ensure
integrity of SNP guest memory. This imposes performance overhead on the
whole system.

RMPOPT is a new instruction that minimizes the performance overhead of
RMP checks on the hypervisor and on non-SNP guests by allowing RMP
checks to be skipped for 1GB regions of memory that are known not to
contain any SEV-SNP guest memory.

Add support for performing RMP optimizations asynchronously using a
dedicated workqueue.

Enable RMPOPT optimizations for up to 2TB of system RAM starting from
the lowest physical memory address aligned down to a 1GB boundary at
RMP initialization time. RMP checks can initially be skipped for 1GB
memory ranges that do not contain SEV-SNP guest memory (excluding
preassigned pages such as the RMP table and firmware pages). As SNP
guests are launched, RMPUPDATE will disable the corresponding RMPOPT
optimizations.

Suggested-by: Thomas Lendacky <thomas.lendacky@amd.com>
Suggested-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Ackerley Tng <ackerleytng@google.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
 arch/x86/virt/svm/sev.c | 196 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 193 insertions(+), 3 deletions(-)

diff --git a/arch/x86/virt/svm/sev.c b/arch/x86/virt/svm/sev.c
index 089c9a14edc7..d7e40a5fe5ca 100644
--- a/arch/x86/virt/svm/sev.c
+++ b/arch/x86/virt/svm/sev.c
@@ -19,6 +19,7 @@
 #include <linux/iommu.h>
 #include <linux/amd-iommu.h>
 #include <linux/nospec.h>
+#include <linux/workqueue.h>
 
 #include <asm/sev.h>
 #include <asm/processor.h>
@@ -125,7 +126,18 @@ static void *rmp_bookkeeping __ro_after_init;
 static u64 probed_rmp_base, probed_rmp_size;
 
 static cpumask_t rmpopt_cpumask;
-static phys_addr_t rmpopt_pa_start;
+static phys_addr_t rmpopt_pa_start, rmpopt_pa_end;
+
+enum rmpopt_function {
+	RMPOPT_FUNC_VERIFY_AND_REPORT_STATUS,
+	RMPOPT_FUNC_REPORT_STATUS
+};
+
+#define RMPOPT_WORK_TIMEOUT	10000
+
+static struct workqueue_struct *rmpopt_wq;
+static struct delayed_work rmpopt_delayed_work;
+static DEFINE_MUTEX(rmpopt_wq_mutex);
 
 static LIST_HEAD(snp_leaked_pages_list);
 static DEFINE_SPINLOCK(snp_leaked_pages_list_lock);
@@ -566,6 +578,14 @@ static void rmpopt_cleanup(void)
 {
 	int cpu;
 
+	guard(mutex)(&rmpopt_wq_mutex);
+
+	if (!rmpopt_wq)
+		return;
+
+	cancel_delayed_work_sync(&rmpopt_delayed_work);
+	destroy_workqueue(rmpopt_wq);
+
 	cpus_read_lock();
 
 	for_each_cpu(cpu, &rmpopt_cpumask)
@@ -574,7 +594,8 @@ static void rmpopt_cleanup(void)
 	cpus_read_unlock();
 
 	cpumask_clear(&rmpopt_cpumask);
-	rmpopt_pa_start = 0;
+	rmpopt_pa_start = rmpopt_pa_end = 0;
+	rmpopt_wq = NULL;
 }
 
 void snp_shutdown(void)
@@ -592,6 +613,134 @@ void snp_shutdown(void)
 }
 EXPORT_SYMBOL_FOR_MODULES(snp_shutdown, "ccp");
 
+static inline bool __rmpopt(u64 pa_start, u64 op_type)
+{
+	bool optimized;
+
+	asm volatile(".byte 0xf2, 0x0f, 0x01, 0xfc"
+		     : "=@ccc" (optimized)
+		     : "a" (pa_start), "c" (op_type)
+		     : "memory", "cc");
+
+	return optimized;
+}
+
+static void rmpopt(u64 pa)
+{
+	u64 pa_start = ALIGN_DOWN(pa, SZ_1G);
+	u64 op_type = RMPOPT_FUNC_VERIFY_AND_REPORT_STATUS;
+
+	__rmpopt(pa_start, op_type);
+}
+
+/*
+ * 'val' is a system physical address.
+ */
+static void rmpopt_smp(void *val)
+{
+	rmpopt((u64)val);
+}
+
+/*
+ * RMPOPT optimizations skip RMP checks at 1GB granularity if this
+ * range of memory does not contain any SNP guest memory.
+ */
+static void rmpopt_work_handler(struct work_struct *work)
+{
+	cpumask_var_t follower_mask;
+	phys_addr_t pa;
+	int this_cpu;
+
+	pr_info("Attempt RMP optimizations on physical address range @1GB alignment [0x%016llx - 0x%016llx]\n",
+		rmpopt_pa_start, rmpopt_pa_end);
+
+	if (!alloc_cpumask_var(&follower_mask, GFP_KERNEL))
+		return;
+
+	/*
+	 * RMPOPT scans the RMP table, stores the result of the scan in the
+	 * reserved processor memory. The RMP scan is the most expensive
+	 * part. If a second RMPOPT occurs, it can skip the expensive scan
+	 * if they can see a cached result in the reserved processor memory.
+	 *
+	 * Do RMPOPT on one CPU alone. Then, follow that up with RMPOPT
+	 * on every other primary thread. Followers are "designed to"
+	 * skip the scan if they see the "cached" scan results.
+	 */
+	cpumask_copy(follower_mask, &rmpopt_cpumask);
+
+	/*
+	 * Pin the worker to the current CPU for the leader loop so that
+	 * this_cpu remains valid and the RMPOPT instruction executes on
+	 * the correct CPU.
+	 *
+	 * Use migrate_disable() rather than get_cpu() to prevent
+	 * migration while still allowing preemption.
+	 */
+	migrate_disable();
+	this_cpu = smp_processor_id();
+
+	if (cpumask_test_cpu(this_cpu, follower_mask)) {
+		/*
+		 * Current CPU is a primary thread in rmpopt_cpumask.
+		 * Run leader locally and remove from follower mask.
+		 */
+		cpumask_clear_cpu(this_cpu, follower_mask);
+
+		for (pa = rmpopt_pa_start; pa < rmpopt_pa_end; pa += SZ_1G)
+			rmpopt(pa);
+	} else if (cpumask_intersects(topology_sibling_cpumask(this_cpu),
+				      follower_mask)) {
+		/*
+		 * Current CPU is a sibling thread whose primary is in
+		 * rmpopt_cpumask.  RMPOPT_BASE MSR is per-core, so it
+		 * is safe to run the leader locally.  Remove the sibling's
+		 * primary from the follower mask as this core is already
+		 * covered by the leader.
+		 */
+		cpumask_andnot(follower_mask, follower_mask,
+			       topology_sibling_cpumask(this_cpu));
+
+		for (pa = rmpopt_pa_start; pa < rmpopt_pa_end; pa += SZ_1G)
+			rmpopt(pa);
+	} else {
+		/*
+		 * Current CPU does not have RMPOPT_BASE MSR programmed.
+		 * Pick an explicit leader from the cpumask to avoid #UD.
+		 */
+		int leader_cpu = cpumask_first(follower_mask);
+
+		if (WARN_ON_ONCE(leader_cpu >= nr_cpu_ids)) {
+			migrate_enable();
+			goto out;
+		}
+
+		cpumask_clear_cpu(leader_cpu, follower_mask);
+
+		cpus_read_lock();
+		for (pa = rmpopt_pa_start; pa < rmpopt_pa_end; pa += SZ_1G)
+			smp_call_function_single(leader_cpu, rmpopt_smp,
+						 (void *)pa, true);
+		cpus_read_unlock();
+	}
+
+	migrate_enable();
+
+	/* Followers: run RMPOPT on remaining cores */
+	cpus_read_lock();
+	for (pa = rmpopt_pa_start; pa < rmpopt_pa_end; pa += SZ_1G) {
+		on_each_cpu_mask(follower_mask, rmpopt_smp,
+				 (void *)pa, true);
+
+		 /* Give a chance for other threads to run */
+		cond_resched();
+	}
+	cpus_read_unlock();
+
+out:
+	free_cpumask_var(follower_mask);
+}
+
 void snp_setup_rmpopt(void)
 {
 	u64 rmpopt_base;
@@ -600,11 +749,35 @@ void snp_setup_rmpopt(void)
 	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
 		return;
 
+	guard(mutex)(&rmpopt_wq_mutex);
+
+	/*
+	 * Guard against re-initialization.  When SNP_SHUTDOWN_EX is issued
+	 * with x86_snp_shutdown=0, snp_shutdown() is not called and
+	 * rmpopt_cleanup() is skipped, but snp_initialized is still cleared.
+	 * A subsequent __sev_snp_init_locked() would call snp_setup_rmpopt()
+	 * again, leaking the existing workqueue, delayed work, debugfs
+	 * entries, and cpumask state.
+	 */
+	if (rmpopt_wq)
+		return;
+
+	/*
+	 * Create an RMPOPT-specific workqueue to avoid scheduling
+	 * RMPOPT workitem on the global system workqueue.
+	 */
+	rmpopt_wq = alloc_workqueue("rmpopt_wq", WQ_UNBOUND, 1);
+	if (!rmpopt_wq) {
+		pr_err("Failed to allocate RMPOPT workqueue\n");
+		return;
+	}
+
 	cpus_read_lock();
 
 	/*
 	 * The RMPOPT_BASE MSR is per-core, so only one thread per core needs
-	 * to set up the RMPOPT_BASE MSR.
+	 * to set up the RMPOPT_BASE MSR. Likewise, only one thread per core
+	 * needs to issue the RMPOPT instruction.
 	 *
 	 * Note: only online primary threads are included.  If a core's
 	 * primary thread is offline, that core is not covered.  CPU hotplug
@@ -628,6 +801,23 @@ void snp_setup_rmpopt(void)
 		wrmsrq_on_cpu(cpu, MSR_AMD64_RMPOPT_BASE, rmpopt_base);
 
 	cpus_read_unlock();
+
+	INIT_DELAYED_WORK(&rmpopt_delayed_work, rmpopt_work_handler);
+
+	rmpopt_pa_end = ALIGN(PFN_PHYS(max_pfn), SZ_1G);
+
+	/* Limit memory scanning to 2TB of RAM */
+	if ((rmpopt_pa_end - rmpopt_pa_start) > SZ_2T) {
+		pr_info("RMPOPT coverage limited to 2TB; memory above 0x%llx not optimized\n",
+			rmpopt_pa_start + SZ_2T);
+		rmpopt_pa_end = rmpopt_pa_start + SZ_2T;
+	}
+
+	/*
+	 * Once all per-CPU RMPOPT tables have been configured, enable RMPOPT
+	 * optimizations on all physical memory.
+	 */
+	queue_delayed_work(rmpopt_wq, &rmpopt_delayed_work, 0);
 }
 EXPORT_SYMBOL_FOR_MODULES(snp_setup_rmpopt, "ccp");
 
-- 
2.43.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox