Linux Modules
 help / color / mirror / Atom feed
* [PATCH v15 4/7] pkcs7: Allow the signing algo to do whatever digestion it wants itself
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
  To: Lukas Wunner, Ignat Korchagin
  Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260126142931.1940586-1-dhowells@redhat.com>

Allow the data to be verified in a PKCS#7 or CMS message to be passed
directly to an asymmetric cipher algorithm (e.g. ML-DSA) if it wants to do
whatever passes for hashing/digestion itself.  The normal digestion of the
data is then skipped as that would be ignored unless another signed info in
the message has some other algorithm that needs it.

The 'data to be verified' may be the content of the PKCS#7 message or it
will be the authenticatedAttributes (signedAttrs if CMS), modified, if
those are present.

This is done by:

 (1) Make ->m and ->m_size point to the data to be verified rather than
     making public_key_verify_signature() access the data directly.  This
     is so that keyctl(KEYCTL_PKEY_VERIFY) will still work.

 (2) Add a flag, ->algo_takes_data, to indicate that the verification
     algorithm wants to access the data to be verified directly rather than
     having it digested first.

 (3) If the PKCS#7 message has authenticatedAttributes (or CMS
     signedAttrs), then the digest contained therein will be validated as
     now, and the modified attrs blob will either be digested or assigned
     to ->m as appropriate.

 (4) If present, always copy and modify the authenticatedAttributes (or
     signedAttrs) then digest that in one go rather than calling the shash
     update twice (once for the tag and once for the rest).

 (5) For ML-DSA, point ->m to the TBSCertificate instead of digesting it
     and using the digest.

Note that whilst ML-DSA does allow for an "external mu", CMS doesn't yet
have that standardised.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
 crypto/asymmetric_keys/pkcs7_parser.c    |  4 +-
 crypto/asymmetric_keys/pkcs7_verify.c    | 52 ++++++++++++++++--------
 crypto/asymmetric_keys/signature.c       |  3 +-
 crypto/asymmetric_keys/x509_public_key.c | 10 +++++
 include/crypto/public_key.h              |  2 +
 5 files changed, 51 insertions(+), 20 deletions(-)

diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 423d13c47545..3cdbab3b9f50 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -599,8 +599,8 @@ int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
 	}
 
 	/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
-	sinfo->authattrs = value - (hdrlen - 1);
-	sinfo->authattrs_len = vlen + (hdrlen - 1);
+	sinfo->authattrs = value - hdrlen;
+	sinfo->authattrs_len = vlen + hdrlen;
 	return 0;
 }
 
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index aa085ec6fb1c..06abb9838f95 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -30,6 +30,16 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 
 	kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
 
+	if (!sinfo->authattrs && sig->algo_takes_data) {
+		/* There's no intermediate digest and the signature algo
+		 * doesn't want the data prehashing.
+		 */
+		sig->m = (void *)pkcs7->data;
+		sig->m_size = pkcs7->data_len;
+		sig->m_free = false;
+		return 0;
+	}
+
 	/* The digest was calculated already. */
 	if (sig->m)
 		return 0;
@@ -48,9 +58,10 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 	sig->m_size = crypto_shash_digestsize(tfm);
 
 	ret = -ENOMEM;
-	sig->m = kmalloc(sig->m_size, GFP_KERNEL);
+	sig->m = kmalloc(umax(sinfo->authattrs_len, sig->m_size), GFP_KERNEL);
 	if (!sig->m)
 		goto error_no_desc;
+	sig->m_free = true;
 
 	desc = kzalloc(desc_size, GFP_KERNEL);
 	if (!desc)
@@ -69,8 +80,6 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 	 * digest we just calculated.
 	 */
 	if (sinfo->authattrs) {
-		u8 tag;
-
 		if (!sinfo->msgdigest) {
 			pr_warn("Sig %u: No messageDigest\n", sinfo->index);
 			ret = -EKEYREJECTED;
@@ -96,21 +105,25 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 		 * as the contents of the digest instead.  Note that we need to
 		 * convert the attributes from a CONT.0 into a SET before we
 		 * hash it.
+		 *
+		 * However, for certain algorithms, such as ML-DSA, the digest
+		 * is integrated into the signing algorithm.  In such a case,
+		 * we copy the authattrs, modifying the tag type, and set that
+		 * as the digest.
 		 */
-		memset(sig->m, 0, sig->m_size);
-
-
-		ret = crypto_shash_init(desc);
-		if (ret < 0)
-			goto error;
-		tag = ASN1_CONS_BIT | ASN1_SET;
-		ret = crypto_shash_update(desc, &tag, 1);
-		if (ret < 0)
-			goto error;
-		ret = crypto_shash_finup(desc, sinfo->authattrs,
-					 sinfo->authattrs_len, sig->m);
-		if (ret < 0)
-			goto error;
+		memcpy(sig->m, sinfo->authattrs, sinfo->authattrs_len);
+		sig->m[0] = ASN1_CONS_BIT | ASN1_SET;
+
+		if (sig->algo_takes_data) {
+			sig->m_size = sinfo->authattrs_len;
+			ret = 0;
+		} else {
+			ret = crypto_shash_digest(desc, sig->m,
+						  sinfo->authattrs_len,
+						  sig->m);
+			if (ret < 0)
+				goto error;
+		}
 		pr_devel("AADigest = [%*ph]\n", 8, sig->m);
 	}
 
@@ -137,6 +150,11 @@ int pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf, u32 *len,
 	ret = pkcs7_digest(pkcs7, sinfo);
 	if (ret)
 		return ret;
+	if (!sinfo->sig->m_free) {
+		pr_notice_once("%s: No digest available\n", __func__);
+		return -EINVAL; /* TODO: MLDSA doesn't necessarily calculate an
+				 * intermediate digest. */
+	}
 
 	*buf = sinfo->sig->m;
 	*len = sinfo->sig->m_size;
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
index f4ec126121b3..a5ac7a53b670 100644
--- a/crypto/asymmetric_keys/signature.c
+++ b/crypto/asymmetric_keys/signature.c
@@ -28,7 +28,8 @@ void public_key_signature_free(struct public_key_signature *sig)
 		for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
 			kfree(sig->auth_ids[i]);
 		kfree(sig->s);
-		kfree(sig->m);
+		if (sig->m_free)
+			kfree(sig->m);
 		kfree(sig);
 	}
 }
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 3854f7ae4ed0..27b4fea37845 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -50,6 +50,14 @@ int x509_get_sig_params(struct x509_certificate *cert)
 
 	sig->s_size = cert->raw_sig_size;
 
+	if (sig->algo_takes_data) {
+		/* The signature algorithm does whatever passes for hashing. */
+		sig->m = (u8 *)cert->tbs;
+		sig->m_size = cert->tbs_size;
+		sig->m_free = false;
+		goto out;
+	}
+
 	/* Allocate the hashing algorithm we're going to need and find out how
 	 * big the hash operational data will be.
 	 */
@@ -69,6 +77,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	sig->m = kmalloc(sig->m_size, GFP_KERNEL);
 	if (!sig->m)
 		goto error;
+	sig->m_free = true;
 
 	desc = kzalloc(desc_size, GFP_KERNEL);
 	if (!desc)
@@ -84,6 +93,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	kfree(desc);
 error:
 	crypto_free_shash(tfm);
+out:
 	pr_devel("<==%s() = %d\n", __func__, ret);
 	return ret;
 }
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index bd38ba4d217d..4c5199b20338 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -46,6 +46,8 @@ struct public_key_signature {
 	u8 *m;			/* Message data to pass to verifier */
 	u32 s_size;		/* Number of bytes in signature */
 	u32 m_size;		/* Number of bytes in ->m */
+	bool m_free;		/* T if ->m needs freeing */
+	bool algo_takes_data;	/* T if public key algo operates on data, not a hash */
 	const char *pkey_algo;
 	const char *hash_algo;
 	const char *encoding;


^ permalink raw reply related

* [PATCH v15 3/7] pkcs7, x509: Rename ->digest to ->m
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
  To: Lukas Wunner, Ignat Korchagin
  Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260126142931.1940586-1-dhowells@redhat.com>

Rename ->digest and ->digest_len to ->m and ->m_size to represent the input
to the signature verification algorithm, reflecting that ->digest may no
longer actually *be* a digest.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Jarkko Sakkinen <jarkko@kernel.org>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
 crypto/asymmetric_keys/asymmetric_type.c |  4 ++--
 crypto/asymmetric_keys/pkcs7_verify.c    | 28 ++++++++++++------------
 crypto/asymmetric_keys/public_key.c      |  3 +--
 crypto/asymmetric_keys/signature.c       |  2 +-
 crypto/asymmetric_keys/x509_public_key.c | 10 ++++-----
 include/crypto/public_key.h              |  4 ++--
 security/integrity/digsig_asymmetric.c   |  4 ++--
 7 files changed, 26 insertions(+), 29 deletions(-)

diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index 348966ea2175..2326743310b1 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -593,10 +593,10 @@ static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
 {
 	struct public_key_signature sig = {
 		.s_size		= params->in2_len,
-		.digest_size	= params->in_len,
+		.m_size		= params->in_len,
 		.encoding	= params->encoding,
 		.hash_algo	= params->hash_algo,
-		.digest		= (void *)in,
+		.m		= (void *)in,
 		.s		= (void *)in2,
 	};
 
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 6d6475e3a9bf..aa085ec6fb1c 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -31,7 +31,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 	kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
 
 	/* The digest was calculated already. */
-	if (sig->digest)
+	if (sig->m)
 		return 0;
 
 	if (!sinfo->sig->hash_algo)
@@ -45,11 +45,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
 
 	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
-	sig->digest_size = crypto_shash_digestsize(tfm);
+	sig->m_size = crypto_shash_digestsize(tfm);
 
 	ret = -ENOMEM;
-	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
-	if (!sig->digest)
+	sig->m = kmalloc(sig->m_size, GFP_KERNEL);
+	if (!sig->m)
 		goto error_no_desc;
 
 	desc = kzalloc(desc_size, GFP_KERNEL);
@@ -59,11 +59,10 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 	desc->tfm   = tfm;
 
 	/* Digest the message [RFC2315 9.3] */
-	ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len,
-				  sig->digest);
+	ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len, sig->m);
 	if (ret < 0)
 		goto error;
-	pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest);
+	pr_devel("MsgDigest = [%*ph]\n", 8, sig->m);
 
 	/* However, if there are authenticated attributes, there must be a
 	 * message digest attribute amongst them which corresponds to the
@@ -78,14 +77,14 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 			goto error;
 		}
 
-		if (sinfo->msgdigest_len != sig->digest_size) {
+		if (sinfo->msgdigest_len != sig->m_size) {
 			pr_warn("Sig %u: Invalid digest size (%u)\n",
 				sinfo->index, sinfo->msgdigest_len);
 			ret = -EBADMSG;
 			goto error;
 		}
 
-		if (memcmp(sig->digest, sinfo->msgdigest,
+		if (memcmp(sig->m, sinfo->msgdigest,
 			   sinfo->msgdigest_len) != 0) {
 			pr_warn("Sig %u: Message digest doesn't match\n",
 				sinfo->index);
@@ -98,7 +97,8 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 		 * convert the attributes from a CONT.0 into a SET before we
 		 * hash it.
 		 */
-		memset(sig->digest, 0, sig->digest_size);
+		memset(sig->m, 0, sig->m_size);
+
 
 		ret = crypto_shash_init(desc);
 		if (ret < 0)
@@ -108,10 +108,10 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 		if (ret < 0)
 			goto error;
 		ret = crypto_shash_finup(desc, sinfo->authattrs,
-					 sinfo->authattrs_len, sig->digest);
+					 sinfo->authattrs_len, sig->m);
 		if (ret < 0)
 			goto error;
-		pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
+		pr_devel("AADigest = [%*ph]\n", 8, sig->m);
 	}
 
 error:
@@ -138,8 +138,8 @@ int pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf, u32 *len,
 	if (ret)
 		return ret;
 
-	*buf = sinfo->sig->digest;
-	*len = sinfo->sig->digest_size;
+	*buf = sinfo->sig->m;
+	*len = sinfo->sig->m_size;
 
 	i = match_string(hash_algo_name, HASH_ALGO__LAST,
 			 sinfo->sig->hash_algo);
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index e5b177c8e842..a46356e0c08b 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -425,8 +425,7 @@ int public_key_verify_signature(const struct public_key *pkey,
 	if (ret)
 		goto error_free_key;
 
-	ret = crypto_sig_verify(tfm, sig->s, sig->s_size,
-				sig->digest, sig->digest_size);
+	ret = crypto_sig_verify(tfm, sig->s, sig->s_size, sig->m, sig->m_size);
 
 error_free_key:
 	kfree_sensitive(key);
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
index 041d04b5c953..f4ec126121b3 100644
--- a/crypto/asymmetric_keys/signature.c
+++ b/crypto/asymmetric_keys/signature.c
@@ -28,7 +28,7 @@ void public_key_signature_free(struct public_key_signature *sig)
 		for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
 			kfree(sig->auth_ids[i]);
 		kfree(sig->s);
-		kfree(sig->digest);
+		kfree(sig->m);
 		kfree(sig);
 	}
 }
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 79cc7b7a0630..3854f7ae4ed0 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -63,11 +63,11 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	}
 
 	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
-	sig->digest_size = crypto_shash_digestsize(tfm);
+	sig->m_size = crypto_shash_digestsize(tfm);
 
 	ret = -ENOMEM;
-	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
-	if (!sig->digest)
+	sig->m = kmalloc(sig->m_size, GFP_KERNEL);
+	if (!sig->m)
 		goto error;
 
 	desc = kzalloc(desc_size, GFP_KERNEL);
@@ -76,9 +76,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
 
 	desc->tfm = tfm;
 
-	ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size,
-				  sig->digest);
-
+	ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, sig->m);
 	if (ret < 0)
 		goto error_2;
 
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index 81098e00c08f..bd38ba4d217d 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -43,9 +43,9 @@ extern void public_key_free(struct public_key *key);
 struct public_key_signature {
 	struct asymmetric_key_id *auth_ids[3];
 	u8 *s;			/* Signature */
-	u8 *digest;
+	u8 *m;			/* Message data to pass to verifier */
 	u32 s_size;		/* Number of bytes in signature */
-	u32 digest_size;	/* Number of bytes in digest */
+	u32 m_size;		/* Number of bytes in ->m */
 	const char *pkey_algo;
 	const char *hash_algo;
 	const char *encoding;
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 457c0a396caf..87be85f477d1 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -121,8 +121,8 @@ int asymmetric_verify(struct key *keyring, const char *sig,
 		goto out;
 	}
 
-	pks.digest = (u8 *)data;
-	pks.digest_size = datalen;
+	pks.m = (u8 *)data;
+	pks.m_size = datalen;
 	pks.s = hdr->sig;
 	pks.s_size = siglen;
 	ret = verify_signature(key, &pks);


^ permalink raw reply related

* [PATCH v15 2/7] x509: Separately calculate sha256 for blacklist
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
  To: Lukas Wunner, Ignat Korchagin
  Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260126142931.1940586-1-dhowells@redhat.com>

Calculate the SHA256 hash for blacklisting purposes independently of the
signature hash (which may be something other than SHA256).

This is necessary because when ML-DSA is used, no digest is calculated.

Note that this represents a change of behaviour in that the hash used for
the blacklist check would previously have been whatever digest was used
for, say, RSA-based signatures.  It may be that this is inadvisable.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
 crypto/asymmetric_keys/x509_parser.h     |  2 ++
 crypto/asymmetric_keys/x509_public_key.c | 22 +++++++++++++---------
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 0688c222806b..b7aeebdddb36 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -9,12 +9,14 @@
 #include <linux/time.h>
 #include <crypto/public_key.h>
 #include <keys/asymmetric-type.h>
+#include <crypto/sha2.h>
 
 struct x509_certificate {
 	struct x509_certificate *next;
 	struct x509_certificate *signer;	/* Certificate that signed this one */
 	struct public_key *pub;			/* Public key details */
 	struct public_key_signature *sig;	/* Signature parameters */
+	u8		sha256[SHA256_DIGEST_SIZE]; /* Hash for blacklist purposes */
 	char		*issuer;		/* Name of certificate issuer */
 	char		*subject;		/* Name of certificate subject */
 	struct asymmetric_key_id *id;		/* Issuer + Serial number */
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 12e3341e806b..79cc7b7a0630 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -31,6 +31,19 @@ int x509_get_sig_params(struct x509_certificate *cert)
 
 	pr_devel("==>%s()\n", __func__);
 
+	/* Calculate a SHA256 hash of the TBS and check it against the
+	 * blacklist.
+	 */
+	sha256(cert->tbs, cert->tbs_size, cert->sha256);
+	ret = is_hash_blacklisted(cert->sha256, sizeof(cert->sha256),
+				  BLACKLIST_HASH_X509_TBS);
+	if (ret == -EKEYREJECTED) {
+		pr_err("Cert %*phN is blacklisted\n",
+		       (int)sizeof(cert->sha256), cert->sha256);
+		cert->blacklisted = true;
+		ret = 0;
+	}
+
 	sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
 	if (!sig->s)
 		return -ENOMEM;
@@ -69,15 +82,6 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	if (ret < 0)
 		goto error_2;
 
-	ret = is_hash_blacklisted(sig->digest, sig->digest_size,
-				  BLACKLIST_HASH_X509_TBS);
-	if (ret == -EKEYREJECTED) {
-		pr_err("Cert %*phN is blacklisted\n",
-		       sig->digest_size, sig->digest);
-		cert->blacklisted = true;
-		ret = 0;
-	}
-
 error_2:
 	kfree(desc);
 error:


^ permalink raw reply related

* [PATCH v15 1/7] crypto: Add ML-DSA crypto_sig support
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
  To: Lukas Wunner, Ignat Korchagin
  Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260126142931.1940586-1-dhowells@redhat.com>

Add verify-only public key crypto support for ML-DSA so that the
X.509/PKCS#7 signature verification code, as used by module signing,
amongst other things, can make use of it through the common crypto_sig API.

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
 crypto/Kconfig  |   9 +++
 crypto/Makefile |   2 +
 crypto/mldsa.c  | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 212 insertions(+)
 create mode 100644 crypto/mldsa.c

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 12a87f7cf150..a210575fa5e0 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -344,6 +344,15 @@ config CRYPTO_ECRDSA
 	  One of the Russian cryptographic standard algorithms (called GOST
 	  algorithms). Only signature verification is implemented.
 
+config CRYPTO_MLDSA
+	tristate "ML-DSA (Module-Lattice-Based Digital Signature Algorithm)"
+	select CRYPTO_SIG
+	select CRYPTO_LIB_MLDSA
+	help
+	  ML-DSA (Module-Lattice-Based Digital Signature Algorithm) (FIPS-204).
+
+	  Only signature verification is implemented.
+
 endmenu
 
 menu "Block ciphers"
diff --git a/crypto/Makefile b/crypto/Makefile
index 23d3db7be425..267d5403045b 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -60,6 +60,8 @@ ecdsa_generic-y += ecdsa-p1363.o
 ecdsa_generic-y += ecdsasignature.asn1.o
 obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o
 
+obj-$(CONFIG_CRYPTO_MLDSA) += mldsa.o
+
 crypto_acompress-y := acompress.o
 crypto_acompress-y += scompress.o
 obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o
diff --git a/crypto/mldsa.c b/crypto/mldsa.c
new file mode 100644
index 000000000000..d8de082cc67a
--- /dev/null
+++ b/crypto/mldsa.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * crypto_sig wrapper around ML-DSA library.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <crypto/internal/sig.h>
+#include <crypto/mldsa.h>
+
+struct crypto_mldsa_ctx {
+	u8 pk[MAX(MAX(MLDSA44_PUBLIC_KEY_SIZE,
+		      MLDSA65_PUBLIC_KEY_SIZE),
+		  MLDSA87_PUBLIC_KEY_SIZE)];
+	unsigned int pk_len;
+	enum mldsa_alg strength;
+	bool key_set;
+};
+
+static int crypto_mldsa_sign(struct crypto_sig *tfm,
+			     const void *msg, unsigned int msg_len,
+			     void *sig, unsigned int sig_len)
+{
+	return -EOPNOTSUPP;
+}
+
+static int crypto_mldsa_verify(struct crypto_sig *tfm,
+			       const void *sig, unsigned int sig_len,
+			       const void *msg, unsigned int msg_len)
+{
+	const struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+	if (unlikely(!ctx->key_set))
+		return -EINVAL;
+
+	return mldsa_verify(ctx->strength, sig, sig_len, msg, msg_len,
+			    ctx->pk, ctx->pk_len);
+}
+
+static unsigned int crypto_mldsa_key_size(struct crypto_sig *tfm)
+{
+	struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+	switch (ctx->strength) {
+	case MLDSA44:
+		return MLDSA44_PUBLIC_KEY_SIZE;
+	case MLDSA65:
+		return MLDSA65_PUBLIC_KEY_SIZE;
+	case MLDSA87:
+		return MLDSA87_PUBLIC_KEY_SIZE;
+	default:
+		WARN_ON_ONCE(1);
+		return 0;
+	}
+}
+
+static int crypto_mldsa_set_pub_key(struct crypto_sig *tfm,
+				    const void *key, unsigned int keylen)
+{
+	struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+	unsigned int expected_len = crypto_mldsa_key_size(tfm);
+
+	if (keylen != expected_len)
+		return -EINVAL;
+
+	ctx->pk_len = keylen;
+	memcpy(ctx->pk, key, keylen);
+	ctx->key_set = true;
+	return 0;
+}
+
+static int crypto_mldsa_set_priv_key(struct crypto_sig *tfm,
+				     const void *key, unsigned int keylen)
+{
+	return -EOPNOTSUPP;
+}
+
+static unsigned int crypto_mldsa_max_size(struct crypto_sig *tfm)
+{
+	struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+	switch (ctx->strength) {
+	case MLDSA44:
+		return MLDSA44_SIGNATURE_SIZE;
+	case MLDSA65:
+		return MLDSA65_SIGNATURE_SIZE;
+	case MLDSA87:
+		return MLDSA87_SIGNATURE_SIZE;
+	default:
+		WARN_ON_ONCE(1);
+		return 0;
+	}
+}
+
+static int crypto_mldsa44_alg_init(struct crypto_sig *tfm)
+{
+	struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+	ctx->strength = MLDSA44;
+	ctx->key_set = false;
+	return 0;
+}
+
+static int crypto_mldsa65_alg_init(struct crypto_sig *tfm)
+{
+	struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+	ctx->strength = MLDSA65;
+	ctx->key_set = false;
+	return 0;
+}
+
+static int crypto_mldsa87_alg_init(struct crypto_sig *tfm)
+{
+	struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+	ctx->strength = MLDSA87;
+	ctx->key_set = false;
+	return 0;
+}
+
+static void crypto_mldsa_alg_exit(struct crypto_sig *tfm)
+{
+}
+
+static struct sig_alg crypto_mldsa_algs[] = {
+	{
+		.sign			= crypto_mldsa_sign,
+		.verify			= crypto_mldsa_verify,
+		.set_pub_key		= crypto_mldsa_set_pub_key,
+		.set_priv_key		= crypto_mldsa_set_priv_key,
+		.key_size		= crypto_mldsa_key_size,
+		.max_size		= crypto_mldsa_max_size,
+		.init			= crypto_mldsa44_alg_init,
+		.exit			= crypto_mldsa_alg_exit,
+		.base.cra_name		= "mldsa44",
+		.base.cra_driver_name	= "mldsa44-lib",
+		.base.cra_ctxsize	= sizeof(struct crypto_mldsa_ctx),
+		.base.cra_module	= THIS_MODULE,
+		.base.cra_priority	= 5000,
+	}, {
+		.sign			= crypto_mldsa_sign,
+		.verify			= crypto_mldsa_verify,
+		.set_pub_key		= crypto_mldsa_set_pub_key,
+		.set_priv_key		= crypto_mldsa_set_priv_key,
+		.key_size		= crypto_mldsa_key_size,
+		.max_size		= crypto_mldsa_max_size,
+		.init			= crypto_mldsa65_alg_init,
+		.exit			= crypto_mldsa_alg_exit,
+		.base.cra_name		= "mldsa65",
+		.base.cra_driver_name	= "mldsa65-lib",
+		.base.cra_ctxsize	= sizeof(struct crypto_mldsa_ctx),
+		.base.cra_module	= THIS_MODULE,
+		.base.cra_priority	= 5000,
+	}, {
+		.sign			= crypto_mldsa_sign,
+		.verify			= crypto_mldsa_verify,
+		.set_pub_key		= crypto_mldsa_set_pub_key,
+		.set_priv_key		= crypto_mldsa_set_priv_key,
+		.key_size		= crypto_mldsa_key_size,
+		.max_size		= crypto_mldsa_max_size,
+		.init			= crypto_mldsa87_alg_init,
+		.exit			= crypto_mldsa_alg_exit,
+		.base.cra_name		= "mldsa87",
+		.base.cra_driver_name	= "mldsa87-lib",
+		.base.cra_ctxsize	= sizeof(struct crypto_mldsa_ctx),
+		.base.cra_module	= THIS_MODULE,
+		.base.cra_priority	= 5000,
+	},
+};
+
+static int __init mldsa_init(void)
+{
+	int ret, i;
+
+	for (i = 0; i < ARRAY_SIZE(crypto_mldsa_algs); i++) {
+		ret = crypto_register_sig(&crypto_mldsa_algs[i]);
+		if (ret < 0)
+			goto error;
+	}
+	return 0;
+
+error:
+	pr_err("Failed to register (%d)\n", ret);
+	for (i--; i >= 0; i--)
+		crypto_unregister_sig(&crypto_mldsa_algs[i]);
+	return ret;
+}
+module_init(mldsa_init);
+
+static void mldsa_exit(void)
+{
+	for (int i = 0; i < ARRAY_SIZE(crypto_mldsa_algs); i++)
+		crypto_unregister_sig(&crypto_mldsa_algs[i]);
+}
+module_exit(mldsa_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Crypto API support for ML-DSA signature verification");
+MODULE_ALIAS_CRYPTO("mldsa44");
+MODULE_ALIAS_CRYPTO("mldsa65");
+MODULE_ALIAS_CRYPTO("mldsa87");


^ permalink raw reply related

* [PATCH v15 0/7] x509, pkcs7, crypto: Add ML-DSA signing
From: David Howells @ 2026-01-26 14:29 UTC (permalink / raw)
  To: Lukas Wunner, Ignat Korchagin
  Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel

Hi Lukas, Ignat,

[Note this is based on Eric Bigger's libcrypto-next branch].

These patches add ML-DSA module signing signing:

 (1) Add a crypto_sig interface for ML-DSA, verification only.

 (2) Generate a SHA256 hash of the X.509 TBSCertificate and check that in
     the blacklist.  Direct-sign ML-DSA doesn't generate an easily
     accessible hash.  Note that this changes behaviour as we no longer use
     whatever hash is specified in the certificate for this.

 (3) Rename the public_key_signature struct's "digest" and "digest_size"
     members to "m" and "m_size" to reflect that it's not necessarily a
     digest, but it is an input to the public key algorithm.

 (4) Modify PKCS#7 support to allow kernel module signatures to carry
     authenticatedAttributes as OpenSSL refuses to let them be opted out of
     for ML-DSA (CMS_NOATTR).  This adds an extra digest calculation to the
     process.

     Modify PKCS#7 to pass the authenticatedAttributes directly to the
     ML-DSA algorithm rather than passing over a digest as is done with RSA
     as ML-DSA wants to do its own hashing and will add other stuff into
     the hash.  We could use hashML-DSA or an external mu instead, but they
     aren't standardised for CMS yet.

 (5) Add support to the PKCS#7 and X.509 parsers for ML-DSA.

 (6) Modify sign-file to handle OpenSSL not permitting CMS_NOATTR with
     ML-DSA and add ML-DSA to the choice of algorithm with which to sign
     modules.  Note that this might need some more 'select' lines in the
     Kconfig to select the lib stuff as well.

 (7) Add a config option to allow authenticatedAttributes to be used with
     ML-DSA for module signing.  Ordinarily, authenticatedAttributes are
     not permitted for this purpose, however direct signing with ML-DSA
     will not be supported by OpenSSL until v4 is released.

The patches can also be found here:

	https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-pqc

David

Changes
=======
ver #15)
 - Undo a removed blank line to simplify the X.509 patch.
 - Split the rename of ->digest to ->m into its own patch.
 - In pkcs7_digest(), always copy the signedAttrs and modify rather than
   passing the replacement tag byte in a separate shash update call to the
   rest of the data.  That way the ->m buffer is very likely to be
   optimally aligned for the crypto.
 - Only allow authenticatedAttributes with ML-DSA for module signing and
   only if permission is given in the kernel config.

ver #14)
 - public_key:
   - Rename public_key::digest to public_key::m.
 - X.509:
   - Independently calculate the SHA256 hash for the blacklist check as
     an ML-DSA-signed X.509 cert doesn't generate a digest we can use.
   - Point public_key::m at the TBS data for ML-DSA.
 - PKCS#7:
   - Allocate a big enough digest buffer rather than reallocating in order
     to store the authattrs/signedattrs instead.
   - Merge the two patches that add direct signing support.
 - ML-DSA:
   - Use bool instead of u8.
   - Remove references to SHAKE in Kconfig and mention OpenSSL requirements
     there.
   - Limit ML-DSA with an intermediate hash (e.g. signedAttrs) to using
     SHA512 only.
   - Don't select CRYPTO_LIB_SHA3 for CRYPTO_MLDSA.
 - RSASSA-PSS:
   - Allow use with SHA256 and SHA384.
   - Fix calculation of emBits to be number of bits in the RSA modulus 'n'.
   - Use strncmp() not memcmp() to avoid reading beyond end of string.
   - Use correct destructor in rsassa_params_parse().
   - Drop this algo for the moment.
 - Drop the pefile_context::digest_free for now - it's only set to true and
   is unrelated to public_key::digest_free.

ver #13)
 - Allow a zero-length salt in RSASSA-PSS.
 - Don't reject ECDSA/ECRDSA with SHA256 and SHA384 otherwise the FIPS
   selftest panics when used.
 - Add a FIPS test for RSASSA-PSS (from NIST's SigVerPSS_186-3.rsp).
 - Add a FIPS test for ML-DSA (from NIST's FIPS204 JSON set).

ver #12)
 - Rebased on Eric's libcrypto-next branch.
 - Delete references to Dilithium (ML-DSA derived from this).
 - Made sign-file supply CMS_NOATTR for ML-DSA if openssl >= v4.
 - Made it possible to do ML-DSA over the data without signedAttrs.
 - Made RSASSA-PSS info parser use strsep() and match_token().
 - Cleaned the RSASSA-PSS param parsing.
 - Added limitation on what hashes can be used with what algos.
 - Moved __free()-marked variables to the point of setting.

ver #11)
 - Rebased on Eric's libcrypto-next branch.
 - Added RSASSA-PSS support patches.

ver #10)
 - Replaced the Leancrypto ML-DSA implementation with Eric's.
 - Fixed Eric's implementation to have MODULE_* info.
 - Added a patch to drive Eric's ML-DSA implementation from crypto_sig.
 - Removed SHAKE256 from the list of available module hash algorithms.
 - Changed a some more ML_DSA to MLDSA in config symbols.

ver #9)
 - ML-DSA changes:
   - Separate output into four modules (1 common, 3 strength-specific).
     - Solves Kconfig issue with needing to select at least one strength.
   - Separate the strength-specific crypto-lib APIs.
     - This is now generated by preprocessor-templating.
   - Remove the multiplexor code.
   - Multiplex the crypto-lib APIs by C type.
 - Fix the PKCS#7/X.509 code to have the correct algo names.

ver #8)
 - Moved the ML-DSA code to lib/crypto/mldsa/.
 - Renamed some bits from ml-dsa to mldsa.
 - Created a simplified API and placed that in include/crypto/mldsa.h.
 - Made the testing code use the simplified API.
 - Fixed a warning about implicitly casting between uint16_t and __le16.

ver #7)
 - Rebased on Eric's tree as that now contains all the necessary SHA-3
   infrastructure and drop the SHA-3 patches from here.
 - Added a minimal patch to provide shake256 support for crypto_sig.
 - Got rid of the memory allocation wrappers.
 - Removed the ML-DSA keypair generation code and the signing code, leaving
   only the signature verification code.
 - Removed the secret key handling code.
 - Removed the secret keys from the kunit tests and the signing testing.
 - Removed some unused bits from the ML-DSA code.
 - Downgraded the kdoc comments to ordinary comments, but keep the markup
   for easier comparison to Leancrypto.

ver #6)
 - Added a patch to make the jitterentropy RNG use lib/sha3.
 - Added back the crypto/sha3_generic changes.
 - Added ML-DSA implementation (still needs more cleanup).
 - Added kunit test for ML-DSA.
 - Modified PKCS#7 to accommodate ML-DSA.
 - Modified PKCS#7 and X.509 to allow ML-DSA to be specified and used.
 - Modified sign-file to not use CMS_NOATTR with ML-DSA.
 - Allowed SHA3 and SHAKE* algorithms for module signing default.
 - Allowed ML-DSA-{44,65,87} to be selected as the module signing default.

ver #5)
 - Fix gen-hash-testvecs.py to correctly handle algo names that contain a
   dash.
 - Fix gen-hash-testvecs.py to not generate HMAC for SHA3-* or SHAKE* as
   these don't currently have HMAC variants implemented.
 - Fix algo names to be correct.
 - Fix kunit module description as it now tests all SHA3 variants.

ver #4)
 - Fix a couple of arm64 build problems.
 - Doc fixes:
   - Fix the description of the algorithm to be closer to the NIST spec's
     terminology.
   - Don't talk of finialising the context for XOFs.
   - Don't say "Return: None".
   - Declare the "Context" to be "Any context" and make no mention of the
     fact that it might use the FPU.
   - Change "initialise" to "initialize".
   - Don't warn that the context is relatively large for stack use.
 - Use size_t for size parameters/variables.
 - Make the module_exit unconditional.
 - Dropped the crypto/ dir-affecting patches for the moment.

ver #3)
 - Renamed conflicting arm64 functions.
 - Made a separate wrapper API for each algorithm in the family.
 - Removed sha3_init(), sha3_reinit() and sha3_final().
 - Removed sha3_ctx::digest_size.
 - Renamed sha3_ctx::partial to sha3_ctx::absorb_offset.
 - Refer to the output of SHAKE* as "output" not "digest".
 - Moved the Iota transform into the one-round function.
 - Made sha3_update() warn if called after sha3_squeeze().
 - Simplified the module-load test to not do update after squeeze.
 - Added Return: and Context: kdoc statements and expanded the kdoc
   headers.
 - Added an API description document.
 - Overhauled the kunit tests.
   - Only have one kunit test.
   - Only call the general hash tester on one algo.
   - Add separate simple cursory checks for the other algos.
   - Add resqueezing tests.
   - Add some NIST example tests.
 - Changed crypto/sha3_generic to use this
 - Added SHAKE128/256 to crypto/sha3_generic and crypto/testmgr
 - Folded struct sha3_state into struct sha3_ctx.

ver #2)
  - Simplify the endianness handling.
  - Rename sha3_final() to sha3_squeeze() and don't clear the context at the
    end as it's permitted to continue calling sha3_final() to extract
    continuations of the digest (needed by ML-DSA).
  - Don't reapply the end marker to the hash state in continuation
    sha3_squeeze() unless sha3_update() gets called again (needed by
    ML-DSA).
  - Give sha3_squeeze() the amount of digest to produce as a parameter
    rather than using ctx->digest_size and don't return the amount digested.
  - Reimplement sha3_final() as a wrapper around sha3_squeeze() that
    extracts ctx->digest_size amount of digest and then zeroes out the
    context.  The latter is necessary to avoid upsetting
    hash-test-template.h.
  - Provide a sha3_reinit() function to clear the state, but to leave the
    parameters that indicate the hash properties unaffected, allowing for
    reuse.
  - Provide a sha3_set_digestsize() function to change the size of the
    digest to be extracted by sha3_final().  sha3_squeeze() takes a
    parameter for this instead.
  - Don't pass the digest size as a parameter to shake128/256_init() but
    rather default to 128/256 bits as per the function name.
  - Provide a sha3_clear() function to zero out the context.

David Howells (7):
  crypto: Add ML-DSA crypto_sig support
  x509: Separately calculate sha256 for blacklist
  pkcs7, x509: Rename ->digest to ->m
  pkcs7: Allow the signing algo to do whatever digestion it wants itself
  pkcs7, x509: Add ML-DSA support
  modsign: Enable ML-DSA module signing
  pkcs7: Allow authenticatedAttributes for ML-DSA

 Documentation/admin-guide/module-signing.rst |  16 +-
 certs/Kconfig                                |  30 +++
 certs/Makefile                               |   3 +
 crypto/Kconfig                               |   9 +
 crypto/Makefile                              |   2 +
 crypto/asymmetric_keys/Kconfig               |  11 +
 crypto/asymmetric_keys/asymmetric_type.c     |   4 +-
 crypto/asymmetric_keys/pkcs7_parser.c        |  36 +++-
 crypto/asymmetric_keys/pkcs7_parser.h        |   3 +
 crypto/asymmetric_keys/pkcs7_verify.c        |  78 ++++---
 crypto/asymmetric_keys/public_key.c          |  13 +-
 crypto/asymmetric_keys/signature.c           |   3 +-
 crypto/asymmetric_keys/x509_cert_parser.c    |  27 ++-
 crypto/asymmetric_keys/x509_parser.h         |   2 +
 crypto/asymmetric_keys/x509_public_key.c     |  42 ++--
 crypto/mldsa.c                               | 201 +++++++++++++++++++
 include/crypto/public_key.h                  |   6 +-
 include/linux/oid_registry.h                 |   5 +
 scripts/sign-file.c                          |  34 +++-
 security/integrity/digsig_asymmetric.c       |   4 +-
 20 files changed, 459 insertions(+), 70 deletions(-)
 create mode 100644 crypto/mldsa.c


^ permalink raw reply

* Re: [PATCH v14 4/5] pkcs7, x509: Add ML-DSA support
From: James Bottomley @ 2026-01-26 13:56 UTC (permalink / raw)
  To: David Howells, Jarkko Sakkinen
  Cc: Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <1903448.1769426738@warthog.procyon.org.uk>

On Mon, 2026-01-26 at 11:25 +0000, David Howells wrote:
> Jarkko Sakkinen <jarkko@kernel.org> wrote:
> 
> > Why don't we have a constant for "none"?
> > 
> > $ git grep "\"none\"" security/
> > security/apparmor/audit.c:      "none",
> > security/apparmor/lib.c:        { "none", DEBUG_NONE },
> > security/security.c:    [LOCKDOWN_NONE] = "none",
> > 
> > $ git grep "\"none\"" crypto
> > crypto/asymmetric_keys/public_key.c:                               
> >      hash_algo = "none";
> > crypto/asymmetric_keys/public_key.c:                           
> > hash_algo = "none";
> > crypto/testmgr.h: * PKCS#1 RSA test vectors for hash algorithm
> > "none"
> > 
> > IMHO, this a bad practice.
> 
> You'd think that the compiler and linker ought to be able to deal
> with read-only string sharing within compilation units.

They do ... it's -fmerge-string-constants, which has been enabled in
gcc for any optimization level above 0 for ages.  The way its supposed
to work is that each string gets its own rodata section and the linker
eliminates duplicates.

>   I don't particularly want to deal with combining every "none"
> string within the kernel into one within this patchset.

Agree: let's just rely on the tools and if they're not getting it right
someone can fix the tools.

Regards,

James


^ permalink raw reply

* Re: [PATCH v14 4/5] pkcs7, x509: Add ML-DSA support
From: Christophe Leroy (CS GROUP) @ 2026-01-26 12:02 UTC (permalink / raw)
  To: Jarkko Sakkinen, David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <aXYrvMpaQ2rHmFrw@kernel.org>



Le 25/01/2026 à 15:42, Jarkko Sakkinen a écrit :
> On Wed, Jan 21, 2026 at 10:36:06PM +0000, David Howells wrote:
>> Add support for ML-DSA keys and signatures to the CMS/PKCS#7 and X.509
>> implementations.  ML-DSA-44, -65 and -87 are all supported.  For X.509
>> certificates, the TBSCertificate is required to be signed directly; for CMS,
>> direct signing of the data is preferred, though use of SHA512 (and only that)
>> as an intermediate hash of the content is permitted with signedAttrs.
>>
>> Signed-off-by: David Howells <dhowells@redhat.com>
>> cc: Lukas Wunner <lukas@wunner.de>
>> cc: Ignat Korchagin <ignat@cloudflare.com>
>> cc: Stephan Mueller <smueller@chronox.de>
>> cc: Eric Biggers <ebiggers@kernel.org>
>> cc: Herbert Xu <herbert@gondor.apana.org.au>
>> cc: keyrings@vger.kernel.org
>> cc: linux-crypto@vger.kernel.org
>> ---
>>   crypto/asymmetric_keys/pkcs7_parser.c     | 24 +++++++++++++++++++-
>>   crypto/asymmetric_keys/public_key.c       | 10 +++++++++
>>   crypto/asymmetric_keys/x509_cert_parser.c | 27 ++++++++++++++++++++++-
>>   include/linux/oid_registry.h              |  5 +++++
>>   4 files changed, 64 insertions(+), 2 deletions(-)
>>
>> diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
>> index 3cdbab3b9f50..594a8f1d9dfb 100644
>> --- a/crypto/asymmetric_keys/pkcs7_parser.c
>> +++ b/crypto/asymmetric_keys/pkcs7_parser.c
>> @@ -95,11 +95,18 @@ static int pkcs7_check_authattrs(struct pkcs7_message *msg)
>>   	if (sinfo->authattrs) {
>>   		want = true;
>>   		msg->have_authattrs = true;
>> +	} else if (sinfo->sig->algo_takes_data) {
>> +		sinfo->sig->hash_algo = "none";
>>   	}
>>   
>> -	for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
>> +	for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next) {
>>   		if (!!sinfo->authattrs != want)
>>   			goto inconsistent;
>> +
>> +		if (!sinfo->authattrs &&
>> +		    sinfo->sig->algo_takes_data)
>> +			sinfo->sig->hash_algo = "none";
> 
> Why don't we have a constant for "none"?
> 
> $ git grep "\"none\"" security/
> security/apparmor/audit.c:      "none",
> security/apparmor/lib.c:        { "none", DEBUG_NONE },
> security/security.c:    [LOCKDOWN_NONE] = "none",
> 
> $ git grep "\"none\"" crypto
> crypto/asymmetric_keys/public_key.c:                                    hash_algo = "none";
> crypto/asymmetric_keys/public_key.c:                            hash_algo = "none";
> crypto/testmgr.h: * PKCS#1 RSA test vectors for hash algorithm "none"
> 
> IMHO, this a bad practice.

What is a bad practice ?

$ git grep "\"sha256\"" security
security/apparmor/apparmorfs.c:         dent = 
aafs_create_file("sha256", S_IFREG | 0444, dir,
security/apparmor/apparmorfs.c: return rawdata_get_link_base(dentry, 
inode, done, "sha256");
security/apparmor/apparmorfs.c:         dent = create_profile_file(dir, 
"sha256", profile,
security/integrity/ima/Kconfig: default "sha256" if IMA_DEFAULT_HASH_SHA256
security/ipe/audit.c:#define IPE_AUDIT_HASH_ALG "sha256" /* keep in sync 
with audit_policy() */

$ git grep "\"sha256\"" crypto
crypto/asymmetric_keys/mscode_parser.c:         ctx->digest_algo = "sha256";
crypto/asymmetric_keys/pkcs7_parser.c: 
ctx->sinfo->sig->hash_algo = "sha256";
crypto/asymmetric_keys/public_key.c:                strcmp(hash_algo, 
"sha256") != 0 &&
crypto/asymmetric_keys/x509_cert_parser.c: 
ctx->cert->sig->hash_algo = "sha256";
crypto/asymmetric_keys/x509_cert_parser.c: 
ctx->cert->sig->hash_algo = "sha256";
crypto/drbg.c:          .cra_name = "sha256",
crypto/drbg.c:          .backend_cra_name = "sha256",
crypto/essiv.c: /* Synchronous hash, e.g., "sha256" */
crypto/krb5/rfc8009_aes2.c:     .hash_name      = "sha256",
crypto/sha256.c:                .base.cra_name          = "sha256",
crypto/sha256.c:MODULE_ALIAS_CRYPTO("sha256");
crypto/tcrypt.c:                ret = min(ret, tcrypt_test("sha256"));
crypto/tcrypt.c:                test_hash_speed("sha256", sec, 
generic_hash_speed_template);
crypto/tcrypt.c:                test_ahash_speed("sha256", sec, 
generic_hash_speed_template);
crypto/testmgr.c:               .alg = "sha256",

How is the handling of "none" different from other hash algorithms ?

Christophe

^ permalink raw reply

* Re: [PATCH v14 4/5] pkcs7, x509: Add ML-DSA support
From: David Howells @ 2026-01-26 11:25 UTC (permalink / raw)
  To: Jarkko Sakkinen
  Cc: dhowells, Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <aXYrvMpaQ2rHmFrw@kernel.org>

Jarkko Sakkinen <jarkko@kernel.org> wrote:

> Why don't we have a constant for "none"?
> 
> $ git grep "\"none\"" security/
> security/apparmor/audit.c:      "none",
> security/apparmor/lib.c:        { "none", DEBUG_NONE },
> security/security.c:    [LOCKDOWN_NONE] = "none",
> 
> $ git grep "\"none\"" crypto
> crypto/asymmetric_keys/public_key.c:                                    hash_algo = "none";
> crypto/asymmetric_keys/public_key.c:                            hash_algo = "none";
> crypto/testmgr.h: * PKCS#1 RSA test vectors for hash algorithm "none"
> 
> IMHO, this a bad practice.

You'd think that the compiler and linker ought to be able to deal with
read-only string sharing within compilation units.  I don't particularly want
to deal with combining every "none" string within the kernel into one within
this patchset.

I could move back to using an enum of algorithms, I suppose - though again,
I'd rather not do that in this patchset.

David


^ permalink raw reply

* Re: [PATCH v14 3/5] pkcs7: Allow the signing algo to do whatever digestion it wants itself
From: David Howells @ 2026-01-26 11:11 UTC (permalink / raw)
  To: Jarkko Sakkinen
  Cc: dhowells, Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <aXYq_9XoOx5WaoU9@kernel.org>

Jarkko Sakkinen <jarkko@kernel.org> wrote:

> >  (1) Rename ->digest and ->digest_len to ->m and ->m_size to represent the
> >      input to the signature verification algorithm, reflecting that
> >      ->digest may no longer actually *be* a digest.
> ...
> These renames emit enough noise to be split into a separate patch.

Yeah, I had considered that, so I've now done that.

> > +		if (sig->algo_takes_data) {
> > +			sig->m_size = sinfo->authattrs_len;
> > +			memcpy(sig->m, sinfo->authattrs, sinfo->authattrs_len);
> > +			sig->m[0] = ASN1_CONS_BIT | ASN1_SET;
> > +			ret = 0;
> > +		} else {
> > +			u8 tag = ASN1_CONS_BIT | ASN1_SET;
> > +
> > +			ret = crypto_shash_init(desc);
> > +			if (ret < 0)
> > +				goto error;
> > +			ret = crypto_shash_update(desc, &tag, 1);
> > +			if (ret < 0)
> > +				goto error;
> > +			ret = crypto_shash_finup(desc, sinfo->authattrs + 1,
> > +						 sinfo->authattrs_len - 1,
> > +						 sig->m);
> > +			if (ret < 0)
> > +				goto error;
> > +		}

Thinking further on this, I think it's better just to do the copy and modify
unconditionally and then in the second case here just call
crypto_hash_digest().  That means we end up doing a single crypto call on an
aligned buffer.  It's not like expect the authattrs to be particularly big for
an RSA signature.

David


^ permalink raw reply

* Re: [PATCH v14 5/5] modsign: Enable ML-DSA module signing
From: Jarkko Sakkinen @ 2026-01-25 14:44 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260121223609.1650735-6-dhowells@redhat.com>

On Wed, Jan 21, 2026 at 10:36:07PM +0000, David Howells wrote:
> Allow ML-DSA module signing to be enabled.
> 
> Note that OpenSSL's CMS_*() function suite does not, as of OpenSSL-3.6,
> support the use of CMS_NOATTR with ML-DSA, so the prohibition against using
> signedAttrs with module signing has to be removed.  The selected digest
> then applies only to the algorithm used to calculate the digest stored in
> the messageDigest attribute.  The OpenSSL development branch has patches
> applied that fix this[1], but it appears that that will only be available
> in OpenSSL-4.
> 
> [1] https://github.com/openssl/openssl/pull/28923
> 
> sign-file won't set CMS_NOATTR if openssl is earlier than v4, resulting in
> the use of signed attributes.
> 
> The ML-DSA algorithm takes the raw data to be signed without regard to what
> digest algorithm is specified in the CMS message.  The CMS specified digest
> algorithm is ignored unless signedAttrs are used; in such a case, only
> SHA512 is permitted.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Eric Biggers <ebiggers@kernel.org>
> cc: Lukas Wunner <lukas@wunner.de>
> cc: Ignat Korchagin <ignat@cloudflare.com>
> cc: Stephan Mueller <smueller@chronox.de>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: keyrings@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
> ---
>  Documentation/admin-guide/module-signing.rst | 16 +++++----
>  certs/Kconfig                                | 30 +++++++++++++++++
>  certs/Makefile                               |  3 ++
>  crypto/asymmetric_keys/pkcs7_verify.c        |  4 ---
>  scripts/sign-file.c                          | 34 +++++++++++++++-----
>  5 files changed, 68 insertions(+), 19 deletions(-)
> 
> diff --git a/Documentation/admin-guide/module-signing.rst b/Documentation/admin-guide/module-signing.rst
> index a8667a777490..7f2f127dc76f 100644
> --- a/Documentation/admin-guide/module-signing.rst
> +++ b/Documentation/admin-guide/module-signing.rst
> @@ -28,10 +28,12 @@ trusted userspace bits.
>  
>  This facility uses X.509 ITU-T standard certificates to encode the public keys
>  involved.  The signatures are not themselves encoded in any industrial standard
> -type.  The built-in facility currently only supports the RSA & NIST P-384 ECDSA
> -public key signing standard (though it is pluggable and permits others to be
> -used).  The possible hash algorithms that can be used are SHA-2 and SHA-3 of
> -sizes 256, 384, and 512 (the algorithm is selected by data in the signature).
> +type.  The built-in facility currently only supports the RSA, NIST P-384 ECDSA
> +and NIST FIPS-204 ML-DSA public key signing standards (though it is pluggable
> +and permits others to be used).  For RSA and ECDSA, the possible hash
> +algorithms that can be used are SHA-2 and SHA-3 of sizes 256, 384, and 512 (the
> +algorithm is selected by data in the signature); ML-DSA does its own hashing,
> +but is allowed to be used with a SHA512 hash for signed attributes.
>  
>  
>  ==========================
> @@ -146,9 +148,9 @@ into vmlinux) using parameters in the::
>  
>  file (which is also generated if it does not already exist).
>  
> -One can select between RSA (``MODULE_SIG_KEY_TYPE_RSA``) and ECDSA
> -(``MODULE_SIG_KEY_TYPE_ECDSA``) to generate either RSA 4k or NIST
> -P-384 keypair.
> +One can select between RSA (``MODULE_SIG_KEY_TYPE_RSA``), ECDSA
> +(``MODULE_SIG_KEY_TYPE_ECDSA``) and ML-DSA (``MODULE_SIG_KEY_TYPE_MLDSA_*``) to
> +generate an RSA 4k, a NIST P-384 keypair or an ML-DSA 44, 65 or 87 keypair.
>  
>  It is strongly recommended that you provide your own x509.genkey file.
>  
> diff --git a/certs/Kconfig b/certs/Kconfig
> index 78307dc25559..2b088ef58373 100644
> --- a/certs/Kconfig
> +++ b/certs/Kconfig
> @@ -39,6 +39,36 @@ config MODULE_SIG_KEY_TYPE_ECDSA
>  	 Note: Remove all ECDSA signing keys, e.g. certs/signing_key.pem,
>  	 when falling back to building Linux 5.14 and older kernels.
>  
> +config MODULE_SIG_KEY_TYPE_MLDSA_44
> +	bool "ML-DSA-44"
> +	select CRYPTO_MLDSA
> +	help
> +	  Use an ML-DSA-44 key (NIST FIPS 204) for module signing.  ML-DSA
> +	  support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+.  With
> +	  the latter, the entire module body will be signed; with the former,
> +	  signedAttrs will be used as it lacks support for CMS_NOATTR with
> +	  ML-DSA.
> +
> +config MODULE_SIG_KEY_TYPE_MLDSA_65
> +	bool "ML-DSA-65"
> +	select CRYPTO_MLDSA
> +	help
> +	  Use an ML-DSA-65 key (NIST FIPS 204) for module signing.  ML-DSA
> +	  support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+.  With
> +	  the latter, the entire module body will be signed; with the former,
> +	  signedAttrs will be used as it lacks support for CMS_NOATTR with
> +	  ML-DSA.
> +
> +config MODULE_SIG_KEY_TYPE_MLDSA_87
> +	bool "ML-DSA-87"
> +	select CRYPTO_MLDSA
> +	help
> +	  Use an ML-DSA-87 key (NIST FIPS 204) for module signing.  ML-DSA
> +	  support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+.  With
> +	  the latter, the entire module body will be signed; with the former,
> +	  signedAttrs will be used as it lacks support for CMS_NOATTR with
> +	  ML-DSA.
> +
>  endchoice
>  
>  config SYSTEM_TRUSTED_KEYRING
> diff --git a/certs/Makefile b/certs/Makefile
> index f6fa4d8d75e0..3ee1960f9f4a 100644
> --- a/certs/Makefile
> +++ b/certs/Makefile
> @@ -43,6 +43,9 @@ targets += x509_certificate_list
>  ifeq ($(CONFIG_MODULE_SIG_KEY),certs/signing_key.pem)
>  
>  keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_ECDSA) := -newkey ec -pkeyopt ec_paramgen_curve:secp384r1
> +keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_44) := -newkey ml-dsa-44
> +keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_65) := -newkey ml-dsa-65
> +keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_87) := -newkey ml-dsa-87
>  
>  quiet_cmd_gen_key = GENKEY  $@
>        cmd_gen_key = openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
> diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
> index a5b2ed4d53fd..75d1d694dc7b 100644
> --- a/crypto/asymmetric_keys/pkcs7_verify.c
> +++ b/crypto/asymmetric_keys/pkcs7_verify.c
> @@ -431,10 +431,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
>  			pr_warn("Invalid module sig (not pkcs7-data)\n");
>  			return -EKEYREJECTED;
>  		}
> -		if (pkcs7->have_authattrs) {
> -			pr_warn("Invalid module sig (has authattrs)\n");
> -			return -EKEYREJECTED;
> -		}
>  		break;
>  	case VERIFYING_FIRMWARE_SIGNATURE:
>  		if (pkcs7->data_type != OID_data) {
> diff --git a/scripts/sign-file.c b/scripts/sign-file.c
> index 7070245edfc1..547b97097230 100644
> --- a/scripts/sign-file.c
> +++ b/scripts/sign-file.c
> @@ -315,18 +315,36 @@ int main(int argc, char **argv)
>  		ERR(!digest_algo, "EVP_get_digestbyname");
>  
>  #ifndef USE_PKCS7
> +
> +		unsigned int flags =
> +			CMS_NOCERTS |
> +			CMS_PARTIAL |
> +			CMS_BINARY |
> +			CMS_DETACHED |
> +			CMS_STREAM  |
> +			CMS_NOSMIMECAP |
> +			CMS_NO_SIGNING_TIME |
> +			use_keyid;
> +
> +		if ((EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
> +		     EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
> +		     EVP_PKEY_is_a(private_key, "ML-DSA-87")) &&
> +		    OPENSSL_VERSION_MAJOR < 4) {
> +			 /* ML-DSA + CMS_NOATTR is not supported in openssl-3.5
> +			  * and before.
> +			  */
> +			use_signed_attrs = 0;
> +		}
> +
> +		flags |= use_signed_attrs;
> +
>  		/* Load the signature message from the digest buffer. */
> -		cms = CMS_sign(NULL, NULL, NULL, NULL,
> -			       CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
> -			       CMS_DETACHED | CMS_STREAM);
> +		cms = CMS_sign(NULL, NULL, NULL, NULL, flags);
>  		ERR(!cms, "CMS_sign");
>  
> -		ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
> -				     CMS_NOCERTS | CMS_BINARY |
> -				     CMS_NOSMIMECAP | use_keyid |
> -				     use_signed_attrs),
> +		ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, flags),
>  		    "CMS_add1_signer");
> -		ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) != 1,
> +		ERR(CMS_final(cms, bm, NULL, flags) != 1,
>  		    "CMS_final");
>  
>  #else
> 

LGTM

Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>

BR, Jarkko

^ permalink raw reply

* Re: [PATCH v14 4/5] pkcs7, x509: Add ML-DSA support
From: Jarkko Sakkinen @ 2026-01-25 14:42 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260121223609.1650735-5-dhowells@redhat.com>

On Wed, Jan 21, 2026 at 10:36:06PM +0000, David Howells wrote:
> Add support for ML-DSA keys and signatures to the CMS/PKCS#7 and X.509
> implementations.  ML-DSA-44, -65 and -87 are all supported.  For X.509
> certificates, the TBSCertificate is required to be signed directly; for CMS,
> direct signing of the data is preferred, though use of SHA512 (and only that)
> as an intermediate hash of the content is permitted with signedAttrs.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Lukas Wunner <lukas@wunner.de>
> cc: Ignat Korchagin <ignat@cloudflare.com>
> cc: Stephan Mueller <smueller@chronox.de>
> cc: Eric Biggers <ebiggers@kernel.org>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: keyrings@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
> ---
>  crypto/asymmetric_keys/pkcs7_parser.c     | 24 +++++++++++++++++++-
>  crypto/asymmetric_keys/public_key.c       | 10 +++++++++
>  crypto/asymmetric_keys/x509_cert_parser.c | 27 ++++++++++++++++++++++-
>  include/linux/oid_registry.h              |  5 +++++
>  4 files changed, 64 insertions(+), 2 deletions(-)
> 
> diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
> index 3cdbab3b9f50..594a8f1d9dfb 100644
> --- a/crypto/asymmetric_keys/pkcs7_parser.c
> +++ b/crypto/asymmetric_keys/pkcs7_parser.c
> @@ -95,11 +95,18 @@ static int pkcs7_check_authattrs(struct pkcs7_message *msg)
>  	if (sinfo->authattrs) {
>  		want = true;
>  		msg->have_authattrs = true;
> +	} else if (sinfo->sig->algo_takes_data) {
> +		sinfo->sig->hash_algo = "none";
>  	}
>  
> -	for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
> +	for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next) {
>  		if (!!sinfo->authattrs != want)
>  			goto inconsistent;
> +
> +		if (!sinfo->authattrs &&
> +		    sinfo->sig->algo_takes_data)
> +			sinfo->sig->hash_algo = "none";

Why don't we have a constant for "none"?

$ git grep "\"none\"" security/
security/apparmor/audit.c:      "none",
security/apparmor/lib.c:        { "none", DEBUG_NONE },
security/security.c:    [LOCKDOWN_NONE] = "none",

$ git grep "\"none\"" crypto
crypto/asymmetric_keys/public_key.c:                                    hash_algo = "none";
crypto/asymmetric_keys/public_key.c:                            hash_algo = "none";
crypto/testmgr.h: * PKCS#1 RSA test vectors for hash algorithm "none"

IMHO, this a bad practice.


> +	}
>  	return 0;
>  
>  inconsistent:
> @@ -297,6 +304,21 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
>  		ctx->sinfo->sig->pkey_algo = "ecrdsa";
>  		ctx->sinfo->sig->encoding = "raw";
>  		break;
> +	case OID_id_ml_dsa_44:
> +		ctx->sinfo->sig->pkey_algo = "mldsa44";
> +		ctx->sinfo->sig->encoding = "raw";
> +		ctx->sinfo->sig->algo_takes_data = true;
> +		break;
> +	case OID_id_ml_dsa_65:
> +		ctx->sinfo->sig->pkey_algo = "mldsa65";
> +		ctx->sinfo->sig->encoding = "raw";
> +		ctx->sinfo->sig->algo_takes_data = true;
> +		break;
> +	case OID_id_ml_dsa_87:
> +		ctx->sinfo->sig->pkey_algo = "mldsa87";
> +		ctx->sinfo->sig->encoding = "raw";
> +		ctx->sinfo->sig->algo_takes_data = true;
> +		break;
>  	default:
>  		printk("Unsupported pkey algo: %u\n", ctx->last_oid);
>  		return -ENOPKG;
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index a46356e0c08b..09a0b83d5d77 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -142,6 +142,16 @@ software_key_determine_akcipher(const struct public_key *pkey,
>  		if (strcmp(hash_algo, "streebog256") != 0 &&
>  		    strcmp(hash_algo, "streebog512") != 0)
>  			return -EINVAL;
> +	} else if (strcmp(pkey->pkey_algo, "mldsa44") == 0 ||
> +		   strcmp(pkey->pkey_algo, "mldsa65") == 0 ||
> +		   strcmp(pkey->pkey_algo, "mldsa87") == 0) {
> +		if (strcmp(encoding, "raw") != 0)
> +			return -EINVAL;
> +		if (!hash_algo)
> +			return -EINVAL;
> +		if (strcmp(hash_algo, "none") != 0 &&
> +		    strcmp(hash_algo, "sha512") != 0)
> +			return -EINVAL;
>  	} else {
>  		/* Unknown public key algorithm */
>  		return -ENOPKG;
> diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
> index b37cae914987..2fe094f5caf3 100644
> --- a/crypto/asymmetric_keys/x509_cert_parser.c
> +++ b/crypto/asymmetric_keys/x509_cert_parser.c
> @@ -257,6 +257,15 @@ int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag,
>  	case OID_gost2012Signature512:
>  		ctx->cert->sig->hash_algo = "streebog512";
>  		goto ecrdsa;
> +	case OID_id_ml_dsa_44:
> +		ctx->cert->sig->pkey_algo = "mldsa44";
> +		goto ml_dsa;
> +	case OID_id_ml_dsa_65:
> +		ctx->cert->sig->pkey_algo = "mldsa65";
> +		goto ml_dsa;
> +	case OID_id_ml_dsa_87:
> +		ctx->cert->sig->pkey_algo = "mldsa87";
> +		goto ml_dsa;
>  	}
>  
>  rsa_pkcs1:
> @@ -274,6 +283,12 @@ int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag,
>  	ctx->cert->sig->encoding = "x962";
>  	ctx->sig_algo = ctx->last_oid;
>  	return 0;
> +ml_dsa:
> +	ctx->cert->sig->algo_takes_data = true;
> +	ctx->cert->sig->hash_algo = "none";
> +	ctx->cert->sig->encoding = "raw";
> +	ctx->sig_algo = ctx->last_oid;
> +	return 0;
>  }
>  
>  /*
> @@ -300,7 +315,8 @@ int x509_note_signature(void *context, size_t hdrlen,
>  
>  	if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 ||
>  	    strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 ||
> -	    strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0) {
> +	    strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0 ||
> +	    strncmp(ctx->cert->sig->pkey_algo, "mldsa", 5) == 0) {
>  		/* Discard the BIT STRING metadata */
>  		if (vlen < 1 || *(const u8 *)value != 0)
>  			return -EBADMSG;
> @@ -524,6 +540,15 @@ int x509_extract_key_data(void *context, size_t hdrlen,
>  			return -ENOPKG;
>  		}
>  		break;
> +	case OID_id_ml_dsa_44:
> +		ctx->cert->pub->pkey_algo = "mldsa44";
> +		break;
> +	case OID_id_ml_dsa_65:
> +		ctx->cert->pub->pkey_algo = "mldsa65";
> +		break;
> +	case OID_id_ml_dsa_87:
> +		ctx->cert->pub->pkey_algo = "mldsa87";
> +		break;
>  	default:
>  		return -ENOPKG;
>  	}
> diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
> index 6de479ebbe5d..ebce402854de 100644
> --- a/include/linux/oid_registry.h
> +++ b/include/linux/oid_registry.h
> @@ -145,6 +145,11 @@ enum OID {
>  	OID_id_rsassa_pkcs1_v1_5_with_sha3_384, /* 2.16.840.1.101.3.4.3.15 */
>  	OID_id_rsassa_pkcs1_v1_5_with_sha3_512, /* 2.16.840.1.101.3.4.3.16 */
>  
> +	/* NIST FIPS-204 ML-DSA */
> +	OID_id_ml_dsa_44,			/* 2.16.840.1.101.3.4.3.17 */
> +	OID_id_ml_dsa_65,			/* 2.16.840.1.101.3.4.3.18 */
> +	OID_id_ml_dsa_87,			/* 2.16.840.1.101.3.4.3.19 */
> +
>  	OID__NR
>  };
>  
> 

BR, Jarkko

^ permalink raw reply

* Re: [PATCH v14 3/5] pkcs7: Allow the signing algo to do whatever digestion it wants itself
From: Jarkko Sakkinen @ 2026-01-25 14:38 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260121223609.1650735-4-dhowells@redhat.com>

On Wed, Jan 21, 2026 at 10:36:05PM +0000, David Howells wrote:
> Allow the data to be verified in a PKCS#7 or CMS message to be passed
> directly to an asymmetric cipher algorithm (e.g. ML-DSA) if it wants to do
> whatever passes for hashing/digestion itself.  The normal digestion of the
> data is then skipped as that would be ignored unless another signed info in
> the message has some other algorithm that needs it.
> 
> The 'data to be verified' may be the content of the PKCS#7 message or it
> will be the authenticatedAttributes (signedAttrs if CMS), modified, if
> those are present.
> 
> This is done by:
> 
>  (1) Rename ->digest and ->digest_len to ->m and ->m_size to represent the
>      input to the signature verification algorithm, reflecting that
>      ->digest may no longer actually *be* a digest.
> 
>  (2) Make ->m and ->m_size point to the data to be verified rather than
>      making public_key_verify_signature() access the data directly.  This
>      is so that keyctl(KEYCTL_PKEY_VERIFY) will still work.

These renames emit enough noise to be split into a separate patch.

> 
>  (3) Add a flag, ->algo_takes_data, to indicate that the verification
>      algorithm wants to access the data to be verified directly rather than
>      having it digested first.
> 
>  (4) If the PKCS#7 message has authenticatedAttributes (or CMS signedAtts),
>      then the digest contained therein will be validated as now, and the
>      modified attrs blob will either be digested or assigned to ->m as
>      appropriate.
> 
>  (5) For ML-DSA, point ->m to the TBSCertificate instead of digesting it
>      and using the digest.
> 
> Note that whilst ML-DSA does allow for an "external mu", CMS doesn't yet
> have that standardised.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Lukas Wunner <lukas@wunner.de>
> cc: Ignat Korchagin <ignat@cloudflare.com>
> cc: Stephan Mueller <smueller@chronox.de>
> cc: Eric Biggers <ebiggers@kernel.org>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: keyrings@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
> ---
>  crypto/asymmetric_keys/asymmetric_type.c |  4 +-
>  crypto/asymmetric_keys/pkcs7_parser.c    |  4 +-
>  crypto/asymmetric_keys/pkcs7_verify.c    | 79 ++++++++++++++++--------
>  crypto/asymmetric_keys/public_key.c      |  3 +-
>  crypto/asymmetric_keys/signature.c       |  3 +-
>  crypto/asymmetric_keys/x509_public_key.c | 19 ++++--
>  include/crypto/public_key.h              |  6 +-
>  security/integrity/digsig_asymmetric.c   |  4 +-
>  8 files changed, 79 insertions(+), 43 deletions(-)
> 
> diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
> index 348966ea2175..2326743310b1 100644
> --- a/crypto/asymmetric_keys/asymmetric_type.c
> +++ b/crypto/asymmetric_keys/asymmetric_type.c
> @@ -593,10 +593,10 @@ static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
>  {
>  	struct public_key_signature sig = {
>  		.s_size		= params->in2_len,
> -		.digest_size	= params->in_len,
> +		.m_size		= params->in_len,
>  		.encoding	= params->encoding,
>  		.hash_algo	= params->hash_algo,
> -		.digest		= (void *)in,
> +		.m		= (void *)in,
>  		.s		= (void *)in2,
>  	};
>  
> diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
> index 423d13c47545..3cdbab3b9f50 100644
> --- a/crypto/asymmetric_keys/pkcs7_parser.c
> +++ b/crypto/asymmetric_keys/pkcs7_parser.c
> @@ -599,8 +599,8 @@ int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
>  	}
>  
>  	/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
> -	sinfo->authattrs = value - (hdrlen - 1);
> -	sinfo->authattrs_len = vlen + (hdrlen - 1);
> +	sinfo->authattrs = value - hdrlen;
> +	sinfo->authattrs_len = vlen + hdrlen;
>  	return 0;
>  }
>  
> diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
> index 6d6475e3a9bf..a5b2ed4d53fd 100644
> --- a/crypto/asymmetric_keys/pkcs7_verify.c
> +++ b/crypto/asymmetric_keys/pkcs7_verify.c
> @@ -30,8 +30,18 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
>  
>  	kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
>  
> +	if (!sinfo->authattrs && sig->algo_takes_data) {
> +		/* There's no intermediate digest and the signature algo
> +		 * doesn't want the data prehashing.
> +		 */
> +		sig->m = (void *)pkcs7->data;
> +		sig->m_size = pkcs7->data_len;
> +		sig->m_free = false;
> +		return 0;
> +	}
> +
>  	/* The digest was calculated already. */
> -	if (sig->digest)
> +	if (sig->m)
>  		return 0;
>  
>  	if (!sinfo->sig->hash_algo)
> @@ -45,12 +55,13 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
>  		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
>  
>  	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
> -	sig->digest_size = crypto_shash_digestsize(tfm);
> +	sig->m_size = crypto_shash_digestsize(tfm);
>  
>  	ret = -ENOMEM;
> -	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
> -	if (!sig->digest)
> +	sig->m = kmalloc(umax(sinfo->authattrs_len, sig->m_size), GFP_KERNEL);
> +	if (!sig->m)
>  		goto error_no_desc;
> +	sig->m_free = true;
>  
>  	desc = kzalloc(desc_size, GFP_KERNEL);
>  	if (!desc)
> @@ -59,33 +70,30 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
>  	desc->tfm   = tfm;
>  
>  	/* Digest the message [RFC2315 9.3] */
> -	ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len,
> -				  sig->digest);
> +	ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len, sig->m);
>  	if (ret < 0)
>  		goto error;
> -	pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest);
> +	pr_devel("MsgDigest = [%*ph]\n", 8, sig->m);
>  
>  	/* However, if there are authenticated attributes, there must be a
>  	 * message digest attribute amongst them which corresponds to the
>  	 * digest we just calculated.
>  	 */
>  	if (sinfo->authattrs) {
> -		u8 tag;
> -
>  		if (!sinfo->msgdigest) {
>  			pr_warn("Sig %u: No messageDigest\n", sinfo->index);
>  			ret = -EKEYREJECTED;
>  			goto error;
>  		}
>  
> -		if (sinfo->msgdigest_len != sig->digest_size) {
> +		if (sinfo->msgdigest_len != sig->m_size) {
>  			pr_warn("Sig %u: Invalid digest size (%u)\n",
>  				sinfo->index, sinfo->msgdigest_len);
>  			ret = -EBADMSG;
>  			goto error;
>  		}
>  
> -		if (memcmp(sig->digest, sinfo->msgdigest,
> +		if (memcmp(sig->m, sinfo->msgdigest,
>  			   sinfo->msgdigest_len) != 0) {
>  			pr_warn("Sig %u: Message digest doesn't match\n",
>  				sinfo->index);
> @@ -97,21 +105,33 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
>  		 * as the contents of the digest instead.  Note that we need to
>  		 * convert the attributes from a CONT.0 into a SET before we
>  		 * hash it.
> +		 *
> +		 * However, for certain algorithms, such as ML-DSA, the digest
> +		 * is integrated into the signing algorithm.  In such a case,
> +		 * we copy the authattrs, modifying the tag type, and set that
> +		 * as the digest.
>  		 */
> -		memset(sig->digest, 0, sig->digest_size);
> -
> -		ret = crypto_shash_init(desc);
> -		if (ret < 0)
> -			goto error;
> -		tag = ASN1_CONS_BIT | ASN1_SET;
> -		ret = crypto_shash_update(desc, &tag, 1);
> -		if (ret < 0)
> -			goto error;
> -		ret = crypto_shash_finup(desc, sinfo->authattrs,
> -					 sinfo->authattrs_len, sig->digest);
> -		if (ret < 0)
> -			goto error;
> -		pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
> +		if (sig->algo_takes_data) {
> +			sig->m_size = sinfo->authattrs_len;
> +			memcpy(sig->m, sinfo->authattrs, sinfo->authattrs_len);
> +			sig->m[0] = ASN1_CONS_BIT | ASN1_SET;
> +			ret = 0;
> +		} else {
> +			u8 tag = ASN1_CONS_BIT | ASN1_SET;
> +
> +			ret = crypto_shash_init(desc);
> +			if (ret < 0)
> +				goto error;
> +			ret = crypto_shash_update(desc, &tag, 1);
> +			if (ret < 0)
> +				goto error;
> +			ret = crypto_shash_finup(desc, sinfo->authattrs + 1,
> +						 sinfo->authattrs_len - 1,
> +						 sig->m);
> +			if (ret < 0)
> +				goto error;
> +		}
> +		pr_devel("AADigest = [%*ph]\n", 8, sig->m);
>  	}
>  
>  error:
> @@ -137,9 +157,14 @@ int pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf, u32 *len,
>  	ret = pkcs7_digest(pkcs7, sinfo);
>  	if (ret)
>  		return ret;
> +	if (!sinfo->sig->m_free) {
> +		pr_notice_once("%s: No digest available\n", __func__);
> +		return -EINVAL; /* TODO: MLDSA doesn't necessarily calculate an
> +				 * intermediate digest. */
> +	}
>  
> -	*buf = sinfo->sig->digest;
> -	*len = sinfo->sig->digest_size;
> +	*buf = sinfo->sig->m;
> +	*len = sinfo->sig->m_size;
>  
>  	i = match_string(hash_algo_name, HASH_ALGO__LAST,
>  			 sinfo->sig->hash_algo);
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index e5b177c8e842..a46356e0c08b 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -425,8 +425,7 @@ int public_key_verify_signature(const struct public_key *pkey,
>  	if (ret)
>  		goto error_free_key;
>  
> -	ret = crypto_sig_verify(tfm, sig->s, sig->s_size,
> -				sig->digest, sig->digest_size);
> +	ret = crypto_sig_verify(tfm, sig->s, sig->s_size, sig->m, sig->m_size);
>  
>  error_free_key:
>  	kfree_sensitive(key);
> diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
> index 041d04b5c953..a5ac7a53b670 100644
> --- a/crypto/asymmetric_keys/signature.c
> +++ b/crypto/asymmetric_keys/signature.c
> @@ -28,7 +28,8 @@ void public_key_signature_free(struct public_key_signature *sig)
>  		for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
>  			kfree(sig->auth_ids[i]);
>  		kfree(sig->s);
> -		kfree(sig->digest);
> +		if (sig->m_free)
> +			kfree(sig->m);
>  		kfree(sig);
>  	}
>  }
> diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
> index 6d002e3b20c5..27b4fea37845 100644
> --- a/crypto/asymmetric_keys/x509_public_key.c
> +++ b/crypto/asymmetric_keys/x509_public_key.c
> @@ -50,6 +50,14 @@ int x509_get_sig_params(struct x509_certificate *cert)
>  
>  	sig->s_size = cert->raw_sig_size;
>  
> +	if (sig->algo_takes_data) {
> +		/* The signature algorithm does whatever passes for hashing. */
> +		sig->m = (u8 *)cert->tbs;
> +		sig->m_size = cert->tbs_size;
> +		sig->m_free = false;
> +		goto out;
> +	}
> +
>  	/* Allocate the hashing algorithm we're going to need and find out how
>  	 * big the hash operational data will be.
>  	 */
> @@ -63,12 +71,13 @@ int x509_get_sig_params(struct x509_certificate *cert)
>  	}
>  
>  	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
> -	sig->digest_size = crypto_shash_digestsize(tfm);
> +	sig->m_size = crypto_shash_digestsize(tfm);
>  
>  	ret = -ENOMEM;
> -	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
> -	if (!sig->digest)
> +	sig->m = kmalloc(sig->m_size, GFP_KERNEL);
> +	if (!sig->m)
>  		goto error;
> +	sig->m_free = true;
>  
>  	desc = kzalloc(desc_size, GFP_KERNEL);
>  	if (!desc)
> @@ -76,8 +85,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
>  
>  	desc->tfm = tfm;
>  
> -	ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size,
> -				  sig->digest);
> +	ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, sig->m);
>  	if (ret < 0)
>  		goto error_2;
>  
> @@ -85,6 +93,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
>  	kfree(desc);
>  error:
>  	crypto_free_shash(tfm);
> +out:
>  	pr_devel("<==%s() = %d\n", __func__, ret);
>  	return ret;
>  }
> diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
> index 81098e00c08f..4c5199b20338 100644
> --- a/include/crypto/public_key.h
> +++ b/include/crypto/public_key.h
> @@ -43,9 +43,11 @@ extern void public_key_free(struct public_key *key);
>  struct public_key_signature {
>  	struct asymmetric_key_id *auth_ids[3];
>  	u8 *s;			/* Signature */
> -	u8 *digest;
> +	u8 *m;			/* Message data to pass to verifier */
>  	u32 s_size;		/* Number of bytes in signature */
> -	u32 digest_size;	/* Number of bytes in digest */
> +	u32 m_size;		/* Number of bytes in ->m */
> +	bool m_free;		/* T if ->m needs freeing */
> +	bool algo_takes_data;	/* T if public key algo operates on data, not a hash */
>  	const char *pkey_algo;
>  	const char *hash_algo;
>  	const char *encoding;
> diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
> index 457c0a396caf..87be85f477d1 100644
> --- a/security/integrity/digsig_asymmetric.c
> +++ b/security/integrity/digsig_asymmetric.c
> @@ -121,8 +121,8 @@ int asymmetric_verify(struct key *keyring, const char *sig,
>  		goto out;
>  	}
>  
> -	pks.digest = (u8 *)data;
> -	pks.digest_size = datalen;
> +	pks.m = (u8 *)data;
> +	pks.m_size = datalen;
>  	pks.s = hdr->sig;
>  	pks.s_size = siglen;
>  	ret = verify_signature(key, &pks);
> 

BR, Jarkko

^ permalink raw reply

* Re: [PATCH v14 2/5] x509: Separately calculate sha256 for blacklist
From: Jarkko Sakkinen @ 2026-01-25 14:34 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260121223609.1650735-3-dhowells@redhat.com>

On Wed, Jan 21, 2026 at 10:36:04PM +0000, David Howells wrote:
> Calculate the SHA256 hash for blacklisting purposes independently of the
> signature hash (which may be something other than SHA256).
> 
> This is necessary because when ML-DSA is used, no digest is calculated.
> 
> Note that this represents a change of behaviour in that the hash used for
> the blacklist check would previously have been whatever digest was used
> for, say, RSA-based signatures.  It may be that this is inadvisable.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Lukas Wunner <lukas@wunner.de>
> cc: Ignat Korchagin <ignat@cloudflare.com>
> cc: Stephan Mueller <smueller@chronox.de>
> cc: Eric Biggers <ebiggers@kernel.org>
> cc: Herbert Xu <herbert@gondor.apana.org.au>
> cc: keyrings@vger.kernel.org
> cc: linux-crypto@vger.kernel.org
> ---
>  crypto/asymmetric_keys/x509_parser.h     |  2 ++
>  crypto/asymmetric_keys/x509_public_key.c | 23 +++++++++++++----------
>  2 files changed, 15 insertions(+), 10 deletions(-)
> 
> diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
> index 0688c222806b..b7aeebdddb36 100644
> --- a/crypto/asymmetric_keys/x509_parser.h
> +++ b/crypto/asymmetric_keys/x509_parser.h
> @@ -9,12 +9,14 @@
>  #include <linux/time.h>
>  #include <crypto/public_key.h>
>  #include <keys/asymmetric-type.h>
> +#include <crypto/sha2.h>
>  
>  struct x509_certificate {
>  	struct x509_certificate *next;
>  	struct x509_certificate *signer;	/* Certificate that signed this one */
>  	struct public_key *pub;			/* Public key details */
>  	struct public_key_signature *sig;	/* Signature parameters */
> +	u8		sha256[SHA256_DIGEST_SIZE]; /* Hash for blacklist purposes */
>  	char		*issuer;		/* Name of certificate issuer */
>  	char		*subject;		/* Name of certificate subject */
>  	struct asymmetric_key_id *id;		/* Issuer + Serial number */
> diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
> index 12e3341e806b..6d002e3b20c5 100644
> --- a/crypto/asymmetric_keys/x509_public_key.c
> +++ b/crypto/asymmetric_keys/x509_public_key.c
> @@ -31,6 +31,19 @@ int x509_get_sig_params(struct x509_certificate *cert)
>  
>  	pr_devel("==>%s()\n", __func__);
>  
> +	/* Calculate a SHA256 hash of the TBS and check it against the
> +	 * blacklist.
> +	 */
> +	sha256(cert->tbs, cert->tbs_size, cert->sha256);
> +	ret = is_hash_blacklisted(cert->sha256, sizeof(cert->sha256),
> +				  BLACKLIST_HASH_X509_TBS);
> +	if (ret == -EKEYREJECTED) {
> +		pr_err("Cert %*phN is blacklisted\n",
> +		       (int)sizeof(cert->sha256), cert->sha256);
> +		cert->blacklisted = true;
> +		ret = 0;
> +	}
> +
>  	sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
>  	if (!sig->s)
>  		return -ENOMEM;
> @@ -65,19 +78,9 @@ int x509_get_sig_params(struct x509_certificate *cert)
>  
>  	ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size,
>  				  sig->digest);
> -

nit: spurious diff unrelated to change

>  	if (ret < 0)
>  		goto error_2;
>  
> -	ret = is_hash_blacklisted(sig->digest, sig->digest_size,
> -				  BLACKLIST_HASH_X509_TBS);
> -	if (ret == -EKEYREJECTED) {
> -		pr_err("Cert %*phN is blacklisted\n",
> -		       sig->digest_size, sig->digest);
> -		cert->blacklisted = true;
> -		ret = 0;
> -	}
> -
>  error_2:
>  	kfree(desc);
>  error:
> 

I hold on for commentary (nit was is not reason to not give
reviewed-by) tho it looks to me acceptable.

BR, Jarkko

^ permalink raw reply

* Re: [PATCH v12 06/10] crypto: Add supplementary info param to asymmetric key signature verification
From: Jarkko Sakkinen @ 2026-01-25 14:19 UTC (permalink / raw)
  To: Eric Biggers
  Cc: David Howells, Lukas Wunner, Ignat Korchagin, Herbert Xu,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel,
	David S. Miller
In-Reply-To: <20260120220321.GA6191@quark>

On Tue, Jan 20, 2026 at 02:03:21PM -0800, Eric Biggers wrote:
> On Thu, Jan 15, 2026 at 09:50:48PM +0000, David Howells wrote:
> > Add a supplementary information parameter to the asymmetric key signature
> > verification API, in particular crypto_sig_verify() and sig_alg::verify.
> > This takes the form of a printable string containing of key=val elements.
> 
> As I'm sure you're aware, C has native support for function parameters.
> No need to serialize to a string on the caller side and then deserialize
> in the callee.
> 
> This is yet another example of a case where trying to fit different
> algorithms into a generic API doesn't work well.
> 
> We should just have a library API for each signature algorithm, with
> each algorithm taking the parameters it needs.

This would be a great idea IMHO. I'm looking into renewing my TPM2
asymmetric keys patch set some day, and e.g., for that such primitives
would be more ergonomic fit.

> 
> - Eric

BR, Jarkko

^ permalink raw reply

* Re: [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself
From: Jarkko Sakkinen @ 2026-01-24 11:46 UTC (permalink / raw)
  To: David Howells
  Cc: Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
	Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
	linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <1501916.1768998695@warthog.procyon.org.uk>

On Wed, Jan 21, 2026 at 12:31:35PM +0000, David Howells wrote:
> Jarkko Sakkinen <jarkko@kernel.org> wrote:
> 
> > I'd use the wording you used already in commit message, which
> > factors more descriptive than what you have here. E.g., name
> > it "external_digest".
> 
> ML-DSA uses "external" to mean that the caller does the
> digestion/hashing/XOF-ing/whatever Eric wants to call it, but the caller also
> has to put other stuff into the digest/hash/XOF/thing that then gets passed to
> ML-DSA if it does this.
> 
> For added confusion, the NIST FIPS tests seem to consider what this patch does
> as 'external' but an "external mu" as 'internal':
> 
> 	"tgId": 1,
> 	"testType": "AFT",
> 	"parameterSet": "ML-DSA-44",
> 	"signatureInterface": "external",
> 	"preHash": "pure",
> 
> vs:
> 
> 	"tgId": 7,
> 	"testType": "AFT",
> 	"parameterSet": "ML-DSA-44",
> 	"signatureInterface": "internal",
> 	"externalMu": true,
> 
> I haven't come up with a better name that particularly describes this.  Maybe
> use "no_prehash" or "algo_takes_hash" or "algo_takes_data"?
> 
> Maybe better than using a true/false value, use an enum?
> 
> 	enum public_key_hash {
> 		ALGO_SIGNS_HASH, /* RSA, ECDSA, ... */
> 		ALGO_SIGNS_DATA, /* MLDSA, ... */
> 	};

I think this would be better idea, as it makes the states more explicit.

And I was actually considering to suggest enum so yeah, I'm on board
with this suggestion.

> 
> David
> 

BR, Jarkko

^ permalink raw reply

* Re: [RFC PATCH 1/1] module: speed modprobe by adding name_crc to struct module
From: jim.cromie @ 2026-01-23 23:33 UTC (permalink / raw)
  To: Daniel Gomez
  Cc: Petr Pavlu, Luis Chamberlain, Sami Tolvanen, Aaron Tomlin,
	linux-modules, linux-kernel
In-Reply-To: <aXNNpCl2lKb9YXJN@macos>

On Fri, Jan 23, 2026 at 3:32 AM Daniel Gomez <da.gomez@kernel.org> wrote:
>
> On 2026-01-23 10:36, Petr Pavlu wrote:
> > On 1/23/26 12:46 AM, Jim Cromie wrote:
> > > "modprobe foo" currently does strcmp on the name, this can be improved.
> > >
> > > So this commit:
> > >
> > > 1. adds name_crc to struct module
> > > 2. modpost.c computes the value and
> > > 3. outputs it for "modinfo foo" to see/use.
> > >
> > > 4. adds hotpath to find_module_all()
> > >    this uses name_crc to do quick "name-check"
> > >    falls back to strcmp only to guard against collisions.
> > >
> > > This should significantly reduce modprobe workload, and shorten module
> > > load-time.
> > >
> > > Since it alters struct module, its binary incompatible. This means:
> > >
> > > 1. RFC for its wide "blast radius".
> > > 2. suitable for major version bump *only*
> > >
> > > 3. it opens door for further struct module reorg, to:
> > >    a. segregate fields by "temperature"
> > >    b. pack out paholes.
> > >    c. improve cache locality (by reordering coldest on bottom)
> > >       name should be cold now.
> > >       bikeshedding is appropriate here.
> > >
> > > NB: this isn't a substitute for CONFIG_MODULE_SIG.
> > > It reimplements crc_le(), doesn't reuse kernel's version.
> > >
> > > CC: Luis Chamberlain <mcgrof@kernel.org>
> > > CC: Petr Pavlu <petr.pavlu@suse.com>
> > > CC: Daniel Gomez <da.gomez@kernel.org>
> > > CC: Sami Tolvanen <samitolvanen@google.com>
> > > CC: Aaron Tomlin <atomlin@atomlin.com>
> > > CC: linux-modules@vger.kernel.org
> > >
> > > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> > >
> > >  '#' will be ignored, and an empty message aborts the commit.
> >
> > This patch looks as if it were generated by AI. If so, please avoid
> > sending such changes. Otherwise, the commit description should explain
>
> FYI, this is a process already documented. You can check out what maintainers
> expect from contributions and possible guidelines:
>
> https://lore.kernel.org/all/20260119200418.89541-1-dave.hansen@linux.intel.com/

Thanks, from LWN, I knew the topic was being discussed, but I was
unaware of its resolution.

FTR, I did argue with the AI, it gave me the crc_le() fn, which let me
proceed and test the patch.

^ permalink raw reply

* Re: [RFC PATCH 1/1] module: speed modprobe by adding name_crc to struct module
From: jim.cromie @ 2026-01-23 23:24 UTC (permalink / raw)
  To: Christophe Leroy (CS GROUP)
  Cc: linux-kernel, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
	Sami Tolvanen, Aaron Tomlin, linux-modules
In-Reply-To: <CAJfuBxx5q_jyDgH+dvJZSxwus5wxxo-4q6r0Mt1N49VLz96T4A@mail.gmail.com>

Apologies, I hit send too soon, and missed some of your points.

name_hash vs name_crc
was failure to recheck my names for consistency.

On Fri, Jan 23, 2026 at 4:10 PM <jim.cromie@gmail.com> wrote:
>
> On Fri, Jan 23, 2026 at 4:39 AM Christophe Leroy (CS GROUP)
> <chleroy@kernel.org> wrote:
> >
> >
> >
> > Le 23/01/2026 à 00:46, Jim Cromie a écrit :
> > > [Vous ne recevez pas souvent de courriers de jim.cromie@gmail.com. Découvrez pourquoi ceci est important à https://aka.ms/LearnAboutSenderIdentification ]
> > >
> > > "modprobe foo" currently does strcmp on the name, this can be improved.
> > >
> > > So this commit:
> > >
> > > 1. adds name_crc to struct module
> > > 2. modpost.c computes the value and
> > > 3. outputs it for "modinfo foo" to see/use.
> > >
> > > 4. adds hotpath to find_module_all()
> > >     this uses name_crc to do quick "name-check"
> > >     falls back to strcmp only to guard against collisions.
> > >
> > > This should significantly reduce modprobe workload, and shorten module
> > > load-time.
> >
> > Any numbers of how significant is the reduction ?
>
> Not at this time.
> In absolute terms, my box is running fedora, has 165 modules,
> so the significance is minor in most circumstances.
> In relative terms, a numerical equality test is much faster than strcmp.
>
> I recall seeing Luis doing quite a bit of work tuning module loading,
> I was hoping he could shed light / opine / provide numbers
> on the utility of this.
>
> >
> > >
> > > Since it alters struct module, its binary incompatible. This means:
> > >
> > > 1. RFC for its wide "blast radius".
> > > 2. suitable for major version bump *only*
> > >
> > > 3. it opens door for further struct module reorg, to:
> > >     a. segregate fields by "temperature"
> > >     b. pack out paholes.
> > >     c. improve cache locality (by reordering coldest on bottom)
> > >        name should be cold now.
> > >        bikeshedding is appropriate here.
> > >
> > > NB: this isn't a substitute for CONFIG_MODULE_SIG.
> > > It reimplements crc_le(), doesn't reuse kernel's version.
> >
> > Why not use the kernel's version ?
>
> I briefly fiddled with doing so, but sorting the includes looked like a hassle,
> so I punted and asked the AI for an implementation.
>
>
> >
> > >
> > > CC: Luis Chamberlain <mcgrof@kernel.org>
> > > CC: Petr Pavlu <petr.pavlu@suse.com>
> > > CC: Daniel Gomez <da.gomez@kernel.org>
> > > CC: Sami Tolvanen <samitolvanen@google.com>
> > > CC: Aaron Tomlin <atomlin@atomlin.com>
> > > CC: linux-modules@vger.kernel.org
> > >
> > > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> > >
> > >   '#' will be ignored, and an empty message aborts the commit.
> > > ---
> > >   include/linux/module.h | 15 ++++++++-------
> > >   kernel/module/main.c   |  8 ++++++--
> > >   scripts/mod/modpost.c  | 18 ++++++++++++++++++
> > >   scripts/mod/modpost.h  |  6 +++++-
> > >   4 files changed, 37 insertions(+), 10 deletions(-)
> > >
> > > diff --git a/include/linux/module.h b/include/linux/module.h
> > > index d80c3ea57472..4ea6c5ae3374 100644
> > > --- a/include/linux/module.h
> > > +++ b/include/linux/module.h
> > > @@ -402,10 +402,18 @@ struct klp_modinfo {
> > >
> > >   struct module {
> > >          enum module_state state;
> > > +       u32 name_hash;
> >
> > In the subject you say "name_crc"
> >
> > >
> > >          /* Member of list of modules */
> > >          struct list_head list;
> > >
> > > +       /* Sysfs stuff. */
> > > +       struct module_kobject mkobj;
> > > +       struct module_attribute *modinfo_attrs;
> > > +       const char *version;
> > > +       const char *srcversion;
> > > +       struct kobject *holders_dir;
> > > +
> >
> > Shouldn't this move be another patch ?
> >
> > >          /* Unique handle for this module */
> > >          char name[MODULE_NAME_LEN];
> > >
> > > @@ -414,13 +422,6 @@ struct module {
> > >          unsigned char build_id[BUILD_ID_SIZE_MAX];
> > >   #endif
> > >
> > > -       /* Sysfs stuff. */
> > > -       struct module_kobject mkobj;
> > > -       struct module_attribute *modinfo_attrs;
> > > -       const char *version;
> > > -       const char *srcversion;
> > > -       struct kobject *holders_dir;
> > > -
> > >          /* Exported symbols */
> > >          const struct kernel_symbol *syms;
> > >          const u32 *crcs;
> > > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > > index d855f43a2be3..685218b2c5ef 100644
> > > --- a/kernel/module/main.c
> > > +++ b/kernel/module/main.c
> > > @@ -39,6 +39,7 @@
> > >   #include <linux/mutex.h>
> > >   #include <linux/rculist.h>
> > >   #include <linux/uaccess.h>
> > > +#include <linux/crc32.h>
> > >   #include <asm/cacheflush.h>
> > >   #include <linux/set_memory.h>
> > >   #include <asm/mmu_context.h>
> > > @@ -431,13 +432,16 @@ struct module *find_module_all(const char *name, size_t len,
> > >                                 bool even_unformed)
> > >   {
> > >          struct module *mod;
> > > +       u32 incoming_name_hash = crc32_le(0, name, len);
> > >
> > >          list_for_each_entry_rcu(mod, &modules, list,
> > >                                  lockdep_is_held(&module_mutex)) {
> > >                  if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
> > >                          continue;
> > > -               if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
> > > -                       return mod;
> > > +               if (mod->name_hash == incoming_name_hash) {
> > > +                       if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
> > > +                               return mod;
> > > +               }
> >
> > Why not just adding the following instead of modifing existing test:

thats an alternative.
I modified the existing test cuz its qualitatively the same test,
except for collisions.

> >
> >         if (mod->name_hash != incoming_name_hash)
> >                 continue;
> >
> > >          }
> > >          return NULL;
> > >   }
> > > diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> > > index 755b842f1f9b..ae90e0bf9330 100644
> > > --- a/scripts/mod/modpost.c
> > > +++ b/scripts/mod/modpost.c
> > > @@ -21,6 +21,22 @@
> > >   #include <stdbool.h>
> > >   #include <errno.h>
> > >
> > > +/* Local CRC32 implementation for modpost.c */
> > > +#define CRCPOLY_LE 0xEDB88320
> > > +
> > > +typedef uint32_t u32;
> > > +
> > > +static u32 crc32_le(u32 crc,  char  *p, size_t len)
> > > +{
> > > +       int i;
> > > +       while (len--) {
> > > +               crc ^= *p++;
> > > +               for (i = 0; i < 8; i++)
> > > +                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
> > > +       }
> > > +       return crc;
> > > +}
> > > +
> >
> > Why do you re-implement crc32_le() ?

I didnt want to wrestle with the headers.
If theres utility here, I can do so.

> >
> > >   #include <hash.h>
> > >   #include <hashtable.h>
> > >   #include <list.h>
> > > @@ -1581,6 +1597,7 @@ static void read_symbols(const char *modname)
> > >
> > >          /* strip trailing .o */
> > >          mod = new_module(modname, strlen(modname) - strlen(".o"));
> > > +       mod->name_hash = crc32_le(0, mod->name, strlen(mod->name));
> > >
> > >          /* save .no_trim_symbol section for later use */
> > >          if (info.no_trim_symbol_len) {
> > > @@ -1834,6 +1851,7 @@ static void add_header(struct buffer *b, struct module *mod)
> > >          buf_printf(b, "#include <linux/compiler.h>\n");
> > >          buf_printf(b, "\n");
> > >          buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
> > > +       buf_printf(b, "MODULE_INFO(name_crc, \"0x%08x\");\n", mod->name_hash);
> > >          buf_printf(b, "\n");
> > >          buf_printf(b, "__visible struct module __this_module\n");
> > >          buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
> > > diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
> > > index 2aecb8f25c87..3fc3cfd0a039 100644
> > > --- a/scripts/mod/modpost.h
> > > +++ b/scripts/mod/modpost.h
> > > @@ -11,11 +11,14 @@
> > >   #include <fcntl.h>
> > >   #include <unistd.h>
> > >   #include <elf.h>
> > > +#include <stdint.h>
> > >   #include "../../include/linux/module_symbol.h"
> > >
> > >   #include <list_types.h>
> > >   #include "elfconfig.h"
> > >
> > > +typedef uint32_t u32;
> > > +
> > >   /* On BSD-alike OSes elf.h defines these according to host's word size */
> > >   #undef ELF_ST_BIND
> > >   #undef ELF_ST_TYPE
> > > @@ -126,7 +129,8 @@ struct module {
> > >          bool seen;
> > >          bool has_init;
> > >          bool has_cleanup;
> > > -       char         srcversion[25];
> > > +               char         srcversion[25];
> > > +               u32          name_hash;
> > >          // Missing namespace dependencies
> > >          struct list_head missing_namespaces;
> > >          // Actual imported namespaces
> > > --
> > > 2.52.0
> > >
> > >
> >

^ permalink raw reply

* Re: [RFC PATCH 1/1] module: speed modprobe by adding name_crc to struct module
From: jim.cromie @ 2026-01-23 23:10 UTC (permalink / raw)
  To: Christophe Leroy (CS GROUP)
  Cc: linux-kernel, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
	Sami Tolvanen, Aaron Tomlin, linux-modules
In-Reply-To: <6277616a-e66d-4ed1-b5d2-270f95d6eacc@kernel.org>

On Fri, Jan 23, 2026 at 4:39 AM Christophe Leroy (CS GROUP)
<chleroy@kernel.org> wrote:
>
>
>
> Le 23/01/2026 à 00:46, Jim Cromie a écrit :
> > [Vous ne recevez pas souvent de courriers de jim.cromie@gmail.com. Découvrez pourquoi ceci est important à https://aka.ms/LearnAboutSenderIdentification ]
> >
> > "modprobe foo" currently does strcmp on the name, this can be improved.
> >
> > So this commit:
> >
> > 1. adds name_crc to struct module
> > 2. modpost.c computes the value and
> > 3. outputs it for "modinfo foo" to see/use.
> >
> > 4. adds hotpath to find_module_all()
> >     this uses name_crc to do quick "name-check"
> >     falls back to strcmp only to guard against collisions.
> >
> > This should significantly reduce modprobe workload, and shorten module
> > load-time.
>
> Any numbers of how significant is the reduction ?

Not at this time.
In absolute terms, my box is running fedora, has 165 modules,
so the significance is minor in most circumstances.
In relative terms, a numerical equality test is much faster than strcmp.

I recall seeing Luis doing quite a bit of work tuning module loading,
I was hoping he could shed light / opine / provide numbers
on the utility of this.

>
> >
> > Since it alters struct module, its binary incompatible. This means:
> >
> > 1. RFC for its wide "blast radius".
> > 2. suitable for major version bump *only*
> >
> > 3. it opens door for further struct module reorg, to:
> >     a. segregate fields by "temperature"
> >     b. pack out paholes.
> >     c. improve cache locality (by reordering coldest on bottom)
> >        name should be cold now.
> >        bikeshedding is appropriate here.
> >
> > NB: this isn't a substitute for CONFIG_MODULE_SIG.
> > It reimplements crc_le(), doesn't reuse kernel's version.
>
> Why not use the kernel's version ?

I briefly fiddled with doing so, but sorting the includes looked like a hassle,
so I punted and asked the AI for an implementation.


>
> >
> > CC: Luis Chamberlain <mcgrof@kernel.org>
> > CC: Petr Pavlu <petr.pavlu@suse.com>
> > CC: Daniel Gomez <da.gomez@kernel.org>
> > CC: Sami Tolvanen <samitolvanen@google.com>
> > CC: Aaron Tomlin <atomlin@atomlin.com>
> > CC: linux-modules@vger.kernel.org
> >
> > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> >
> >   '#' will be ignored, and an empty message aborts the commit.
> > ---
> >   include/linux/module.h | 15 ++++++++-------
> >   kernel/module/main.c   |  8 ++++++--
> >   scripts/mod/modpost.c  | 18 ++++++++++++++++++
> >   scripts/mod/modpost.h  |  6 +++++-
> >   4 files changed, 37 insertions(+), 10 deletions(-)
> >
> > diff --git a/include/linux/module.h b/include/linux/module.h
> > index d80c3ea57472..4ea6c5ae3374 100644
> > --- a/include/linux/module.h
> > +++ b/include/linux/module.h
> > @@ -402,10 +402,18 @@ struct klp_modinfo {
> >
> >   struct module {
> >          enum module_state state;
> > +       u32 name_hash;
>
> In the subject you say "name_crc"
>
> >
> >          /* Member of list of modules */
> >          struct list_head list;
> >
> > +       /* Sysfs stuff. */
> > +       struct module_kobject mkobj;
> > +       struct module_attribute *modinfo_attrs;
> > +       const char *version;
> > +       const char *srcversion;
> > +       struct kobject *holders_dir;
> > +
>
> Shouldn't this move be another patch ?
>
> >          /* Unique handle for this module */
> >          char name[MODULE_NAME_LEN];
> >
> > @@ -414,13 +422,6 @@ struct module {
> >          unsigned char build_id[BUILD_ID_SIZE_MAX];
> >   #endif
> >
> > -       /* Sysfs stuff. */
> > -       struct module_kobject mkobj;
> > -       struct module_attribute *modinfo_attrs;
> > -       const char *version;
> > -       const char *srcversion;
> > -       struct kobject *holders_dir;
> > -
> >          /* Exported symbols */
> >          const struct kernel_symbol *syms;
> >          const u32 *crcs;
> > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > index d855f43a2be3..685218b2c5ef 100644
> > --- a/kernel/module/main.c
> > +++ b/kernel/module/main.c
> > @@ -39,6 +39,7 @@
> >   #include <linux/mutex.h>
> >   #include <linux/rculist.h>
> >   #include <linux/uaccess.h>
> > +#include <linux/crc32.h>
> >   #include <asm/cacheflush.h>
> >   #include <linux/set_memory.h>
> >   #include <asm/mmu_context.h>
> > @@ -431,13 +432,16 @@ struct module *find_module_all(const char *name, size_t len,
> >                                 bool even_unformed)
> >   {
> >          struct module *mod;
> > +       u32 incoming_name_hash = crc32_le(0, name, len);
> >
> >          list_for_each_entry_rcu(mod, &modules, list,
> >                                  lockdep_is_held(&module_mutex)) {
> >                  if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
> >                          continue;
> > -               if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
> > -                       return mod;
> > +               if (mod->name_hash == incoming_name_hash) {
> > +                       if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
> > +                               return mod;
> > +               }
>
> Why not just adding the following instead of modifing existing test:
>
>         if (mod->name_hash != incoming_name_hash)
>                 continue;
>
> >          }
> >          return NULL;
> >   }
> > diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> > index 755b842f1f9b..ae90e0bf9330 100644
> > --- a/scripts/mod/modpost.c
> > +++ b/scripts/mod/modpost.c
> > @@ -21,6 +21,22 @@
> >   #include <stdbool.h>
> >   #include <errno.h>
> >
> > +/* Local CRC32 implementation for modpost.c */
> > +#define CRCPOLY_LE 0xEDB88320
> > +
> > +typedef uint32_t u32;
> > +
> > +static u32 crc32_le(u32 crc,  char  *p, size_t len)
> > +{
> > +       int i;
> > +       while (len--) {
> > +               crc ^= *p++;
> > +               for (i = 0; i < 8; i++)
> > +                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
> > +       }
> > +       return crc;
> > +}
> > +
>
> Why do you re-implement crc32_le() ?
>
> >   #include <hash.h>
> >   #include <hashtable.h>
> >   #include <list.h>
> > @@ -1581,6 +1597,7 @@ static void read_symbols(const char *modname)
> >
> >          /* strip trailing .o */
> >          mod = new_module(modname, strlen(modname) - strlen(".o"));
> > +       mod->name_hash = crc32_le(0, mod->name, strlen(mod->name));
> >
> >          /* save .no_trim_symbol section for later use */
> >          if (info.no_trim_symbol_len) {
> > @@ -1834,6 +1851,7 @@ static void add_header(struct buffer *b, struct module *mod)
> >          buf_printf(b, "#include <linux/compiler.h>\n");
> >          buf_printf(b, "\n");
> >          buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
> > +       buf_printf(b, "MODULE_INFO(name_crc, \"0x%08x\");\n", mod->name_hash);
> >          buf_printf(b, "\n");
> >          buf_printf(b, "__visible struct module __this_module\n");
> >          buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
> > diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
> > index 2aecb8f25c87..3fc3cfd0a039 100644
> > --- a/scripts/mod/modpost.h
> > +++ b/scripts/mod/modpost.h
> > @@ -11,11 +11,14 @@
> >   #include <fcntl.h>
> >   #include <unistd.h>
> >   #include <elf.h>
> > +#include <stdint.h>
> >   #include "../../include/linux/module_symbol.h"
> >
> >   #include <list_types.h>
> >   #include "elfconfig.h"
> >
> > +typedef uint32_t u32;
> > +
> >   /* On BSD-alike OSes elf.h defines these according to host's word size */
> >   #undef ELF_ST_BIND
> >   #undef ELF_ST_TYPE
> > @@ -126,7 +129,8 @@ struct module {
> >          bool seen;
> >          bool has_init;
> >          bool has_cleanup;
> > -       char         srcversion[25];
> > +               char         srcversion[25];
> > +               u32          name_hash;
> >          // Missing namespace dependencies
> >          struct list_head missing_namespaces;
> >          // Actual imported namespaces
> > --
> > 2.52.0
> >
> >
>

^ permalink raw reply

* Re: [PATCH v3 0/2] Improve handling of the __klp_{objects,funcs} sections in modules
From: Josh Poimboeuf @ 2026-01-23 17:50 UTC (permalink / raw)
  To: Petr Pavlu
  Cc: Jiri Kosina, Miroslav Benes, Petr Mladek, Joe Lawrence,
	Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
	Peter Zijlstra, live-patching, linux-modules, linux-kernel
In-Reply-To: <20260123102825.3521961-1-petr.pavlu@suse.com>

On Fri, Jan 23, 2026 at 11:26:55AM +0100, Petr Pavlu wrote:
> Changes since v2 [1]:
> - Generalize the helper function that locates __klp_objects in a module
>   to allow it to find any data in other sections as well.
> 
> Changes since v1 [2]:
> - Generalize the helper function that locates __klp_objects in a module
>   to allow it to find objects in other sections as well.
> 
> [1] https://lore.kernel.org/linux-modules/20260121082842.3050453-1-petr.pavlu@suse.com/
> [2] https://lore.kernel.org/linux-modules/20260114123056.2045816-1-petr.pavlu@suse.com/
> 
> Petr Pavlu (2):
>   livepatch: Fix having __klp_objects relics in non-livepatch modules
>   livepatch: Free klp_{object,func}_ext data after initialization

Thanks!

Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>

-- 
Josh

^ permalink raw reply

* IMA and PQC
From: David Howells @ 2026-01-23 17:43 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: dhowells, Simo Sorce, Roberto Sassu, Dmitry Kasatkin,
	Eric Snowberg, Eric Biggers, linux-integrity, linux-crypto,
	keyrings, linux-modules, linux-kernel

Hi Mimi,

I've posted patches which I hope will accepted to implement ML-DSA module
signing:

	https://lore.kernel.org/linux-crypto/1753972.1769166821@warthog.procyon.org.uk/T/#t

but for the moment, it will give an error to pkcs7_get_digest() if there's no
digest available (which there won't be with ML-DSA).  This means that there
isn't a hash for IMA to get at for TPM measurement.

Now, I probably have to make a SHA256 hash anyway for UEFI blacklisting
purposes, so that could be used.  Alternatively, we can require the use of
authenticatedAttributes/signedAttrs and give you the hash of that - but then
you're a bit at the mercy of whatever hashes were used.

Further, we need to think how we're going to do PQC support in IMA -
particularly as the signatures are so much bigger and verification slower.

Would ML-DSA-44 be acceptable?  Should we grab some internal state out of
ML-DSA to use in lieu of a hash?

David


^ permalink raw reply

* Re: [RFC PATCH 1/1] module: speed modprobe by adding name_crc to struct module
From: Christophe Leroy (CS GROUP) @ 2026-01-23 11:39 UTC (permalink / raw)
  To: Jim Cromie, linux-kernel
  Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Aaron Tomlin, linux-modules
In-Reply-To: <20260122234621.3403276-1-jim.cromie@gmail.com>



Le 23/01/2026 à 00:46, Jim Cromie a écrit :
> [Vous ne recevez pas souvent de courriers de jim.cromie@gmail.com. Découvrez pourquoi ceci est important à https://aka.ms/LearnAboutSenderIdentification ]
> 
> "modprobe foo" currently does strcmp on the name, this can be improved.
> 
> So this commit:
> 
> 1. adds name_crc to struct module
> 2. modpost.c computes the value and
> 3. outputs it for "modinfo foo" to see/use.
> 
> 4. adds hotpath to find_module_all()
>     this uses name_crc to do quick "name-check"
>     falls back to strcmp only to guard against collisions.
> 
> This should significantly reduce modprobe workload, and shorten module
> load-time.

Any numbers of how significant is the reduction ?

> 
> Since it alters struct module, its binary incompatible. This means:
> 
> 1. RFC for its wide "blast radius".
> 2. suitable for major version bump *only*
> 
> 3. it opens door for further struct module reorg, to:
>     a. segregate fields by "temperature"
>     b. pack out paholes.
>     c. improve cache locality (by reordering coldest on bottom)
>        name should be cold now.
>        bikeshedding is appropriate here.
> 
> NB: this isn't a substitute for CONFIG_MODULE_SIG.
> It reimplements crc_le(), doesn't reuse kernel's version.

Why not use the kernel's version ?

> 
> CC: Luis Chamberlain <mcgrof@kernel.org>
> CC: Petr Pavlu <petr.pavlu@suse.com>
> CC: Daniel Gomez <da.gomez@kernel.org>
> CC: Sami Tolvanen <samitolvanen@google.com>
> CC: Aaron Tomlin <atomlin@atomlin.com>
> CC: linux-modules@vger.kernel.org
> 
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> 
>   '#' will be ignored, and an empty message aborts the commit.
> ---
>   include/linux/module.h | 15 ++++++++-------
>   kernel/module/main.c   |  8 ++++++--
>   scripts/mod/modpost.c  | 18 ++++++++++++++++++
>   scripts/mod/modpost.h  |  6 +++++-
>   4 files changed, 37 insertions(+), 10 deletions(-)
> 
> diff --git a/include/linux/module.h b/include/linux/module.h
> index d80c3ea57472..4ea6c5ae3374 100644
> --- a/include/linux/module.h
> +++ b/include/linux/module.h
> @@ -402,10 +402,18 @@ struct klp_modinfo {
> 
>   struct module {
>          enum module_state state;
> +       u32 name_hash;

In the subject you say "name_crc"

> 
>          /* Member of list of modules */
>          struct list_head list;
> 
> +       /* Sysfs stuff. */
> +       struct module_kobject mkobj;
> +       struct module_attribute *modinfo_attrs;
> +       const char *version;
> +       const char *srcversion;
> +       struct kobject *holders_dir;
> +

Shouldn't this move be another patch ?

>          /* Unique handle for this module */
>          char name[MODULE_NAME_LEN];
> 
> @@ -414,13 +422,6 @@ struct module {
>          unsigned char build_id[BUILD_ID_SIZE_MAX];
>   #endif
> 
> -       /* Sysfs stuff. */
> -       struct module_kobject mkobj;
> -       struct module_attribute *modinfo_attrs;
> -       const char *version;
> -       const char *srcversion;
> -       struct kobject *holders_dir;
> -
>          /* Exported symbols */
>          const struct kernel_symbol *syms;
>          const u32 *crcs;
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index d855f43a2be3..685218b2c5ef 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -39,6 +39,7 @@
>   #include <linux/mutex.h>
>   #include <linux/rculist.h>
>   #include <linux/uaccess.h>
> +#include <linux/crc32.h>
>   #include <asm/cacheflush.h>
>   #include <linux/set_memory.h>
>   #include <asm/mmu_context.h>
> @@ -431,13 +432,16 @@ struct module *find_module_all(const char *name, size_t len,
>                                 bool even_unformed)
>   {
>          struct module *mod;
> +       u32 incoming_name_hash = crc32_le(0, name, len);
> 
>          list_for_each_entry_rcu(mod, &modules, list,
>                                  lockdep_is_held(&module_mutex)) {
>                  if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
>                          continue;
> -               if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
> -                       return mod;
> +               if (mod->name_hash == incoming_name_hash) {
> +                       if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
> +                               return mod;
> +               }

Why not just adding the following instead of modifing existing test:

	if (mod->name_hash != incoming_name_hash)
		continue;

>          }
>          return NULL;
>   }
> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> index 755b842f1f9b..ae90e0bf9330 100644
> --- a/scripts/mod/modpost.c
> +++ b/scripts/mod/modpost.c
> @@ -21,6 +21,22 @@
>   #include <stdbool.h>
>   #include <errno.h>
> 
> +/* Local CRC32 implementation for modpost.c */
> +#define CRCPOLY_LE 0xEDB88320
> +
> +typedef uint32_t u32;
> +
> +static u32 crc32_le(u32 crc,  char  *p, size_t len)
> +{
> +       int i;
> +       while (len--) {
> +               crc ^= *p++;
> +               for (i = 0; i < 8; i++)
> +                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
> +       }
> +       return crc;
> +}
> +

Why do you re-implement crc32_le() ?

>   #include <hash.h>
>   #include <hashtable.h>
>   #include <list.h>
> @@ -1581,6 +1597,7 @@ static void read_symbols(const char *modname)
> 
>          /* strip trailing .o */
>          mod = new_module(modname, strlen(modname) - strlen(".o"));
> +       mod->name_hash = crc32_le(0, mod->name, strlen(mod->name));
> 
>          /* save .no_trim_symbol section for later use */
>          if (info.no_trim_symbol_len) {
> @@ -1834,6 +1851,7 @@ static void add_header(struct buffer *b, struct module *mod)
>          buf_printf(b, "#include <linux/compiler.h>\n");
>          buf_printf(b, "\n");
>          buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
> +       buf_printf(b, "MODULE_INFO(name_crc, \"0x%08x\");\n", mod->name_hash);
>          buf_printf(b, "\n");
>          buf_printf(b, "__visible struct module __this_module\n");
>          buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
> diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
> index 2aecb8f25c87..3fc3cfd0a039 100644
> --- a/scripts/mod/modpost.h
> +++ b/scripts/mod/modpost.h
> @@ -11,11 +11,14 @@
>   #include <fcntl.h>
>   #include <unistd.h>
>   #include <elf.h>
> +#include <stdint.h>
>   #include "../../include/linux/module_symbol.h"
> 
>   #include <list_types.h>
>   #include "elfconfig.h"
> 
> +typedef uint32_t u32;
> +
>   /* On BSD-alike OSes elf.h defines these according to host's word size */
>   #undef ELF_ST_BIND
>   #undef ELF_ST_TYPE
> @@ -126,7 +129,8 @@ struct module {
>          bool seen;
>          bool has_init;
>          bool has_cleanup;
> -       char         srcversion[25];
> +               char         srcversion[25];
> +               u32          name_hash;
>          // Missing namespace dependencies
>          struct list_head missing_namespaces;
>          // Actual imported namespaces
> --
> 2.52.0
> 
> 


^ permalink raw reply

* Re: [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself
From: David Howells @ 2026-01-23 11:37 UTC (permalink / raw)
  To: Eric Biggers
  Cc: dhowells, Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen,
	Herbert Xu, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
	Sami Tolvanen, Jason A . Donenfeld, Ard Biesheuvel,
	Stephan Mueller, linux-crypto, keyrings, linux-modules,
	linux-kernel
In-Reply-To: <20260120211232.GB2657@quark>

Eric Biggers <ebiggers@kernel.org> wrote:

> As I mentioned on v11, it's misleading to start using the term digest
> for something that isn't a digest.

I can call it 'm' if you like.  I don't want to call it 'message' as that is
overused here.

> Naturally, this confusing introduction of non-digest digests seems to
> have already caused a bug: IMA calls pkcs7_get_digest() to calculate the
> digest of the module.  But now that's no longer necessarily a digest.
> It could be the entire signed attributes.

The next patch deals with that, but I can move the error check forward...

> I'll also note that this commit doesn't fully implement "Allow the
> signing algo to calculate the digest itself" as claimed, since only the
> signed attributes case is handled.  It looks like the next patch is
> intended to handle the other case.  But it's not made clear at all that
> it's a two-part thing; this patch implies that it's complete.

... or just squash the two patches together.

David


^ permalink raw reply

* Re: [PATCH v14 0/5] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing
From: David Howells @ 2026-01-23 11:13 UTC (permalink / raw)
  Cc: dhowells, Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen,
	Herbert Xu, Eric Biggers, Luis Chamberlain, Petr Pavlu,
	Daniel Gomez, Sami Tolvanen, Jason A . Donenfeld, Ard Biesheuvel,
	Stephan Mueller, linux-crypto, keyrings, linux-modules,
	linux-kernel
In-Reply-To: <20260121223609.1650735-1-dhowells@redhat.com>

David Howells <dhowells@redhat.com> wrote:

> Subject: [PATCH v14 0/5] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS
>  signing

I forgot to edit the cover to reflect I dropped RSASSA-PSS support from the
patchset for now.

David


^ permalink raw reply

* Re: [RFC PATCH 1/1] module: speed modprobe by adding name_crc to struct module
From: Daniel Gomez @ 2026-01-23 10:31 UTC (permalink / raw)
  To: Jim Cromie
  Cc: Petr Pavlu, Luis Chamberlain, Sami Tolvanen, Aaron Tomlin,
	linux-modules, linux-kernel
In-Reply-To: <198d1ca0-031f-459c-89bd-6d438a84fcb9@suse.com>

On 2026-01-23 10:36, Petr Pavlu wrote:
> On 1/23/26 12:46 AM, Jim Cromie wrote:
> > "modprobe foo" currently does strcmp on the name, this can be improved.
> > 
> > So this commit:
> > 
> > 1. adds name_crc to struct module
> > 2. modpost.c computes the value and
> > 3. outputs it for "modinfo foo" to see/use.
> > 
> > 4. adds hotpath to find_module_all()
> >    this uses name_crc to do quick "name-check"
> >    falls back to strcmp only to guard against collisions.
> > 
> > This should significantly reduce modprobe workload, and shorten module
> > load-time.
> > 
> > Since it alters struct module, its binary incompatible. This means:
> > 
> > 1. RFC for its wide "blast radius".
> > 2. suitable for major version bump *only*
> > 
> > 3. it opens door for further struct module reorg, to:
> >    a. segregate fields by "temperature"
> >    b. pack out paholes.
> >    c. improve cache locality (by reordering coldest on bottom)
> >       name should be cold now.
> >       bikeshedding is appropriate here.
> > 
> > NB: this isn't a substitute for CONFIG_MODULE_SIG.
> > It reimplements crc_le(), doesn't reuse kernel's version.
> > 
> > CC: Luis Chamberlain <mcgrof@kernel.org>
> > CC: Petr Pavlu <petr.pavlu@suse.com>
> > CC: Daniel Gomez <da.gomez@kernel.org>
> > CC: Sami Tolvanen <samitolvanen@google.com>
> > CC: Aaron Tomlin <atomlin@atomlin.com>
> > CC: linux-modules@vger.kernel.org
> > 
> > Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
> > 
> >  '#' will be ignored, and an empty message aborts the commit.
> 
> This patch looks as if it were generated by AI. If so, please avoid
> sending such changes. Otherwise, the commit description should explain

FYI, this is a process already documented. You can check out what maintainers
expect from contributions and possible guidelines:

https://lore.kernel.org/all/20260119200418.89541-1-dave.hansen@linux.intel.com/

^ permalink raw reply

* [PATCH v3 2/2] livepatch: Free klp_{object,func}_ext data after initialization
From: Petr Pavlu @ 2026-01-23 10:26 UTC (permalink / raw)
  To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
	Joe Lawrence
  Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
	Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
	linux-kernel
In-Reply-To: <20260123102825.3521961-1-petr.pavlu@suse.com>

The klp_object_ext and klp_func_ext data, which are stored in the
__klp_objects and __klp_funcs sections, respectively, are not needed
after they are used to create the actual klp_object and klp_func
instances. This operation is implemented by the init function in
scripts/livepatch/init.c.

Prefix the two sections with ".init" so they are freed after the module
is initializated.

Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
---
 scripts/livepatch/init.c            |  2 +-
 scripts/module.lds.S                |  4 ++--
 tools/objtool/check.c               |  2 +-
 tools/objtool/include/objtool/klp.h | 10 +++++-----
 tools/objtool/klp-diff.c            |  2 +-
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index 9e315fc857bd..638c95cffe76 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -19,7 +19,7 @@ static int __init livepatch_mod_init(void)
 	unsigned int nr_objs;
 	int ret;
 
-	obj_exts = klp_find_section_by_name(THIS_MODULE, "__klp_objects",
+	obj_exts = klp_find_section_by_name(THIS_MODULE, ".init.klp_objects",
 					    &obj_exts_sec_size);
 	nr_objs = obj_exts_sec_size / sizeof(*obj_exts);
 	if (!nr_objs) {
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 383d19beffb4..054ef99e8288 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -34,8 +34,8 @@ SECTIONS {
 
 	__patchable_function_entries : { *(__patchable_function_entries) }
 
-	__klp_funcs		0: ALIGN(8) { KEEP(*(__klp_funcs)) }
-	__klp_objects		0: ALIGN(8) { KEEP(*(__klp_objects)) }
+	.init.klp_funcs		0 : ALIGN(8) { KEEP(*(.init.klp_funcs)) }
+	.init.klp_objects	0 : ALIGN(8) { KEEP(*(.init.klp_objects)) }
 
 #ifdef CONFIG_ARCH_USES_CFI_TRAPS
 	__kcfi_traps		: { KEEP(*(.kcfi_traps)) }
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 3f7999317f4d..933868ee3beb 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -4761,7 +4761,7 @@ static int validate_ibt(struct objtool_file *file)
 		    !strcmp(sec->name, "__bug_table")			||
 		    !strcmp(sec->name, "__ex_table")			||
 		    !strcmp(sec->name, "__jump_table")			||
-		    !strcmp(sec->name, "__klp_funcs")			||
+		    !strcmp(sec->name, ".init.klp_funcs")		||
 		    !strcmp(sec->name, "__mcount_loc")			||
 		    !strcmp(sec->name, ".llvm.call-graph-profile")	||
 		    !strcmp(sec->name, ".llvm_bb_addr_map")		||
diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h
index ad830a7ce55b..e32e5e8bc631 100644
--- a/tools/objtool/include/objtool/klp.h
+++ b/tools/objtool/include/objtool/klp.h
@@ -6,12 +6,12 @@
 #define SHN_LIVEPATCH		0xff20
 
 /*
- * __klp_objects and __klp_funcs are created by klp diff and used by the patch
- * module init code to build the klp_patch, klp_object and klp_func structs
- * needed by the livepatch API.
+ * .init.klp_objects and .init.klp_funcs are created by klp diff and used by the
+ * patch module init code to build the klp_patch, klp_object and klp_func
+ * structs needed by the livepatch API.
  */
-#define KLP_OBJECTS_SEC	"__klp_objects"
-#define KLP_FUNCS_SEC	"__klp_funcs"
+#define KLP_OBJECTS_SEC	".init.klp_objects"
+#define KLP_FUNCS_SEC	".init.klp_funcs"
 
 /*
  * __klp_relocs is an intermediate section which are created by klp diff and
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 4d1f9e9977eb..fd64d5e3c3b6 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1439,7 +1439,7 @@ static int clone_special_sections(struct elfs *e)
 }
 
 /*
- * Create __klp_objects and __klp_funcs sections which are intermediate
+ * Create .init.klp_objects and .init.klp_funcs sections which are intermediate
  * sections provided as input to the patch module's init code for building the
  * klp_patch, klp_object and klp_func structs for the livepatch API.
  */
-- 
2.52.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