From nobody Mon Dec 1 22:04:04 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8755E36D4EF; Sun, 30 Nov 2025 21:35:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764538554; cv=none; b=ourAuyrzVfBYMY2dA6apBNLv7GWiDMvCH5ND5JArLXwMV7cI+gSNNsbRBb6k0TGG6VhyyeBdPJYsN/a99Few4AcCeTlrl5803eOU6JqXbp9w8xsSxSleXgHbEz8RKTiPzeu2apjNTLXvIYBgEgPTbyfvs6jnK5sPTNXbD60vrqc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764538554; c=relaxed/simple; bh=5oR+QBk8Q0fmRWFKG4nhigL/APRearymNZOO4gVOs8c=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=ZcfEnJOmly1cwbR7pgNbbUmQoS9y8cVfDHv9IRDknP9SQdhwAC0PMYzFrhAprcYj3jk4zQosK9wuHboQosMvAMQzdpDh9h6YlH5ioXa8sOmvXHhmgeDyfE7edmMNL64hgcMAXfQbpLGzpf9/CSzKIOHLp3tDgzZPUN+wlXhzkww= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BSrNyxMN; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="BSrNyxMN" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5BEF1C4CEF8; Sun, 30 Nov 2025 21:35:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764538553; bh=5oR+QBk8Q0fmRWFKG4nhigL/APRearymNZOO4gVOs8c=; h=From:To:Cc:Subject:Date:From; b=BSrNyxMN+s6a7z3y+M4jGckNbpxplZHBw/nmy7fC71TcsnDc5zzLGiC57DXPG5e0t HKR0Tn63gDFgFxznmmHBGDBBKSdn2ybSIgmehUhoi+k/HMDZWmUmBv9UcAvOLs7Va0 3HTghyTm3+Q1ZAKYq2PcfxIUqY0SzyajYsjYRpE+t8qIDtZQIHeSv3DMYUNQLn5YbN V99M7aIxOF25J/CPr1Tx64Wgs/JmDHTX1KV7sK6quW42oHcFzWK1bsuXhgFTXdvMvf rh1qk9WzxzNRyVDFBQHxFbi364dCHZnEcYQ+y76VJPeHzkPd3Jq4XnCtSFHyUZye6V jXazBXXOf5fRg== From: Jarkko Sakkinen To: linux-integrity@vger.kernel.org Cc: Jarkko Sakkinen , stable@vger.kernel.org, Peter Huewe , Jason Gunthorpe , James Bottomley , Mimi Zohar , David Howells , Paul Moore , James Morris , "Serge E. Hallyn" , Ard Biesheuvel , linux-kernel@vger.kernel.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org Subject: [PATCH v2] tpm2-sessions: address out-of-range indexing Date: Sun, 30 Nov 2025 23:35:47 +0200 Message-ID: <20251130213548.1340706-1-jarkko@kernel.org> X-Mailer: git-send-email 2.52.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 'name_size' does not have any range checks, and it just directly indexes with TPM_ALG_ID. Address the issue by: 1. Rename 'name_size' as 'tpm2_name_size' so that it is bit easier to recognize and make it a fallible function. 2. Check for only known algorithms in 'tpm2_name_size'. Return -EINVAL for unrecognized algorithms. 3. In order to correctly propagate possible errors make also 'tpm2_buf_append_name' and 'tpm_buf_fill_hmac_session' fallible and address their possible errors at the call sites. Cc: stable@vger.kernel.org # v6.10+ Fixes: 1085b8276bb4 ("tpm: Add the rest of the session HMAC API") Signed-off-by: Jarkko Sakkinen --- v2: There was spurious extra field added to tpm2_hash by mistake. drivers/char/tpm/tpm2-cmd.c | 23 ++++- drivers/char/tpm/tpm2-sessions.c | 108 ++++++++++++++-------- include/linux/tpm.h | 6 +- security/keys/trusted-keys/trusted_tpm2.c | 38 ++++++-- 4 files changed, 124 insertions(+), 51 deletions(-) diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 5b6ccf901623..e63254135a74 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -187,7 +187,12 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, } =20 if (!disable_pcr_integrity) { - tpm_buf_append_name(chip, &buf, pcr_idx, NULL); + rc =3D tpm_buf_append_name(chip, &buf, pcr_idx, NULL); + if (rc) { + tpm2_end_auth_session(chip); + return rc; + } + tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0); } else { tpm_buf_append_handle(chip, &buf, pcr_idx); @@ -202,8 +207,14 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, chip->allocated_banks[i].digest_size); } =20 - if (!disable_pcr_integrity) - tpm_buf_fill_hmac_session(chip, &buf); + if (!disable_pcr_integrity) { + rc =3D tpm_buf_fill_hmac_session(chip, &buf); + if (rc) { + tpm2_end_auth_session(chip); + return rc; + } + } + rc =3D tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value"); if (!disable_pcr_integrity) rc =3D tpm_buf_check_hmac_response(chip, &buf, rc); @@ -261,7 +272,11 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, s= ize_t max) | TPM2_SA_CONTINUE_SESSION, NULL, 0); tpm_buf_append_u16(&buf, num_bytes); - tpm_buf_fill_hmac_session(chip, &buf); + + err =3D tpm_buf_fill_hmac_session(chip, &buf); + if (err) + goto out; + err =3D tpm_transmit_cmd(chip, &buf, offsetof(struct tpm2_get_random_out, buffer), diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessi= ons.c index 6d03c224e6b2..82b9d9096fd1 100644 --- a/drivers/char/tpm/tpm2-sessions.c +++ b/drivers/char/tpm/tpm2-sessions.c @@ -141,19 +141,28 @@ struct tpm2_auth { }; =20 #ifdef CONFIG_TCG_TPM2_HMAC + /* - * Name Size based on TPM algorithm (assumes no hash bigger than 255) + * Calculate size of the TPMT_HA payload of TPM2B_NAME. */ -static u8 name_size(const u8 *name) +static int tpm2_name_size(const u8 *name) { - static u8 size_map[] =3D { - [TPM_ALG_SHA1] =3D SHA1_DIGEST_SIZE, - [TPM_ALG_SHA256] =3D SHA256_DIGEST_SIZE, - [TPM_ALG_SHA384] =3D SHA384_DIGEST_SIZE, - [TPM_ALG_SHA512] =3D SHA512_DIGEST_SIZE, - }; - u16 alg =3D get_unaligned_be16(name); - return size_map[alg] + 2; + u16 hash_alg =3D get_unaligned_be16(name); + + switch (hash_alg) { + case TPM_ALG_SHA1: + return SHA1_DIGEST_SIZE + 2; + case TPM_ALG_SHA256: + return SHA256_DIGEST_SIZE + 2; + case TPM_ALG_SHA384: + return SHA384_DIGEST_SIZE + 2; + case TPM_ALG_SHA512: + return SHA512_DIGEST_SIZE + 2; + case TPM_ALG_SM3_256: + return SM3256_DIGEST_SIZE + 2; + } + + return -EINVAL; } =20 static int tpm2_parse_read_public(char *name, struct tpm_buf *buf) @@ -161,6 +170,7 @@ static int tpm2_parse_read_public(char *name, struct tp= m_buf *buf) struct tpm_header *head =3D (struct tpm_header *)buf->data; off_t offset =3D TPM_HEADER_SIZE; u32 tot_len =3D be32_to_cpu(head->length); + int name_size_alg; u32 val; =20 /* we're starting after the header so adjust the length */ @@ -172,9 +182,15 @@ static int tpm2_parse_read_public(char *name, struct t= pm_buf *buf) return -EINVAL; offset +=3D val; /* name */ + val =3D tpm_buf_read_u16(buf, &offset); - if (val !=3D name_size(&buf->data[offset])) + name_size_alg =3D tpm2_name_size(&buf->data[offset]); + if (name_size_alg < 0) + return name_size_alg; + + if (val !=3D name_size_alg) return -EINVAL; + memcpy(name, &buf->data[offset], val); /* forget the rest */ return 0; @@ -222,46 +238,59 @@ static int tpm2_read_public(struct tpm_chip *chip, u3= 2 handle, char *name) * will be caused by an incorrect programming model and indicated by a * kernel message. */ -void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, - u32 handle, u8 *name) +int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, + u32 handle, u8 *name) { #ifdef CONFIG_TCG_TPM2_HMAC enum tpm2_mso_type mso =3D tpm2_handle_mso(handle); struct tpm2_auth *auth; + int name_size; int slot; + int ret; #endif =20 if (!tpm2_chip_auth(chip)) { tpm_buf_append_handle(chip, buf, handle); - return; + return 0; } =20 #ifdef CONFIG_TCG_TPM2_HMAC slot =3D (tpm_buf_length(buf) - TPM_HEADER_SIZE) / 4; if (slot >=3D AUTH_MAX_NAMES) { - dev_err(&chip->dev, "TPM: too many handles\n"); - return; + dev_err(&chip->dev, "too many handles\n"); + return -ENOMEM; } auth =3D chip->auth; - WARN(auth->session !=3D tpm_buf_length(buf), - "name added in wrong place\n"); + if (auth->session !=3D tpm_buf_length(buf)) { + dev_err(&chip->dev, "session state malformed"); + return -EIO; + } tpm_buf_append_u32(buf, handle); auth->session +=3D 4; =20 if (mso =3D=3D TPM2_MSO_PERSISTENT || mso =3D=3D TPM2_MSO_VOLATILE || mso =3D=3D TPM2_MSO_NVRAM) { - if (!name) - tpm2_read_public(chip, handle, auth->name[slot]); + if (!name) { + ret =3D tpm2_read_public(chip, handle, auth->name[slot]); + if (ret) + return tpm_ret_to_err(ret); + } } else { if (name) - dev_err(&chip->dev, "TPM: Handle does not require name but one is speci= fied\n"); + return -EINVAL; } =20 auth->name_h[slot] =3D handle; - if (name) - memcpy(auth->name[slot], name, name_size(name)); + if (name) { + name_size =3D tpm2_name_size(name); + if (name_size < 0) + return name_size; + + memcpy(auth->name[slot], name, name_size); + } #endif + return 0; } EXPORT_SYMBOL_GPL(tpm_buf_append_name); =20 @@ -537,7 +566,7 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, st= ruct tpm_chip *chip, * will be caused by an incorrect programming model and indicated by a * kernel message. */ -void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf) +int tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf) { u32 cc, handles, val; struct tpm2_auth *auth =3D chip->auth; @@ -549,9 +578,10 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, = struct tpm_buf *buf) u8 cphash[SHA256_DIGEST_SIZE]; struct sha256_ctx sctx; struct hmac_sha256_ctx hctx; + int name_size; =20 if (!auth) - return; + return -EINVAL; =20 /* save the command code in BE format */ auth->ordinal =3D head->ordinal; @@ -559,10 +589,9 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, = struct tpm_buf *buf) cc =3D be32_to_cpu(head->ordinal); =20 i =3D tpm2_find_cc(chip, cc); - if (i < 0) { - dev_err(&chip->dev, "Command 0x%x not found in TPM\n", cc); - return; - } + if (i < 0) + return -EINVAL; + attrs =3D chip->cc_attrs_tbl[i]; =20 handles =3D (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0); @@ -576,9 +605,8 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, s= truct tpm_buf *buf) u32 handle =3D tpm_buf_read_u32(buf, &offset_s); =20 if (auth->name_h[i] !=3D handle) { - dev_err(&chip->dev, "TPM: handle %d wrong for name\n", - i); - return; + dev_err(&chip->dev, "invalid handle 0x%08x\n", handle); + return -EINVAL; } } /* point offset_s to the start of the sessions */ @@ -609,12 +637,12 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip,= struct tpm_buf *buf) offset_s +=3D len; } if (offset_s !=3D offset_p) { - dev_err(&chip->dev, "TPM session length is incorrect\n"); - return; + dev_err(&chip->dev, "session length is incorrect\n"); + return -EINVAL; } if (!hmac) { - dev_err(&chip->dev, "TPM could not find HMAC session\n"); - return; + dev_err(&chip->dev, "could not find HMAC session\n"); + return -EINVAL; } =20 /* encrypt before HMAC */ @@ -646,8 +674,11 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, = struct tpm_buf *buf) if (mso =3D=3D TPM2_MSO_PERSISTENT || mso =3D=3D TPM2_MSO_VOLATILE || mso =3D=3D TPM2_MSO_NVRAM) { - sha256_update(&sctx, auth->name[i], - name_size(auth->name[i])); + name_size =3D tpm2_name_size(auth->name[i]); + if (name_size < 0) + return name_size; + + sha256_update(&sctx, auth->name[i], name_size); } else { __be32 h =3D cpu_to_be32(auth->name_h[i]); =20 @@ -668,6 +699,7 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, s= truct tpm_buf *buf) hmac_sha256_update(&hctx, auth->tpm_nonce, sizeof(auth->tpm_nonce)); hmac_sha256_update(&hctx, &auth->attrs, 1); hmac_sha256_final(&hctx, hmac); + return 0; } EXPORT_SYMBOL(tpm_buf_fill_hmac_session); =20 diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 0e9e043f728c..1a59f0190eb3 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -528,8 +528,8 @@ static inline struct tpm2_auth *tpm2_chip_auth(struct t= pm_chip *chip) #endif } =20 -void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, - u32 handle, u8 *name); +int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, + u32 handle, u8 *name); void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *bu= f, u8 attributes, u8 *passphrase, int passphraselen); @@ -562,7 +562,7 @@ static inline void tpm_buf_append_hmac_session_opt(stru= ct tpm_chip *chip, #ifdef CONFIG_TCG_TPM2_HMAC =20 int tpm2_start_auth_session(struct tpm_chip *chip); -void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf); +int tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf); int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf, int rc); void tpm2_end_auth_session(struct tpm_chip *chip); diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trus= ted-keys/trusted_tpm2.c index e165b117bbca..33544b6bc105 100644 --- a/security/keys/trusted-keys/trusted_tpm2.c +++ b/security/keys/trusted-keys/trusted_tpm2.c @@ -283,7 +283,13 @@ int tpm2_seal_trusted(struct tpm_chip *chip, goto out_put; } =20 - tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + rc =3D tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + if (rc) { + tpm_buf_destroy(&buf); + tpm2_end_auth_session(chip); + goto out_put; + } + tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT, options->keyauth, TPM_DIGEST_SIZE); =20 @@ -331,7 +337,12 @@ int tpm2_seal_trusted(struct tpm_chip *chip, goto out; } =20 - tpm_buf_fill_hmac_session(chip, &buf); + rc =3D tpm_buf_fill_hmac_session(chip, &buf); + if (rc) { + tpm2_end_auth_session(chip); + goto out; + } + rc =3D tpm_transmit_cmd(chip, &buf, 4, "sealing data"); rc =3D tpm_buf_check_hmac_response(chip, &buf, rc); if (rc) @@ -438,7 +449,12 @@ static int tpm2_load_cmd(struct tpm_chip *chip, return rc; } =20 - tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + rc =3D tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + if (rc) { + tpm2_end_auth_session(chip); + return rc; + } + tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth, TPM_DIGEST_SIZE); =20 @@ -450,7 +466,10 @@ static int tpm2_load_cmd(struct tpm_chip *chip, goto out; } =20 - tpm_buf_fill_hmac_session(chip, &buf); + rc =3D tpm_buf_fill_hmac_session(chip, &buf); + if (rc) + goto out; + rc =3D tpm_transmit_cmd(chip, &buf, 4, "loading blob"); rc =3D tpm_buf_check_hmac_response(chip, &buf, rc); if (!rc) @@ -497,7 +516,11 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, return rc; } =20 - tpm_buf_append_name(chip, &buf, blob_handle, NULL); + rc =3D tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + if (rc) { + tpm2_end_auth_session(chip); + return rc; + } =20 if (!options->policyhandle) { tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT, @@ -522,7 +545,10 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, NULL, 0); } =20 - tpm_buf_fill_hmac_session(chip, &buf); + rc =3D tpm_buf_fill_hmac_session(chip, &buf); + if (rc) + goto out; + rc =3D tpm_transmit_cmd(chip, &buf, 6, "unsealing"); rc =3D tpm_buf_check_hmac_response(chip, &buf, rc); =20 --=20 2.52.0