1

tpm: Address !chip->auth in tpm_buf_append_name()

Unless tpm_chip_bootstrap() was called by the driver, !chip->auth can
cause a null derefence in tpm_buf_append_name().  Thus, address
!chip->auth in tpm_buf_append_name() and remove the fallback
implementation for !TCG_TPM2_HMAC.

Cc: stable@vger.kernel.org # v6.10+
Reported-by: Stefan Berger <stefanb@linux.ibm.com>
Closes: https://lore.kernel.org/linux-integrity/20240617193408.1234365-1-stefanb@linux.ibm.com/
Fixes: d0a25bb961 ("tpm: Add HMAC session name/handle append")
Tested-by: Michael Ellerman <mpe@ellerman.id.au> # ppc
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
This commit is contained in:
Jarkko Sakkinen 2024-07-03 18:33:14 +03:00 committed by Jarkko Sakkinen
parent 25ee48a55f
commit a61809a332
3 changed files with 132 additions and 112 deletions

View File

@ -16,8 +16,8 @@ tpm-y += eventlog/common.o
tpm-y += eventlog/tpm1.o
tpm-y += eventlog/tpm2.o
tpm-y += tpm-buf.o
tpm-y += tpm2-sessions.o
tpm-$(CONFIG_TCG_TPM2_HMAC) += tpm2-sessions.o
tpm-$(CONFIG_ACPI) += tpm_ppi.o eventlog/acpi.o
tpm-$(CONFIG_EFI) += eventlog/efi.o
tpm-$(CONFIG_OF) += eventlog/of.o

View File

@ -83,9 +83,6 @@
#define AES_KEY_BYTES AES_KEYSIZE_128
#define AES_KEY_BITS (AES_KEY_BYTES*8)
static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
u32 *handle, u8 *name);
/*
* This is the structure that carries all the auth information (like
* session handle, nonces, session key and auth) from use to use it is
@ -148,6 +145,7 @@ struct tpm2_auth {
u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE];
};
#ifdef CONFIG_TCG_TPM2_HMAC
/*
* Name Size based on TPM algorithm (assumes no hash bigger than 255)
*/
@ -163,6 +161,122 @@ static u8 name_size(const u8 *name)
return size_map[alg] + 2;
}
static int tpm2_parse_read_public(char *name, struct tpm_buf *buf)
{
struct tpm_header *head = (struct tpm_header *)buf->data;
off_t offset = TPM_HEADER_SIZE;
u32 tot_len = be32_to_cpu(head->length);
u32 val;
/* we're starting after the header so adjust the length */
tot_len -= TPM_HEADER_SIZE;
/* skip public */
val = tpm_buf_read_u16(buf, &offset);
if (val > tot_len)
return -EINVAL;
offset += val;
/* name */
val = tpm_buf_read_u16(buf, &offset);
if (val != name_size(&buf->data[offset]))
return -EINVAL;
memcpy(name, &buf->data[offset], val);
/* forget the rest */
return 0;
}
static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
if (rc)
return rc;
tpm_buf_append_u32(&buf, handle);
rc = tpm_transmit_cmd(chip, &buf, 0, "read public");
if (rc == TPM2_RC_SUCCESS)
rc = tpm2_parse_read_public(name, &buf);
tpm_buf_destroy(&buf);
return rc;
}
#endif /* CONFIG_TCG_TPM2_HMAC */
/**
* tpm_buf_append_name() - add a handle area to the buffer
* @chip: the TPM chip structure
* @buf: The buffer to be appended
* @handle: The handle to be appended
* @name: The name of the handle (may be NULL)
*
* In order to compute session HMACs, we need to know the names of the
* objects pointed to by the handles. For most objects, this is simply
* the actual 4 byte handle or an empty buf (in these cases @name
* should be NULL) but for volatile objects, permanent objects and NV
* areas, the name is defined as the hash (according to the name
* algorithm which should be set to sha256) of the public area to
* which the two byte algorithm id has been appended. For these
* objects, the @name pointer should point to this. If a name is
* required but @name is NULL, then TPM2_ReadPublic() will be called
* on the handle to obtain the name.
*
* As with most tpm_buf operations, success is assumed because failure
* 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)
{
#ifdef CONFIG_TCG_TPM2_HMAC
enum tpm2_mso_type mso = tpm2_handle_mso(handle);
struct tpm2_auth *auth;
int slot;
#endif
if (!tpm2_chip_auth(chip)) {
tpm_buf_append_u32(buf, handle);
/* count the number of handles in the upper bits of flags */
buf->handles++;
return;
}
#ifdef CONFIG_TCG_TPM2_HMAC
slot = (tpm_buf_length(buf) - TPM_HEADER_SIZE) / 4;
if (slot >= AUTH_MAX_NAMES) {
dev_err(&chip->dev, "TPM: too many handles\n");
return;
}
auth = chip->auth;
WARN(auth->session != tpm_buf_length(buf),
"name added in wrong place\n");
tpm_buf_append_u32(buf, handle);
auth->session += 4;
if (mso == TPM2_MSO_PERSISTENT ||
mso == TPM2_MSO_VOLATILE ||
mso == TPM2_MSO_NVRAM) {
if (!name)
tpm2_read_public(chip, handle, auth->name[slot]);
} else {
if (name)
dev_err(&chip->dev, "TPM: Handle does not require name but one is specified\n");
}
auth->name_h[slot] = handle;
if (name)
memcpy(auth->name[slot], name, name_size(name));
#endif
}
EXPORT_SYMBOL_GPL(tpm_buf_append_name);
#ifdef CONFIG_TCG_TPM2_HMAC
static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
u32 *handle, u8 *name);
/*
* It turns out the crypto hmac(sha256) is hard for us to consume
* because it assumes a fixed key and the TPM seems to change the key
@ -567,104 +681,6 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
}
EXPORT_SYMBOL(tpm_buf_fill_hmac_session);
static int tpm2_parse_read_public(char *name, struct tpm_buf *buf)
{
struct tpm_header *head = (struct tpm_header *)buf->data;
off_t offset = TPM_HEADER_SIZE;
u32 tot_len = be32_to_cpu(head->length);
u32 val;
/* we're starting after the header so adjust the length */
tot_len -= TPM_HEADER_SIZE;
/* skip public */
val = tpm_buf_read_u16(buf, &offset);
if (val > tot_len)
return -EINVAL;
offset += val;
/* name */
val = tpm_buf_read_u16(buf, &offset);
if (val != name_size(&buf->data[offset]))
return -EINVAL;
memcpy(name, &buf->data[offset], val);
/* forget the rest */
return 0;
}
static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name)
{
struct tpm_buf buf;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_READ_PUBLIC);
if (rc)
return rc;
tpm_buf_append_u32(&buf, handle);
rc = tpm_transmit_cmd(chip, &buf, 0, "read public");
if (rc == TPM2_RC_SUCCESS)
rc = tpm2_parse_read_public(name, &buf);
tpm_buf_destroy(&buf);
return rc;
}
/**
* tpm_buf_append_name() - add a handle area to the buffer
* @chip: the TPM chip structure
* @buf: The buffer to be appended
* @handle: The handle to be appended
* @name: The name of the handle (may be NULL)
*
* In order to compute session HMACs, we need to know the names of the
* objects pointed to by the handles. For most objects, this is simply
* the actual 4 byte handle or an empty buf (in these cases @name
* should be NULL) but for volatile objects, permanent objects and NV
* areas, the name is defined as the hash (according to the name
* algorithm which should be set to sha256) of the public area to
* which the two byte algorithm id has been appended. For these
* objects, the @name pointer should point to this. If a name is
* required but @name is NULL, then TPM2_ReadPublic() will be called
* on the handle to obtain the name.
*
* As with most tpm_buf operations, success is assumed because failure
* 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)
{
enum tpm2_mso_type mso = tpm2_handle_mso(handle);
struct tpm2_auth *auth = chip->auth;
int slot;
slot = (tpm_buf_length(buf) - TPM_HEADER_SIZE)/4;
if (slot >= AUTH_MAX_NAMES) {
dev_err(&chip->dev, "TPM: too many handles\n");
return;
}
WARN(auth->session != tpm_buf_length(buf),
"name added in wrong place\n");
tpm_buf_append_u32(buf, handle);
auth->session += 4;
if (mso == TPM2_MSO_PERSISTENT ||
mso == TPM2_MSO_VOLATILE ||
mso == TPM2_MSO_NVRAM) {
if (!name)
tpm2_read_public(chip, handle, auth->name[slot]);
} else {
if (name)
dev_err(&chip->dev, "TPM: Handle does not require name but one is specified\n");
}
auth->name_h[slot] = handle;
if (name)
memcpy(auth->name[slot], name, name_size(name));
}
EXPORT_SYMBOL(tpm_buf_append_name);
/**
* tpm_buf_check_hmac_response() - check the TPM return HMAC for correctness
* @chip: the TPM chip structure
@ -1311,3 +1327,4 @@ int tpm2_sessions_init(struct tpm_chip *chip)
return rc;
}
#endif /* CONFIG_TCG_TPM2_HMAC */

View File

@ -490,11 +490,22 @@ static inline void tpm_buf_append_empty_auth(struct tpm_buf *buf, u32 handle)
{
}
#endif
static inline struct tpm2_auth *tpm2_chip_auth(struct tpm_chip *chip)
{
#ifdef CONFIG_TCG_TPM2_HMAC
return chip->auth;
#else
return NULL;
#endif
}
void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
u32 handle, u8 *name);
#ifdef CONFIG_TCG_TPM2_HMAC
int tpm2_start_auth_session(struct tpm_chip *chip);
void 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 *buf,
u8 attributes, u8 *passphrase,
int passphraselen);
@ -521,14 +532,6 @@ static inline int tpm2_start_auth_session(struct tpm_chip *chip)
static inline void tpm2_end_auth_session(struct tpm_chip *chip)
{
}
static inline void tpm_buf_append_name(struct tpm_chip *chip,
struct tpm_buf *buf,
u32 handle, u8 *name)
{
tpm_buf_append_u32(buf, handle);
/* count the number of handles in the upper bits of flags */
buf->handles++;
}
static inline void tpm_buf_append_hmac_session(struct tpm_chip *chip,
struct tpm_buf *buf,
u8 attributes, u8 *passphrase,