Linux Security Modules development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
Cc: linux-security-module@vger.kernel.org
Subject: Re: [PATCH v4 1/2] ima: discard modsig when detached data cannot be supplied
Date: Sat, 24 Oct 2026 09:58:42 +0000	[thread overview]
Message-ID: <sashiko-outbox-183637@kernel.org> (raw)
In-Reply-To: <20261024093918.2929374-2-Jeremy.Jean@oss.cyber.gouv.fr>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] ima: ignored pkcs7_get_digest() failure in ima_collect_modsig()
- [Medium] ima: unintended measurement in process_measurement() when modsig is discarded
--

commit 6ba08dabf06dd0a8dc8646bcd331980059e5a114
Author: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>

ima: discard modsig when detached data cannot be supplied

This commit updates ima_collect_modsig() to return a boolean indicating
whether detached file data was supplied to the PKCS#7 message, and
discards the modsig in ima_collect_measurement() if supplying the
detached data fails.

> diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
> index 45701f04ba62f..7859c9d1a27f5 100644
> --- a/security/integrity/ima/ima_api.c
> +++ b/security/integrity/ima/ima_api.c
> @@ -235,6 +235,8 @@ static bool ima_get_verity_digest(struct ima_iint_cache *iint,
>   *
>   * Calculate the file hash, if it doesn't already exist,
>   * storing the measurement and i_version in the iint.
> + * If modsig is provided, discard it when detached data cannot be supplied
> + * so ordinary measurement and xattr appraisal can proceed.
>   *
>   * Must be called with iint->mutex held.
>   *
> @@ -242,7 +244,7 @@ static bool ima_get_verity_digest(struct ima_iint_cache *iint,
>   */
>  int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
>  			    void *buf, loff_t size, enum hash_algo algo,
> -			    struct modsig *modsig)
> +			    struct modsig **modsig)
>  {
>  	const char *audit_cause = "failed";
>  	struct inode *inode = file_inode(file);
> @@ -262,8 +264,10 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
>  	 * the file digest without collecting the modsig in a previous
>  	 * measurement rule.
>  	 */
> -	if (modsig)
> -		ima_collect_modsig(modsig, buf, size);
> +	if (modsig && *modsig && !ima_collect_modsig(*modsig, buf, size)) {
> +		ima_free_modsig(*modsig);
> +		*modsig = NULL;
> +	}
>  
>  	if (iint->flags & IMA_COLLECTED)
>  		goto out;
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index fed80da3ee096..336e17ec4f7a3 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -422,7 +422,7 @@ static int process_measurement(struct file *file, const struct cred *cred,
>  
>  	hash_algo = ima_get_hash_algo(xattr_value, xattr_len);
>  
> -	rc = ima_collect_measurement(iint, file, buf, size, hash_algo, modsig);
> +	rc = ima_collect_measurement(iint, file, buf, size, hash_algo, &modsig);

[Severity: Medium]
Can discarding modsig in ima_collect_measurement() leave IMA_MEASURE set
in action when the measurement was only requested to record the modsig?

Earlier in process_measurement(), if IMA_MODSIG_ALLOWED is set and
ima_read_modsig() succeeds on an already-measured file, IMA_MEASURE is
added to action:

	if (iint->flags & IMA_MODSIG_ALLOWED) {
		rc = ima_read_modsig(func, buf, size, &modsig);

		if (!rc && ima_template_has_modsig(template_desc) &&
		    iint->flags & IMA_MEASURED)
			action |= IMA_MEASURE;
	}

When ima_collect_measurement() subsequently discards modsig and sets it
to NULL because pkcs7_supply_detached_data() fails, action still has
IMA_MEASURE set.

If the earlier measurement that set IMA_MEASURED used a non-default PCR
and the current hook only matched an appraise rule (leaving pcr at
CONFIG_IMA_MEASURE_PCR_IDX), ima_store_measurement() will see modsig ==
NULL, find that the default PCR bit is not set in iint->measured_pcrs:

	if (iint->measured_pcrs & (0x1 << pcr) && !modsig)
		return;

and record an extra measurement with no modsig into the default PCR.
Should IMA_MEASURE only be added to action after modsig collection has
succeeded?

[ ... ]

> diff --git a/security/integrity/ima/ima_modsig.c b/security/integrity/ima/ima_modsig.c
> index 632c746fd81e4..e640a9a53508e 100644
> --- a/security/integrity/ima/ima_modsig.c
> +++ b/security/integrity/ima/ima_modsig.c
> @@ -96,8 +96,12 @@ int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
>   * Since the modsig is part of the file contents, the hash used in its signature
>   * isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code
>   * calculates a separate one for signature verification.
> + *
> + * Digest export is best-effort; not all signatures expose a single digest.
> + *
> + * Return: true if the file data was supplied, false otherwise.
>   */
> -void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size)
> +bool ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size)
>  {
>  	int rc;
>  
> @@ -109,11 +113,13 @@ void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size)
>  		sizeof(struct module_signature);
>  	rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size);
>  	if (rc)
> -		return;
> +		return false;
>  
>  	/* Ask the PKCS7 code to calculate the file hash. */
>  	rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest,
>  			      &modsig->digest_size, &modsig->hash_algo);
> +
> +	return true;
>  }
>  
>  int ima_modsig_verify(struct key *keyring, const struct modsig *modsig)
> diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
> index 9bd80ca1159a2..585cd59f00a2e 100644
> --- a/security/integrity/ima/ima_template_lib.c
> +++ b/security/integrity/ima/ima_template_lib.c
> @@ -478,8 +478,8 @@ int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
>  		if (rc)
>  			return rc;
>  		else if (hash_algo == HASH_ALGO__LAST || cur_digestsize == 0)
> -			/* There was some error collecting the digest. */
> -			return -EINVAL;
> +			/* Keep the ordinary measurement without an exported digest. */
> +			return 0;
>  	}

[Severity: High]
What happens in ima_check_blacklist() and ima_store_measurement() when
pkcs7_get_digest() fails in ima_collect_modsig() (note that the return
value of pkcs7_get_digest() also remains unchecked in the follow-up commit
"ima: audit failure to supply detached data for modsig")?

When pkcs7_get_digest() fails (for example, returning -EBADMSG when
sinfo->next != NULL, or -EINVAL when !sinfo->sig->m_free for algorithms
such as ML-DSA) or leaves modsig->hash_algo as HASH_ALGO__LAST,
ima_collect_modsig() still returns true. That leaves modsig non-NULL in
process_measurement() with modsig->digest == NULL, modsig->digest_size ==
0, and modsig->hash_algo == HASH_ALGO__LAST.

In security/integrity/ima/ima_appraise.c:ima_check_blacklist(), a
non-NULL modsig takes the first branch and skips checking iint->ima_hash:

	if (iint->flags & IMA_MODSIG_ALLOWED && modsig) {
		ima_get_modsig_digest(modsig, &hash_algo, &digest, &digestsize);

		rc = is_binary_blacklisted(digest, digestsize);
	} else if (iint->flags & IMA_DIGSIG_REQUIRED && iint->ima_hash)
		rc = is_binary_blacklisted(iint->ima_hash->digest, iint->ima_hash->length);

Because digest is NULL and digestsize is 0, is_binary_blacklisted(NULL, 0)
returns 0. Since pkcs7_get_digest() rejects messages with multiple
SignerInfos (sinfo->next != NULL) while ima_modsig_verify() ->
verify_pkcs7_message_sig() succeeds as long as at least one SignerInfo is
valid and trusted (and similarly for ML-DSA signatures where
!sinfo->sig->m_free), wouldn't a blacklisted binary bypass
ima_check_blacklist()?

In addition, because ima_eventdigest_modsig_init() now returns 0 instead
of -EINVAL when hash_algo == HASH_ALGO__LAST || cur_digestsize == 0 while
event_data->modsig is still non-NULL:

1. For templates like ima-modsig (d-ng|n-ng|sig|d-modsig|modsig),
   ima_eventdigest_modsig_init() leaves the d-modsig field empty while
   ima_eventmodsig_init() still populates the modsig field with the raw
   PKCS#7 signature, breaking the requirement in check_template_modsig()
   that modsig be paired with d-modsig.

2. If the file was already measured (iint->flags & IMA_MEASURED),
   process_measurement() and ima_store_measurement() will record a second
   measurement entry and extend the PCR again even though no modsig digest
   could be exported.

Should ima_collect_modsig() fail and discard the modsig when
pkcs7_get_digest() fails or leaves modsig->hash_algo == HASH_ALGO__LAST?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261024093918.2929374-1-Jeremy.Jean@oss.cyber.gouv.fr?part=1

  reply	other threads:[~2026-10-24  9:58 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-24  9:39 [PATCH v4 0/2] ima: reject modsig when detached data cannot be supplied Jérémy Jean
2026-10-24  9:39 ` [PATCH v4 1/2] ima: discard " Jérémy Jean
2026-10-24  9:58   ` sashiko-bot [this message]
2026-10-24 13:47   ` Jérémy Jean
2026-10-24  9:39 ` [PATCH v4 2/2] ima: audit failure to supply detached data for modsig Jérémy Jean
2026-10-24  9:55   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-183637@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox