diff mbox series

[3/3] efi_loader: Extend PCR's for firmware measurements

Message ID 20211118061751.3334620-4-ruchika.gupta@linaro.org
State New
Headers show
Series [1/3] efi_loader: Add check for event log passed from firmware | expand

Commit Message

Ruchika Gupta Nov. 18, 2021, 6:17 a.m. UTC
Firmwares before U-Boot may be capable of doing tpm measurements
and passing them to U-Boot in the form of eventlog. However there
may be scenarios where the firmwares don't have TPM driver and
are not capable of extending the measurements in the PCRs. To
cater to such platforms, read the PCR0 to determine if the
previous firmwares have extended the PCR0. If not, then extend
the PCR's as the eventlog is parsed.

Signed-off-by: Ruchika Gupta <ruchika.gupta@linaro.org>
---
 lib/efi_loader/efi_tcg2.c | 86 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

Comments

Ilias Apalodimas Nov. 22, 2021, 11:41 a.m. UTC | #1
On Thu, Nov 18, 2021 at 11:47:51AM +0530, Ruchika Gupta wrote:
> Firmwares before U-Boot may be capable of doing tpm measurements
> and passing them to U-Boot in the form of eventlog. However there
> may be scenarios where the firmwares don't have TPM driver and
> are not capable of extending the measurements in the PCRs. To
> cater to such platforms, read the PCR0 to determine if the
> previous firmwares have extended the PCR0. If not, then extend
> the PCR's as the eventlog is parsed.
> 
> Signed-off-by: Ruchika Gupta <ruchika.gupta@linaro.org>
> ---
>  lib/efi_loader/efi_tcg2.c | 86 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
> 
> diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
> index c97766eae3..cbd0c7d224 100644
> --- a/lib/efi_loader/efi_tcg2.c
> +++ b/lib/efi_loader/efi_tcg2.c
> @@ -178,6 +178,43 @@ static efi_status_t tcg2_pcr_extend(struct udevice *dev, u32 pcr_index,
>  	return EFI_SUCCESS;
>  }
>  
> +/* tcg2_pcr_read - Read PCRs for a TPM2 device for a given tpml_digest_values
> + *
> + * @dev:		device
> + * @digest_list:	list of digest algorithms to extend
> + *
> + * @Return: status code
> + */
> +static efi_status_t tcg2_pcr_read(struct udevice *dev, u32 pcr_index,
> +				    struct tpml_digest_values *digest_list)
> +{
> +	struct tpm_chip_priv *priv;
> +	unsigned int updates, pcr_select_min;
> +	u32 rc;
> +	size_t i;
> +
> +	priv = dev_get_uclass_priv(dev);
> +	if (!priv)
> +		return EFI_DEVICE_ERROR;
> +
> +	pcr_select_min = priv->pcr_select_min;
> +
> +	for (i = 0; i < digest_list->count; i++) {
> +		u16 hash_alg = digest_list->digests[i].hash_alg;
> +		u8 *digest = (u8 *)&digest_list->digests[i].digest;
> +
> +		rc = tpm2_pcr_read(dev, pcr_index, pcr_select_min,
> +				    hash_alg, digest, alg_to_len(hash_alg),
> +				    &updates);
> +		if (rc) {
> +			EFI_PRINT("Failed to read PCR\n");
> +			return EFI_DEVICE_ERROR;
> +		}
> +	}
> +
> +	return EFI_SUCCESS;
> +}
> +
>  /* tcg2_agile_log_append - Append an agile event to out eventlog
>   *
>   * @pcr_index:		PCR index
> @@ -1488,10 +1525,12 @@ static efi_status_t efi_init_event_log(struct udevice *dev)
>  	struct tcg_pcr_event *event_header = NULL;
>  	struct tpml_digest_values digest_list;
>  	size_t spec_event_size;
> +	bool extend_pcr = false;
>  	efi_status_t ret;
>  	u32 pcr, pos;
>  	u64 base;
>  	u32 sz;
> +	int i;
>  
>  	ret = platform_get_tpm2_device(&dev);
>  	if (ret != EFI_SUCCESS)
> @@ -1541,6 +1580,26 @@ static efi_status_t efi_init_event_log(struct udevice *dev)
>  			goto free_pool;
>  		}
>  
> +		ret = tcg2_pcr_read(dev, 0, &digest_list);
> +		if (ret) {
> +			log_err("Error reading PCR 0\n");
> +			goto free_pool;
> +		}
> +
> +		/*
> +		 * If PCR0 is 0, previous firmware didn't have the capability
> +		 * to extend the PCR. In this scenario, extend the PCR as
> +		 * the eventlog is parsed.
> +		 */
> +		for (i = 0; i < digest_list.count; i++) {
> +			u8 buffer[TPM2_DIGEST_LEN] =  { 0 };
> +			u16 hash_alg = digest_list.digests[i].hash_alg;
> +
> +			if (!memcmp((u8 *)&digest_list.digests[i].digest,
> +				    buffer, alg_to_len(hash_alg)))
> +				extend_pcr = true;
> +		}
> +
>  		while (pos < sz) {
>  			ret = tcg2_parse_event(dev, buffer, sz, &pos,
>  					       &digest_list, &pcr);
> @@ -1548,6 +1607,33 @@ static efi_status_t efi_init_event_log(struct udevice *dev)
>  				log_err("Error parsing event\n");
>  				goto free_pool;
>  			}
> +
> +			if (pcr != 0) {
> +				/*
> +				 * Eventlog passed by firmware should extend
> +				 * PCR0 only.

I don't get this comment.  The previous stage bootloader could extend any
PCR (0-7) as long as it adheres to the PC client spec right?
I think we just need the logic below here,  were we decide to start with an
empty eventlog if the prior stage boot loader doesn't expose one.

> +				 */
> +				log_err("Invalid PCR\n");
> +				goto free_pool;
> +			}
> +
> +			if (extend_pcr) {
> +				ret = tcg2_pcr_extend(dev, pcr, &digest_list);
> +				if (ret != EFI_SUCCESS) {
> +					log_err("Error in extending PCR\n");
> +					goto free_pool;
> +				}
> +
> +				/* Clear the digest for next event */
> +				for (i = 0; i < digest_list.count; i++) {
> +					u16 hash_alg =
> +						digest_list.digests[i].hash_alg;
> +					u8 *digest =
> +					   (u8 *)&digest_list.digests[i].digest;
> +
> +					memset(digest, 0, alg_to_len(hash_alg));
> +				}
> +			}
>  		}
>  
>  		memcpy(event_log.buffer, buffer, sz);
> -- 
> 2.25.1
> 


Cheers
/Ilias
diff mbox series

Patch

diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
index c97766eae3..cbd0c7d224 100644
--- a/lib/efi_loader/efi_tcg2.c
+++ b/lib/efi_loader/efi_tcg2.c
@@ -178,6 +178,43 @@  static efi_status_t tcg2_pcr_extend(struct udevice *dev, u32 pcr_index,
 	return EFI_SUCCESS;
 }
 
+/* tcg2_pcr_read - Read PCRs for a TPM2 device for a given tpml_digest_values
+ *
+ * @dev:		device
+ * @digest_list:	list of digest algorithms to extend
+ *
+ * @Return: status code
+ */
+static efi_status_t tcg2_pcr_read(struct udevice *dev, u32 pcr_index,
+				    struct tpml_digest_values *digest_list)
+{
+	struct tpm_chip_priv *priv;
+	unsigned int updates, pcr_select_min;
+	u32 rc;
+	size_t i;
+
+	priv = dev_get_uclass_priv(dev);
+	if (!priv)
+		return EFI_DEVICE_ERROR;
+
+	pcr_select_min = priv->pcr_select_min;
+
+	for (i = 0; i < digest_list->count; i++) {
+		u16 hash_alg = digest_list->digests[i].hash_alg;
+		u8 *digest = (u8 *)&digest_list->digests[i].digest;
+
+		rc = tpm2_pcr_read(dev, pcr_index, pcr_select_min,
+				    hash_alg, digest, alg_to_len(hash_alg),
+				    &updates);
+		if (rc) {
+			EFI_PRINT("Failed to read PCR\n");
+			return EFI_DEVICE_ERROR;
+		}
+	}
+
+	return EFI_SUCCESS;
+}
+
 /* tcg2_agile_log_append - Append an agile event to out eventlog
  *
  * @pcr_index:		PCR index
@@ -1488,10 +1525,12 @@  static efi_status_t efi_init_event_log(struct udevice *dev)
 	struct tcg_pcr_event *event_header = NULL;
 	struct tpml_digest_values digest_list;
 	size_t spec_event_size;
+	bool extend_pcr = false;
 	efi_status_t ret;
 	u32 pcr, pos;
 	u64 base;
 	u32 sz;
+	int i;
 
 	ret = platform_get_tpm2_device(&dev);
 	if (ret != EFI_SUCCESS)
@@ -1541,6 +1580,26 @@  static efi_status_t efi_init_event_log(struct udevice *dev)
 			goto free_pool;
 		}
 
+		ret = tcg2_pcr_read(dev, 0, &digest_list);
+		if (ret) {
+			log_err("Error reading PCR 0\n");
+			goto free_pool;
+		}
+
+		/*
+		 * If PCR0 is 0, previous firmware didn't have the capability
+		 * to extend the PCR. In this scenario, extend the PCR as
+		 * the eventlog is parsed.
+		 */
+		for (i = 0; i < digest_list.count; i++) {
+			u8 buffer[TPM2_DIGEST_LEN] =  { 0 };
+			u16 hash_alg = digest_list.digests[i].hash_alg;
+
+			if (!memcmp((u8 *)&digest_list.digests[i].digest,
+				    buffer, alg_to_len(hash_alg)))
+				extend_pcr = true;
+		}
+
 		while (pos < sz) {
 			ret = tcg2_parse_event(dev, buffer, sz, &pos,
 					       &digest_list, &pcr);
@@ -1548,6 +1607,33 @@  static efi_status_t efi_init_event_log(struct udevice *dev)
 				log_err("Error parsing event\n");
 				goto free_pool;
 			}
+
+			if (pcr != 0) {
+				/*
+				 * Eventlog passed by firmware should extend
+				 * PCR0 only.
+				 */
+				log_err("Invalid PCR\n");
+				goto free_pool;
+			}
+
+			if (extend_pcr) {
+				ret = tcg2_pcr_extend(dev, pcr, &digest_list);
+				if (ret != EFI_SUCCESS) {
+					log_err("Error in extending PCR\n");
+					goto free_pool;
+				}
+
+				/* Clear the digest for next event */
+				for (i = 0; i < digest_list.count; i++) {
+					u16 hash_alg =
+						digest_list.digests[i].hash_alg;
+					u8 *digest =
+					   (u8 *)&digest_list.digests[i].digest;
+
+					memset(digest, 0, alg_to_len(hash_alg));
+				}
+			}
 		}
 
 		memcpy(event_log.buffer, buffer, sz);