Commit 4ba05b0e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull tpm fixes from Jarkko Sakkinen:
 "Two bug fixes for TPM bus encryption (the remaining reported issues in
  the feature)"

* tag 'tpmdd-next-6.12-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
  tpm: Disable TPM on tpm2_create_primary() failure
  tpm: Opt-in in disable PCR integrity protection
parents 9f8e716d 423893fc
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -6727,6 +6727,15 @@
	torture.verbose_sleep_duration= [KNL]
			Duration of each verbose-printk() sleep in jiffies.

	tpm.disable_pcr_integrity= [HW,TPM]
			Do not protect PCR registers from unintended physical
			access, or interposers in the bus by the means of
			having an integrity protected session wrapped around
			TPM2_PCR_Extend command. Consider this in a situation
			where TPM is heavily utilized by IMA, thus protection
			causing a major performance hit, and the space where
			machines are deployed is by other means guarded.

	tpm_suspend_pcr=[HW,TPM]
			Format: integer pcr id
			Specify that at suspend time, the tpm driver
+20 −0
Original line number Diff line number Diff line
@@ -146,6 +146,26 @@ void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
}
EXPORT_SYMBOL_GPL(tpm_buf_append_u32);

/**
 * tpm_buf_append_handle() - Add a handle
 * @chip:	&tpm_chip instance
 * @buf:	&tpm_buf instance
 * @handle:	a TPM object handle
 *
 * Add a handle to the buffer, and increase the count tracking the number of
 * handles in the command buffer. Works only for command buffers.
 */
void tpm_buf_append_handle(struct tpm_chip *chip, struct tpm_buf *buf, u32 handle)
{
	if (buf->flags & TPM_BUF_TPM2B) {
		dev_err(&chip->dev, "Invalid buffer type (TPM2B)\n");
		return;
	}

	tpm_buf_append_u32(buf, handle);
	buf->handles++;
}

/**
 * tpm_buf_read() - Read from a TPM buffer
 * @buf:	&tpm_buf instance
+22 −8
Original line number Diff line number Diff line
@@ -14,6 +14,10 @@
#include "tpm.h"
#include <crypto/hash_info.h>

static bool disable_pcr_integrity;
module_param(disable_pcr_integrity, bool, 0444);
MODULE_PARM_DESC(disable_pcr_integrity, "Disable integrity protection of TPM2_PCR_Extend");

static struct tpm2_hash tpm2_hash_map[] = {
	{HASH_ALGO_SHA1, TPM_ALG_SHA1},
	{HASH_ALGO_SHA256, TPM_ALG_SHA256},
@@ -232,18 +236,26 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
	int rc;
	int i;

	if (!disable_pcr_integrity) {
		rc = tpm2_start_auth_session(chip);
		if (rc)
			return rc;
	}

	rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
	if (rc) {
		if (!disable_pcr_integrity)
			tpm2_end_auth_session(chip);
		return rc;
	}

	if (!disable_pcr_integrity) {
		tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
		tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
	} else {
		tpm_buf_append_handle(chip, &buf, pcr_idx);
		tpm_buf_append_auth(chip, &buf, 0, NULL, 0);
	}

	tpm_buf_append_u32(&buf, chip->nr_allocated_banks);

@@ -253,8 +265,10 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
			       chip->allocated_banks[i].digest_size);
	}

	if (!disable_pcr_integrity)
		tpm_buf_fill_hmac_session(chip, &buf);
	rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
	if (!disable_pcr_integrity)
		rc = tpm_buf_check_hmac_response(chip, &buf, rc);

	tpm_buf_destroy(&buf);
+33 −25
Original line number Diff line number Diff line
@@ -237,9 +237,7 @@ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
#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++;
		tpm_buf_append_handle(chip, buf, handle);
		return;
	}

@@ -272,6 +270,31 @@ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
}
EXPORT_SYMBOL_GPL(tpm_buf_append_name);

void tpm_buf_append_auth(struct tpm_chip *chip, struct tpm_buf *buf,
			 u8 attributes, u8 *passphrase, int passphrase_len)
{
	/* offset tells us where the sessions area begins */
	int offset = buf->handles * 4 + TPM_HEADER_SIZE;
	u32 len = 9 + passphrase_len;

	if (tpm_buf_length(buf) != offset) {
		/* not the first session so update the existing length */
		len += get_unaligned_be32(&buf->data[offset]);
		put_unaligned_be32(len, &buf->data[offset]);
	} else {
		tpm_buf_append_u32(buf, len);
	}
	/* auth handle */
	tpm_buf_append_u32(buf, TPM2_RS_PW);
	/* nonce */
	tpm_buf_append_u16(buf, 0);
	/* attributes */
	tpm_buf_append_u8(buf, 0);
	/* passphrase */
	tpm_buf_append_u16(buf, passphrase_len);
	tpm_buf_append(buf, passphrase, passphrase_len);
}

/**
 * tpm_buf_append_hmac_session() - Append a TPM session element
 * @chip: the TPM chip structure
@@ -309,26 +332,8 @@ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
#endif

	if (!tpm2_chip_auth(chip)) {
		/* offset tells us where the sessions area begins */
		int offset = buf->handles * 4 + TPM_HEADER_SIZE;
		u32 len = 9 + passphrase_len;

		if (tpm_buf_length(buf) != offset) {
			/* not the first session so update the existing length */
			len += get_unaligned_be32(&buf->data[offset]);
			put_unaligned_be32(len, &buf->data[offset]);
		} else {
			tpm_buf_append_u32(buf, len);
		}
		/* auth handle */
		tpm_buf_append_u32(buf, TPM2_RS_PW);
		/* nonce */
		tpm_buf_append_u16(buf, 0);
		/* attributes */
		tpm_buf_append_u8(buf, 0);
		/* passphrase */
		tpm_buf_append_u16(buf, passphrase_len);
		tpm_buf_append(buf, passphrase, passphrase_len);
		tpm_buf_append_auth(chip, buf, attributes, passphrase,
				    passphrase_len);
		return;
	}

@@ -948,10 +953,13 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key)
	/* Deduce from the name change TPM interference: */
	dev_err(&chip->dev, "null key integrity check failed\n");
	tpm2_flush_context(chip, tmp_null_key);
	chip->flags |= TPM_CHIP_FLAG_DISABLE;

err:
	return rc ? -ENODEV : 0;
	if (rc) {
		chip->flags |= TPM_CHIP_FLAG_DISABLE;
		rc = -ENODEV;
	}
	return rc;
}

/**
+3 −0
Original line number Diff line number Diff line
@@ -421,6 +421,7 @@ void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value);
u8 tpm_buf_read_u8(struct tpm_buf *buf, off_t *offset);
u16 tpm_buf_read_u16(struct tpm_buf *buf, off_t *offset);
u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset);
void tpm_buf_append_handle(struct tpm_chip *chip, struct tpm_buf *buf, u32 handle);

/*
 * Check if TPM device is in the firmware upgrade mode.
@@ -505,6 +506,8 @@ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
				 u8 attributes, u8 *passphrase,
				 int passphraselen);
void tpm_buf_append_auth(struct tpm_chip *chip, struct tpm_buf *buf,
			 u8 attributes, u8 *passphrase, int passphraselen);
static inline void tpm_buf_append_hmac_session_opt(struct tpm_chip *chip,
						   struct tpm_buf *buf,
						   u8 attributes,