Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 88492259 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'tpmdd-next-20190625' of git://git.infradead.org/users/jjs/linux-tpmdd

Pull tpm updates from Jarkko Sakkinen:
 "This contains two critical bug fixes and support for obtaining TPM
  events triggered by ExitBootServices().

  For the latter I have to give a quite verbose explanation not least
  because I had to revisit all the details myself to remember what was
  going on in Matthew's patches.

  The preboot software stack maintains an event log that gets entries
  every time something gets hashed to any of the PCR registers. What
  gets hashed could be a component to be run or perhaps log of some
  actions taken just to give couple of coarse examples. In general,
  anything relevant for the boot process that the preboot software does
  gets hashed and a log entry with a specific event type [1].

  The main application for this is remote attestation and the reason why
  it is useful is nicely put in the very first section of [1]:

     "Attestation is used to provide information about the platform’s
      state to a challenger. However, PCR contents are difficult to
      interpret; therefore, attestation is typically more useful when
      the PCR contents are accompanied by a measurement log. While not
      trusted on their own, the measurement log contains a richer set of
      information than do the PCR contents. The PCR contents are used to
      provide the validation of the measurement log."

  Because EFI_TCG2_PROTOCOL.GetEventLog() is not available after calling
  ExitBootServices(), Linux EFI stub copies the event log to a custom
  configuration table. Unfortunately, ExitBootServices() also generates
  events and obviously these events do not get copied to that table.
  Luckily firmware does this for us by providing a configuration table
  identified by EFI_TCG2_FINAL_EVENTS_TABLE_GUID.

  This essentially contains necessary changes to provide the full event
  log for the use the user space that is concatenated from these two
  partial event logs [2]"

[1] https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/
[2] The final concatenation is done in drivers/char/tpm/eventlog/efi.c

* tag 'tpmdd-next-20190625' of git://git.infradead.org/users/jjs/linux-tpmdd:
  tpm: Don't duplicate events from the final event log in the TCG2 log
  Abstract out support for locating an EFI config table
  tpm: Fix TPM 1.2 Shutdown sequence to prevent future TPM operations
  efi: Attempt to get the TCG2 event log in the boot stub
  tpm: Append the final event log to the TPM event log
  tpm: Reserve the TPM final events table
  tpm: Abstract crypto agile event size calculations
  tpm: Actually fail on TPM errors during "get random"
parents 222a21d2 166a2809
Loading
Loading
Loading
Loading
+52 −7
Original line number Diff line number Diff line
@@ -16,10 +16,13 @@
int tpm_read_log_efi(struct tpm_chip *chip)
{

	struct efi_tcg2_final_events_table *final_tbl = NULL;
	struct linux_efi_tpm_eventlog *log_tbl;
	struct tpm_bios_log *log;
	u32 log_size;
	u8 tpm_log_version;
	void *tmp;
	int ret;

	if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
		return -ENODEV;
@@ -47,15 +50,57 @@ int tpm_read_log_efi(struct tpm_chip *chip)

	/* malloc EventLog space */
	log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL);
	if (!log->bios_event_log)
		goto err_memunmap;
	log->bios_event_log_end = log->bios_event_log + log_size;
	if (!log->bios_event_log) {
		ret = -ENOMEM;
		goto out;
	}

	log->bios_event_log_end = log->bios_event_log + log_size;
	tpm_log_version = log_tbl->version;
	memunmap(log_tbl);
	return tpm_log_version;

err_memunmap:
	ret = tpm_log_version;

	if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR ||
	    efi_tpm_final_log_size == 0 ||
	    tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
		goto out;

	final_tbl = memremap(efi.tpm_final_log,
			     sizeof(*final_tbl) + efi_tpm_final_log_size,
			     MEMREMAP_WB);
	if (!final_tbl) {
		pr_err("Could not map UEFI TPM final log\n");
		kfree(log->bios_event_log);
		ret = -ENOMEM;
		goto out;
	}

	efi_tpm_final_log_size -= log_tbl->final_events_preboot_size;

	tmp = krealloc(log->bios_event_log,
		       log_size + efi_tpm_final_log_size,
		       GFP_KERNEL);
	if (!tmp) {
		kfree(log->bios_event_log);
		ret = -ENOMEM;
		goto out;
	}

	log->bios_event_log = tmp;

	/*
	 * Copy any of the final events log that didn't also end up in the
	 * main log. Events can be logged in both if events are generated
	 * between GetEventLog() and ExitBootServices().
	 */
	memcpy((void *)log->bios_event_log + log_size,
	       final_tbl->events + log_tbl->final_events_preboot_size,
	       efi_tpm_final_log_size);
	log->bios_event_log_end = log->bios_event_log +
		log_size + efi_tpm_final_log_size;

out:
	memunmap(final_tbl);
	memunmap(log_tbl);
	return -ENOMEM;
	return ret;
}
+1 −46
Original line number Diff line number Diff line
@@ -36,52 +36,7 @@
static size_t calc_tpm2_event_size(struct tcg_pcr_event2_head *event,
				   struct tcg_pcr_event *event_header)
{
	struct tcg_efi_specid_event_head *efispecid;
	struct tcg_event_field *event_field;
	void *marker;
	void *marker_start;
	u32 halg_size;
	size_t size;
	u16 halg;
	int i;
	int j;

	marker = event;
	marker_start = marker;
	marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
		+ sizeof(event->count);

	efispecid = (struct tcg_efi_specid_event_head *)event_header->event;

	/* Check if event is malformed. */
	if (event->count > efispecid->num_algs)
		return 0;

	for (i = 0; i < event->count; i++) {
		halg_size = sizeof(event->digests[i].alg_id);
		memcpy(&halg, marker, halg_size);
		marker = marker + halg_size;
		for (j = 0; j < efispecid->num_algs; j++) {
			if (halg == efispecid->digest_sizes[j].alg_id) {
				marker +=
					efispecid->digest_sizes[j].digest_size;
				break;
			}
		}
		/* Algorithm without known length. Such event is unparseable. */
		if (j == efispecid->num_algs)
			return 0;
	}

	event_field = (struct tcg_event_field *)marker;
	marker = marker + sizeof(event_field->event_size)
		+ event_field->event_size;
	size = marker - marker_start;

	if ((event->event_type == 0) && (event_field->event_size == 0))
		return 0;

	return size;
	return __calc_tpm2_event_size(event, event_header, false);
}

static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
+3 −3
Original line number Diff line number Diff line
@@ -289,15 +289,15 @@ static int tpm_class_shutdown(struct device *dev)
{
	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);

	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
	down_write(&chip->ops_sem);
	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
		if (!tpm_chip_start(chip)) {
			tpm2_shutdown(chip, TPM2_SU_CLEAR);
			tpm_chip_stop(chip);
		}
	}
	chip->ops = NULL;
	up_write(&chip->ops_sem);
	}

	return 0;
}
+5 −2
Original line number Diff line number Diff line
@@ -510,7 +510,7 @@ struct tpm1_get_random_out {
 *
 * Return:
 * *  number of bytes read
 * * -errno or a TPM return code otherwise
 * * -errno (positive TPM return codes are masked to -EIO)
 */
int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
@@ -531,8 +531,11 @@ int tpm1_get_random(struct tpm_chip *chip, u8 *dest, size_t max)

		rc = tpm_transmit_cmd(chip, &buf, sizeof(out->rng_data_len),
				      "attempting get random");
		if (rc)
		if (rc) {
			if (rc > 0)
				rc = -EIO;
			goto out;
		}

		out = (struct tpm1_get_random_out *)&buf.data[TPM_HEADER_SIZE];

+5 −2
Original line number Diff line number Diff line
@@ -297,7 +297,7 @@ struct tpm2_get_random_out {
 *
 * Return:
 *   size of the buffer on success,
 *   -errno otherwise
 *   -errno otherwise (positive TPM return codes are masked to -EIO)
 */
int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
{
@@ -324,8 +324,11 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
				       offsetof(struct tpm2_get_random_out,
						buffer),
				       "attempting get random");
		if (err)
		if (err) {
			if (err > 0)
				err = -EIO;
			goto out;
		}

		out = (struct tpm2_get_random_out *)
			&buf.data[TPM_HEADER_SIZE];
Loading