All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jarkko Sakkinen <jarkko@kernel.org>
To: Michael Bommarito <michael.bommarito@gmail.com>
Cc: Peter Huewe <peterhuewe@gmx.de>, Jason Gunthorpe <jgg@ziepe.ca>,
	James Bottomley <James.Bottomley@hansenpartnership.com>,
	Herbert Xu <herbert@gondor.apana.org.au>,
	linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org
Subject: Re: [PATCH v2] tpm: tpm2-sessions: wait for async KPP completion in tpm_buf_append_salt
Date: Sun, 31 May 2026 20:39:17 +0300	[thread overview]
Message-ID: <ahxyRdpJhEsWc3kQ@kernel.org> (raw)
In-Reply-To: <20260531124428.2304629-1-michael.bommarito@gmail.com>

On Sun, May 31, 2026 at 08:44:28AM -0400, Michael Bommarito wrote:
> tpm_buf_append_salt() in drivers/char/tpm/tpm2-sessions.c calls
> crypto_kpp_generate_public_key() and crypto_kpp_compute_shared_secret()
> without installing a completion callback, discards both return values,
> and immediately frees the kpp_request via kpp_request_free(). When the
> resolved ecdh-nist-p256 KPP backend is asynchronous (atmel-ecc, HPRE,
> keembay-ocs), either operation returns -EINPROGRESS and the deferred
> completion worker dereferences the freed request.
> 
> The path fires automatically from the hwrng_fillfn kernel thread via
> tpm_get_random -> tpm2_get_random -> tpm2_start_auth_session ->
> tpm_buf_append_salt on every entropy poll, without any userland action.
> 
> Install crypto_req_done as the completion callback, wrap both KPP
> operations in crypto_wait_req(), and propagate errors to the caller.
> The wait is a no-op for synchronous backends.
> 
> Fixes: 1085b8276bb4 ("tpm: Add the rest of the session HMAC API")
> Cc: stable@vger.kernel.org # v6.10+
> Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
> Assisted-by: Claude:claude-opus-4-7
> ---
> v2: restructure the error cleanup into an explicit success return plus
>     err_free_req/err_free_kpp labels, per review. No functional change.
> 
> Validation (QEMU x86_64, swtpm, async ecdh-nist-p256 stub backend):
>   Unpatched, the deferred completion worker dereferences the freed
>   kpp_request: KASAN slab-use-after-free with the allocation and free
>   stacks both in tpm_buf_append_salt(), reached from
>   tpm2_start_auth_session -> tpm2_get_random -> hwrng_fillfn with no
>   userland action, then a NULL completion-pointer oops. Patched, the
>   same setup is KASAN-clean across repeated entropy polls: the worker
>   observes a live request and the free runs only after both KPP
>   operations complete. With no accelerator present, the synchronous
>   generic backend establishes sessions unchanged.
> 
>  drivers/char/tpm/tpm2-sessions.c | 45 ++++++++++++++++++++++++--------
>  1 file changed, 34 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c
> index c4da6fde748f4..f44646b26b192 100644
> --- a/drivers/char/tpm/tpm2-sessions.c
> +++ b/drivers/char/tpm/tpm2-sessions.c
> @@ -489,15 +489,17 @@ static void tpm2_KDFe(u8 z[EC_PT_SZ], const char *str, u8 *pt_u, u8 *pt_v,
>  	sha256_final(&sctx, out);
>  }
>  
> -static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip,
> -				struct tpm2_auth *auth)
> +static int tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip,
> +			       struct tpm2_auth *auth)
>  {
>  	struct crypto_kpp *kpp;
>  	struct kpp_request *req;
> +	DECLARE_CRYPTO_WAIT(wait);
>  	struct scatterlist s[2], d[1];
>  	struct ecdh p = {0};
>  	u8 encoded_key[EC_PT_SZ], *x, *y;
>  	unsigned int buf_len;
> +	int rc;
>  
>  	/* secret is two sized points */
>  	tpm_buf_append_u16(buf, (EC_PT_SZ + 2)*2);
> @@ -520,14 +522,15 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip,
>  	kpp = crypto_alloc_kpp("ecdh-nist-p256", CRYPTO_ALG_INTERNAL, 0);
>  	if (IS_ERR(kpp)) {
>  		dev_err(&chip->dev, "crypto ecdh allocation failed\n");
> -		return;
> +		return PTR_ERR(kpp);
>  	}
>  
>  	buf_len = crypto_ecdh_key_len(&p);
>  	if (sizeof(encoded_key) < buf_len) {
>  		dev_err(&chip->dev, "salt buffer too small needs %d\n",
>  			buf_len);
> -		goto out;
> +		rc = -EINVAL;
> +		goto err_free_kpp;
>  	}
>  	crypto_ecdh_encode_key(encoded_key, buf_len, &p);
>  	/* this generates a random private key */
> @@ -535,11 +538,17 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip,
>  
>  	/* salt is now the public point of this private key */
>  	req = kpp_request_alloc(kpp, GFP_KERNEL);
> -	if (!req)
> -		goto out;
> +	if (!req) {
> +		rc = -ENOMEM;
> +		goto err_free_kpp;
> +	}
> +	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				 crypto_req_done, &wait);
>  	kpp_request_set_input(req, NULL, 0);
>  	kpp_request_set_output(req, s, EC_PT_SZ*2);
> -	crypto_kpp_generate_public_key(req);
> +	rc = crypto_wait_req(crypto_kpp_generate_public_key(req), &wait);
> +	if (rc)
> +		goto err_free_req;
>  	/*
>  	 * we're not done: now we have to compute the shared secret
>  	 * which is our private key multiplied by the tpm_key public
> @@ -551,8 +560,9 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip,
>  	kpp_request_set_input(req, s, EC_PT_SZ*2);
>  	sg_init_one(d, auth->salt, EC_PT_SZ);
>  	kpp_request_set_output(req, d, EC_PT_SZ);
> -	crypto_kpp_compute_shared_secret(req);
> -	kpp_request_free(req);
> +	rc = crypto_wait_req(crypto_kpp_compute_shared_secret(req), &wait);
> +	if (rc)
> +		goto err_free_req;
>  
>  	/*
>  	 * pass the shared secret through KDFe for salt. Note salt
> @@ -562,8 +572,16 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip,
>  	 */
>  	tpm2_KDFe(auth->salt, "SECRET", x, chip->null_ec_key_x, auth->salt);
>  
> - out:
> +	kpp_request_free(req);
>  	crypto_free_kpp(kpp);
> +	return 0;
> +
> +err_free_req:
> +	kpp_request_free(req);
> +
> +err_free_kpp:
> +	crypto_free_kpp(kpp);
> +	return rc;
>  }
>  
>  /**
> @@ -1018,7 +1036,12 @@ int tpm2_start_auth_session(struct tpm_chip *chip)
>  	tpm_buf_append(&buf, auth->our_nonce, sizeof(auth->our_nonce));
>  
>  	/* append encrypted salt and squirrel away unencrypted in auth */
> -	tpm_buf_append_salt(&buf, chip, auth);
> +	rc = tpm_buf_append_salt(&buf, chip, auth);
> +	if (rc) {
> +		tpm2_flush_context(chip, null_key);
> +		tpm_buf_destroy(&buf);
> +		goto out;
> +	}
>  	/* session type (HMAC, audit or policy) */
>  	tpm_buf_append_u8(&buf, TPM2_SE_HMAC);
>  
> -- 
> 2.53.0
> 

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

Thank you. I'll apply this shortly.

BR, Jarkko

      reply	other threads:[~2026-05-31 17:39 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-31 12:44 [PATCH v2] tpm: tpm2-sessions: wait for async KPP completion in tpm_buf_append_salt Michael Bommarito
2026-05-31 17:39 ` Jarkko Sakkinen [this message]

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=ahxyRdpJhEsWc3kQ@kernel.org \
    --to=jarkko@kernel.org \
    --cc=James.Bottomley@hansenpartnership.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=jgg@ziepe.ca \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=michael.bommarito@gmail.com \
    --cc=peterhuewe@gmx.de \
    --cc=stable@vger.kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.