coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
crtm.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <fmap.h>
5 #include <cbfs.h>
6 #include "crtm.h"
7 #include <string.h>
8 
10 static inline int tcpa_log_available(void)
11 {
12  if (ENV_BOOTBLOCK)
13  return tcpa_log_initialized;
14 
15  return 1;
16 }
17 
18 /*
19  * Initializes the Core Root of Trust for Measurements
20  * in coreboot. The initial code in a chain of trust must measure
21  * itself.
22  *
23  * Summary:
24  * + Measures the FMAP FMAP partition.
25  * + Measures bootblock in CBFS or BOOTBLOCK FMAP partition.
26  * + If vboot starts in romstage, it measures the romstage
27  * in CBFS.
28  * + Measure the verstage if it is compiled as separate
29  * stage.
30  *
31  * Takes the current vboot context as parameter for s3 checks.
32  * returns on success VB2_SUCCESS, else a vboot error.
33  */
35 {
36  /* Initialize TCPA PRERAM log. */
37  if (!tcpa_log_available()) {
40  } else {
41  printk(BIOS_WARNING, "TSPI: CRTM already initialized!\n");
42  return VB2_SUCCESS;
43  }
44 
45  struct region_device fmap;
46  if (fmap_locate_area_as_rdev("FMAP", &fmap) == 0) {
47  if (tpm_measure_region(&fmap, TPM_CRTM_PCR, "FMAP: FMAP")) {
49  "TSPI: Couldn't measure FMAP into CRTM!\n");
50  return VB2_ERROR_UNKNOWN;
51  }
52  } else {
53  printk(BIOS_ERR, "TSPI: Could not find FMAP!\n");
54  }
55 
56  /* measure bootblock from RO */
57  struct region_device bootblock_fmap;
58  if (fmap_locate_area_as_rdev("BOOTBLOCK", &bootblock_fmap) == 0) {
59  if (tpm_measure_region(&bootblock_fmap,
61  "FMAP: BOOTBLOCK"))
62  return VB2_ERROR_UNKNOWN;
63  } else {
64  /* Mapping measures the file. We know we can safely map here because
65  bootblock-as-a-file is only used on x86, where we don't need cache to map. */
67  void *mapping = cbfs_ro_type_map("bootblock", NULL, &type);
68  if (!mapping) {
70  "TSPI: Couldn't measure bootblock into CRTM!\n");
71  return VB2_ERROR_UNKNOWN;
72  }
73  cbfs_unmap(mapping);
74  }
75 
76  return VB2_SUCCESS;
77 }
78 
79 static bool is_runtime_data(const char *name)
80 {
81  const char *allowlist = CONFIG_TPM_MEASURED_BOOT_RUNTIME_DATA;
82  size_t allowlist_len = sizeof(CONFIG_TPM_MEASURED_BOOT_RUNTIME_DATA) - 1;
83  size_t name_len = strlen(name);
84  const char *end;
85 
86  if (!allowlist_len || !name_len)
87  return false;
88 
89  while ((end = strchr(allowlist, ' '))) {
90  if (end - allowlist == name_len && !strncmp(allowlist, name, name_len))
91  return true;
92  allowlist = end + 1;
93  }
94 
95  return !strcmp(allowlist, name);
96 }
97 
98 uint32_t tspi_cbfs_measurement(const char *name, uint32_t type, const struct vb2_hash *hash)
99 {
100  uint32_t pcr_index;
101  char tcpa_metadata[TCPA_PCR_HASH_NAME];
102 
103  if (!tcpa_log_available()) {
104  if (tspi_init_crtm() != VB2_SUCCESS) {
106  "Initializing CRTM failed!\n");
107  return 0;
108  }
109  printk(BIOS_DEBUG, "CRTM initialized.\n");
110  }
111 
112  switch (type) {
113  case CBFS_TYPE_MRC_CACHE:
114  pcr_index = TPM_RUNTIME_DATA_PCR;
115  break;
116  /*
117  * mrc.bin is code executed on CPU, so it
118  * should not be considered runtime data
119  */
120  case CBFS_TYPE_MRC:
121  case CBFS_TYPE_STAGE:
122  case CBFS_TYPE_SELF:
123  case CBFS_TYPE_FIT:
124  pcr_index = TPM_CRTM_PCR;
125  break;
126  default:
127  if (is_runtime_data(name))
128  pcr_index = TPM_RUNTIME_DATA_PCR;
129  else
130  pcr_index = TPM_CRTM_PCR;
131  break;
132  }
133 
134  snprintf(tcpa_metadata, TCPA_PCR_HASH_NAME, "CBFS: %s", name);
135 
136  return tpm_extend_pcr(pcr_index, hash->algo, hash->raw, vb2_digest_size(hash->algo),
137  tcpa_metadata);
138 }
139 
141 {
142  int i;
143  enum vb2_hash_algorithm hash_alg;
144  struct tcpa_table *tclt = tcpa_log_init();
145 
146  /* This means the table is empty. */
147  if (!tcpa_log_available())
148  return VB2_SUCCESS;
149 
150  if (!tclt) {
151  printk(BIOS_WARNING, "TCPA: Log non-existent!\n");
152  return VB2_ERROR_UNKNOWN;
153  }
154  if (CONFIG(TPM1)) {
155  hash_alg = VB2_HASH_SHA1;
156  } else { /* CONFIG_TPM2 */
157  hash_alg = VB2_HASH_SHA256;
158  }
159 
160  printk(BIOS_DEBUG, "TPM: Write digests cached in TCPA log to PCR\n");
161  for (i = 0; i < tclt->num_entries; i++) {
162  struct tcpa_entry *tce = &tclt->entries[i];
163  if (tce) {
164  printk(BIOS_DEBUG, "TPM: Write digest for"
165  " %s into PCR %d\n",
166  tce->name, tce->pcr);
167  int result = tlcl_extend(tce->pcr,
168  tce->digest,
169  NULL);
170  if (result != TPM_SUCCESS) {
171  printk(BIOS_ERR, "TPM: Writing digest"
172  " of %s into PCR failed with error"
173  " %d\n",
174  tce->name, result);
175  return VB2_ERROR_UNKNOWN;
176  }
177  }
178  }
179 
180  return VB2_SUCCESS;
181 }
const char * name
Definition: mmu.c:92
void cbfs_unmap(void *mapping)
Definition: cbfs.c:86
static void * cbfs_ro_type_map(const char *name, size_t *size_out, enum cbfs_type *type)
Definition: cbfs.h:261
cbfs_type
@ CBFS_TYPE_MRC
@ CBFS_TYPE_SELF
@ CBFS_TYPE_STAGE
@ CBFS_TYPE_FIT
@ CBFS_TYPE_MRC_CACHE
@ CBFS_TYPE_BOOTBLOCK
#define printk(level,...)
Definition: stdlib.h:16
static uint32_t tspi_init_crtm(void)
Definition: crtm.c:34
uint32_t tspi_cbfs_measurement(const char *name, uint32_t type, const struct vb2_hash *hash)
Extend a measurement hash taken for a CBFS file into the appropriate PCR.
Definition: crtm.c:98
static bool is_runtime_data(const char *name)
Definition: crtm.c:79
static int tcpa_log_available(void)
Definition: crtm.c:10
int tspi_measure_cache_to_pcr(void)
Measure digests cached in TCPA log entries into PCRs.
Definition: crtm.c:140
static int tcpa_log_initialized
Definition: crtm.c:9
#define TPM_RUNTIME_DATA_PCR
Definition: crtm.h:17
#define TPM_CRTM_PCR
Definition: crtm.h:12
@ CONFIG
Definition: dsi_common.h:201
int fmap_locate_area_as_rdev(const char *name, struct region_device *area)
Definition: fmap.c:144
unsigned int type
Definition: edid.c:57
void tcpa_preram_log_clear(void)
Clears the pre-RAM tcpa log data and initializes any content with default values.
Definition: log.c:116
struct tcpa_table * tcpa_log_init(void)
Get the pointer to the single instance of global tcpa log data, and initialize it when necessary.
Definition: log.c:33
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
result
Definition: mrc_cache.c:35
#define ENV_BOOTBLOCK
Definition: rules.h:148
#define NULL
Definition: stddef.h:19
unsigned int uint32_t
Definition: stdint.h:14
int strcmp(const char *s1, const char *s2)
Definition: string.c:103
char * strchr(const char *s, int c)
Definition: string.c:50
int strncmp(const char *s1, const char *s2, int maxlen)
Definition: string.c:114
size_t strlen(const char *src)
Definition: string.c:42
uint8_t digest[TCPA_DIGEST_MAX_LENGTH]
uint32_t pcr
char name[TCPA_PCR_HASH_NAME]
uint16_t num_entries
struct tcpa_entry entries[0]
uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest, uint8_t *out_digest)
Perform a TPM_Extend.
Definition: tss.c:334
#define TCPA_PCR_HASH_NAME
uint32_t tpm_extend_pcr(int pcr, enum vb2_hash_algorithm digest_algo, const uint8_t *digest, size_t digest_len, const char *name)
Ask vboot for a digest and extend a TPM PCR with it.
Definition: tspi.c:220
uint32_t tpm_measure_region(const struct region_device *rdev, uint8_t pcr, const char *rname)
Measure a given region device and extend given PCR with the result.
#define TPM_SUCCESS
Definition: tss_common.h:9
int snprintf(char *buf, size_t size, const char *fmt,...)
Note: This file is only for POSIX compatibility, and is meant to be chain-included via string....
Definition: vsprintf.c:35