Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /* Copyright 2020 IBM Corp. */
3 : : #ifndef pr_fmt
4 : : #define pr_fmt(fmt) "SECBOOT_TPM: " fmt
5 : : #endif
6 : :
7 : : #include <stdlib.h>
8 : : #include <skiboot.h>
9 : : #include <opal.h>
10 : : #include <mbedtls/sha256.h>
11 : : #include "../secvar.h"
12 : : #include "../secvar_devtree.h"
13 : : #include "secboot_tpm.h"
14 : : #include <tssskiboot.h>
15 : : #include <ibmtss/TPM_Types.h>
16 : :
17 : : #define CYCLE_BIT(b) (b^0x1)
18 : :
19 : : #define SECBOOT_TPM_MAX_VAR_SIZE 8192
20 : :
21 : : struct secboot *secboot_image = NULL;
22 : : struct tpmnv_vars *tpmnv_vars_image = NULL;
23 : : struct tpmnv_control *tpmnv_control_image = NULL;
24 : :
25 : : const size_t tpmnv_vars_size = 2048;
26 : :
27 : : /* Expected TPM NV index name field from NV_ReadPublic given our known
28 : : * set of attributes (see tss_nv_define_space).
29 : : * See Part 1 Section 16, and Part 2 Section 13.5 of the TPM Specification
30 : : * for how this is calculated
31 : : *
32 : : * These hashes are calculated and checked BEFORE TPM2_NV_WriteLock is called,
33 : : * which alters the hash slightly as it sets TPMA_NV_WRITELOCKED
34 : : */
35 : : const uint8_t tpmnv_vars_name[] = {
36 : : 0x00, 0x0b, 0x7a, 0xdb, 0x70, 0xdd, 0x27, 0x94, 0x93, 0x26, 0x11, 0xe2, 0x97,
37 : : 0x00, 0x77, 0x22, 0x4d, 0x5a, 0x74, 0xf8, 0x91, 0x6f, 0xbf, 0xf8, 0x51, 0x4a,
38 : : 0x67, 0x6f, 0xd9, 0xa8, 0xc3, 0xfc, 0x39, 0xed,
39 : : };
40 : :
41 : : const uint8_t tpmnv_control_name[] = {
42 : : 0x00, 0x0b, 0xad, 0x47, 0x6b, 0xa5, 0xdf, 0xb1, 0xe2, 0x18, 0x50, 0xf6, 0x05,
43 : : 0x67, 0xe8, 0x8b, 0xa9, 0x0f, 0x86, 0x1f, 0x06, 0xab, 0x43, 0x96, 0x7f, 0x6e,
44 : : 0x85, 0x33, 0x5b, 0xa6, 0xf0, 0x63, 0x73, 0xd0,
45 : : };
46 : :
47 : : const uint8_t tpmnv_vars_prov_name[] = {
48 : : 0x00, 0x0b, 0x58, 0x36, 0x2c, 0xbf, 0xec, 0x0e, 0xcc, 0xbf, 0xa9, 0x41, 0x94,
49 : : 0xe9, 0x95, 0xe8, 0x3b, 0xd7, 0x8b, 0x52, 0xac, 0x61, 0x6f, 0xe6, 0x42, 0x93,
50 : : 0xbb, 0x5a, 0x79, 0x9f, 0xcc, 0x60, 0x5e, 0x8d,
51 : : };
52 : :
53 : : const uint8_t tpmnv_control_prov_name[] = {
54 : : 0x00, 0x0b, 0x7b, 0xd6, 0x02, 0xac, 0xf5, 0x34, 0x54, 0x5c, 0x3e, 0xda, 0xe5,
55 : : 0xb2, 0xe4, 0x93, 0x4f, 0x36, 0xfb, 0x7f, 0xea, 0xbe, 0xfa, 0x3c, 0xfe, 0xed,
56 : : 0x6a, 0x12, 0xfb, 0xc8, 0xf7, 0x92, 0x0e, 0xd3,
57 : : };
58 : :
59 : : /* Calculate a SHA256 hash over the supplied buffer */
60 : 3 : static int calc_bank_hash(char *target_hash, const char *source_buf, uint64_t size)
61 : : {
62 : : mbedtls_sha256_context ctx;
63 : : int rc;
64 : :
65 : 3 : mbedtls_sha256_init(&ctx);
66 : :
67 : 3 : rc = mbedtls_sha256_update_ret(&ctx, source_buf, size);
68 : 3 : if (rc)
69 : 0 : goto out;
70 : :
71 : 3 : mbedtls_sha256_finish_ret(&ctx, target_hash);
72 : 3 : if (rc)
73 : 0 : goto out;
74 : :
75 : 3 : out:
76 : 3 : mbedtls_sha256_free(&ctx);
77 : 3 : return rc;
78 : : }
79 : :
80 : : /* Reformat the TPMNV space */
81 : 1 : static int tpmnv_format(void)
82 : : {
83 : : int rc;
84 : :
85 : 1 : memset(tpmnv_vars_image, 0x00, tpmnv_vars_size);
86 : 1 : memset(tpmnv_control_image, 0x00, sizeof(struct tpmnv_control));
87 : :
88 : 1 : tpmnv_vars_image->header.magic_number = SECBOOT_MAGIC_NUMBER;
89 : 1 : tpmnv_vars_image->header.version = SECBOOT_VERSION;
90 : 1 : tpmnv_control_image->header.magic_number = SECBOOT_MAGIC_NUMBER;
91 : 1 : tpmnv_control_image->header.version = SECBOOT_VERSION;
92 : :
93 : : /* Counts as first write to the TPM NV, which sets the
94 : : * TPMA_NVA_WRITTEN attribute */
95 : 1 : rc = tpmnv_ops.write(SECBOOT_TPMNV_VARS_INDEX,
96 : : tpmnv_vars_image,
97 : : tpmnv_vars_size, 0);
98 : 1 : if (rc) {
99 : 0 : prlog(PR_ERR, "Could not write new formatted data to VARS index, rc=%d\n", rc);
100 : 0 : return rc;
101 : : }
102 : :
103 : 1 : rc = tpmnv_ops.write(SECBOOT_TPMNV_CONTROL_INDEX,
104 : : tpmnv_control_image,
105 : : sizeof(struct tpmnv_control), 0);
106 : 1 : if (rc)
107 : 0 : prlog(PR_ERR, "Could not write new formatted data to CONTROL index, rc=%d\n", rc);
108 : :
109 : 1 : return rc;
110 : : }
111 : :
112 : : /* Reformat the secboot PNOR space */
113 : 1 : static int secboot_format(void)
114 : : {
115 : : int rc;
116 : :
117 : 1 : memset(secboot_image, 0x00, sizeof(struct secboot));
118 : :
119 : 1 : secboot_image->header.magic_number = SECBOOT_MAGIC_NUMBER;
120 : 1 : secboot_image->header.version = SECBOOT_VERSION;
121 : :
122 : : /* Write the hash of the empty bank to the tpm so future loads work */
123 : 1 : rc = calc_bank_hash(tpmnv_control_image->bank_hash[0],
124 : 1 : secboot_image->bank[0],
125 : : SECBOOT_VARIABLE_BANK_SIZE);
126 : 1 : if (rc) {
127 : 0 : prlog(PR_ERR, "Bank hash failed to calculate somehow\n");
128 : 0 : return rc;
129 : : }
130 : : /* Clear bank_hash[1] anyway, to match initial zeroed bank hash state */
131 : 1 : memset(tpmnv_control_image->bank_hash[1], 0x00, sizeof(tpmnv_control_image->bank_hash[1]));
132 : :
133 : 1 : tpmnv_control_image->active_bit = 0;
134 : :
135 : 1 : rc = tpmnv_ops.write(SECBOOT_TPMNV_CONTROL_INDEX,
136 : : tpmnv_control_image,
137 : : sizeof(struct tpmnv_control),
138 : : 0);
139 : 1 : if (rc) {
140 : 0 : prlog(PR_ERR, "Could not write fresh formatted bank hashes to CONTROL index, rc=%d\n", rc);
141 : 0 : return rc;
142 : : }
143 : :
144 : 1 : rc = flash_secboot_write(0, secboot_image, sizeof(struct secboot));
145 : 1 : if (rc)
146 : 0 : prlog(PR_ERR, "Could not write formatted data to PNOR, rc=%d\n", rc);
147 : :
148 : 1 : return rc;
149 : : }
150 : :
151 : :
152 : : /*
153 : : * Serialize one variable to a target memory location.
154 : : * Returns the advanced target pointer,
155 : : * NULL if advanced pointer would exceed the supplied bound
156 : : */
157 : 8 : static char *secboot_serialize_secvar(char *target, const struct secvar *var, const char *end)
158 : : {
159 : 8 : if ((target + sizeof(uint64_t) + sizeof(uint64_t)
160 : 8 : + var->key_len + var->data_size) > end)
161 : 0 : return NULL;
162 : :
163 : 8 : *((uint64_t*) target) = cpu_to_be64(var->key_len);
164 : 8 : target += sizeof(var->key_len);
165 : 8 : *((uint64_t*) target) = cpu_to_be64(var->data_size);
166 : 8 : target += sizeof(var->data_size);
167 : 8 : memcpy(target, var->key, var->key_len);
168 : 8 : target += var->key_len;
169 : 8 : memcpy(target, var->data, var->data_size);
170 : 8 : target += var->data_size;
171 : :
172 : 8 : return target;
173 : : }
174 : :
175 : :
176 : : /* Flattens a linked-list bank into a contiguous buffer for writing */
177 : 4 : static int secboot_serialize_bank(const struct list_head *bank, char *target,
178 : : size_t target_size, int flags)
179 : : {
180 : : struct secvar *var;
181 : 4 : char *end = target + target_size;
182 : :
183 : 4 : assert(bank);
184 : 4 : assert(target);
185 : :
186 : 4 : memset(target, 0x00, target_size);
187 : :
188 : 20 : list_for_each(bank, var, link) {
189 : 16 : if (var->flags != flags)
190 : 8 : continue;
191 : :
192 : 8 : target = secboot_serialize_secvar(target, var, end);
193 : 8 : if (!target) {
194 : 0 : prlog(PR_ERR, "Ran out of %s space, giving up!",
195 : : (flags & SECVAR_FLAG_PROTECTED) ? "TPMNV" : "PNOR");
196 : 0 : return OPAL_EMPTY;
197 : : }
198 : : }
199 : :
200 : 4 : return OPAL_SUCCESS;
201 : : }
202 : :
203 : : /* Helper for the variable-bank specific writing logic */
204 : 2 : static int secboot_tpm_write_variable_bank(const struct list_head *bank)
205 : : {
206 : : int rc;
207 : : uint64_t bit;
208 : :
209 : 2 : bit = CYCLE_BIT(tpmnv_control_image->active_bit);
210 : : /* Serialize TPMNV variables */
211 : 2 : rc = secboot_serialize_bank(bank, tpmnv_vars_image->vars, tpmnv_vars_size - sizeof(struct tpmnv_vars), SECVAR_FLAG_PROTECTED);
212 : 2 : if (rc)
213 : 0 : goto out;
214 : :
215 : :
216 : : /* Write TPMNV variables to actual NV */
217 : 2 : rc = tpmnv_ops.write(SECBOOT_TPMNV_VARS_INDEX, tpmnv_vars_image, tpmnv_vars_size, 0);
218 : 2 : if (rc)
219 : 0 : goto out;
220 : :
221 : : /* Serialize the PNOR variables, but don't write to flash until after the bank hash */
222 : 2 : rc = secboot_serialize_bank(bank, secboot_image->bank[bit], SECBOOT_VARIABLE_BANK_SIZE, 0);
223 : 2 : if (rc)
224 : 0 : goto out;
225 : :
226 : : /* Calculate the bank hash, and write to TPM NV */
227 : 2 : rc = calc_bank_hash(tpmnv_control_image->bank_hash[bit], secboot_image->bank[bit], SECBOOT_VARIABLE_BANK_SIZE);
228 : 2 : if (rc)
229 : 0 : goto out;
230 : :
231 : 2 : rc = tpmnv_ops.write(SECBOOT_TPMNV_CONTROL_INDEX, tpmnv_control_image->bank_hash[bit],
232 : : SHA256_DIGEST_LENGTH, offsetof(struct tpmnv_control, bank_hash[bit]));
233 : 2 : if (rc)
234 : 0 : goto out;
235 : :
236 : : /* Write new variable bank to pnor */
237 : 2 : rc = flash_secboot_write(0, secboot_image, sizeof(struct secboot));
238 : 2 : if (rc)
239 : 0 : goto out;
240 : :
241 : : /* Flip the bit, and write to TPM NV */
242 : 2 : tpmnv_control_image->active_bit = bit;
243 : 2 : rc = tpmnv_ops.write(SECBOOT_TPMNV_CONTROL_INDEX,
244 : 2 : &tpmnv_control_image->active_bit,
245 : : sizeof(tpmnv_control_image->active_bit),
246 : : offsetof(struct tpmnv_control, active_bit));
247 : 2 : out:
248 : :
249 : 2 : return rc;
250 : : }
251 : :
252 : 2 : static int secboot_tpm_write_bank(struct list_head *bank, int section)
253 : : {
254 : : int rc;
255 : :
256 : 2 : switch (section) {
257 : 2 : case SECVAR_VARIABLE_BANK:
258 : 2 : rc = secboot_tpm_write_variable_bank(bank);
259 : 2 : break;
260 : 0 : case SECVAR_UPDATE_BANK:
261 : 0 : memset(secboot_image->update, 0, SECBOOT_UPDATE_BANK_SIZE);
262 : 0 : rc = secboot_serialize_bank(bank, secboot_image->update,
263 : : SECBOOT_UPDATE_BANK_SIZE, 0);
264 : 0 : if (rc)
265 : 0 : break;
266 : :
267 : 0 : rc = flash_secboot_write(0, secboot_image,
268 : : sizeof(struct secboot));
269 : 0 : break;
270 : 0 : default:
271 : 0 : rc = OPAL_HARDWARE;
272 : : }
273 : :
274 : 2 : return rc;
275 : : }
276 : :
277 : :
278 : : /*
279 : : * Deserialize a single secvar from a buffer.
280 : : * Returns an advanced pointer, and an allocated secvar in *var.
281 : : * Returns NULL if out of bounds reached, or out of memory.
282 : : */
283 : 8 : static int secboot_deserialize_secvar(struct secvar **var, char **src, const char *end)
284 : : {
285 : : uint64_t key_len;
286 : : uint64_t data_size;
287 : : struct secvar *ret;
288 : :
289 : 8 : assert(var);
290 : :
291 : : /* Load in the two header values */
292 : 8 : key_len = be64_to_cpu(*((uint64_t *) *src));
293 : 8 : *src += sizeof(uint64_t);
294 : 8 : data_size = be64_to_cpu(*((uint64_t *) *src));
295 : 8 : *src += sizeof(uint64_t);
296 : :
297 : : /* Check if we've reached the last var to deserialize */
298 : 8 : if ((key_len == 0) && (data_size == 0)) {
299 : 4 : return OPAL_EMPTY;
300 : : }
301 : :
302 : 4 : if (key_len > SECVAR_MAX_KEY_LEN) {
303 : 0 : prlog(PR_ERR, "Deserialization failed: key length exceeded maximum value"
304 : : "%llu > %u", key_len, SECVAR_MAX_KEY_LEN);
305 : 0 : return OPAL_RESOURCE;
306 : : }
307 : 4 : if (data_size > SECBOOT_TPM_MAX_VAR_SIZE) {
308 : 0 : prlog(PR_ERR, "Deserialization failed: data size exceeded maximum value"
309 : : "%llu > %u", key_len, SECBOOT_TPM_MAX_VAR_SIZE);
310 : 0 : return OPAL_RESOURCE;
311 : : }
312 : :
313 : : /* Make sure these fields aren't oversized... */
314 : 4 : if ((*src + key_len + data_size) > end) {
315 : 0 : *var = NULL;
316 : 0 : prlog(PR_ERR, "key_len or data_size exceeded the expected bounds");
317 : 0 : return OPAL_RESOURCE;
318 : : }
319 : :
320 : 4 : ret = alloc_secvar(key_len, data_size);
321 : 4 : if (!ret) {
322 : 0 : *var = NULL;
323 : 0 : prlog(PR_ERR, "Out of memory, could not allocate new secvar");
324 : 0 : return OPAL_NO_MEM;
325 : : }
326 : :
327 : : /* Load in variable-sized data */
328 : 4 : memcpy(ret->key, *src, ret->key_len);
329 : 4 : *src += ret->key_len;
330 : 4 : memcpy(ret->data, *src, ret->data_size);
331 : 4 : *src += ret->data_size;
332 : :
333 : 4 : *var = ret;
334 : :
335 : 4 : return OPAL_SUCCESS;
336 : : }
337 : :
338 : :
339 : : /* Load variables from a flattened buffer into a bank list */
340 : 4 : static int secboot_tpm_deserialize_from_buffer(struct list_head *bank, char *src,
341 : : uint64_t size, uint64_t flags)
342 : : {
343 : : struct secvar *var;
344 : : char *cur;
345 : : char *end;
346 : 4 : int rc = 0;
347 : :
348 : 4 : cur = src;
349 : 4 : end = src + size;
350 : :
351 : 8 : while (cur < end) {
352 : : /* Ensure there is enough space to even check for another var header */
353 : 8 : if ((end - cur) < (sizeof(uint64_t) * 2))
354 : 0 : break;
355 : :
356 : 8 : rc = secboot_deserialize_secvar(&var, &cur, end);
357 : 8 : switch (rc) {
358 : 0 : case OPAL_RESOURCE:
359 : : case OPAL_NO_MEM:
360 : 0 : goto fail;
361 : 4 : case OPAL_EMPTY:
362 : 4 : goto done;
363 : 4 : default: assert(1);
364 : : }
365 : :
366 : 4 : var->flags |= flags;
367 : :
368 : 4 : list_add_tail(bank, &var->link);
369 : : }
370 : 0 : done:
371 : 4 : return OPAL_SUCCESS;
372 : 0 : fail:
373 : 0 : clear_bank_list(bank);
374 : 0 : return rc;
375 : : }
376 : :
377 : :
378 : : /* Helper to validate the current active SECBOOT bank's data against the hash stored in the TPM */
379 : 0 : static int compare_bank_hash(void)
380 : : {
381 : : char bank_hash[SHA256_DIGEST_LENGTH];
382 : 0 : uint64_t bit = tpmnv_control_image->active_bit;
383 : : int rc;
384 : :
385 : : /* Check the hash of the bank we loaded from PNOR
386 : : * versus the expected hash in TPM NV */
387 : 0 : rc = calc_bank_hash(bank_hash,
388 : 0 : secboot_image->bank[bit],
389 : : SECBOOT_VARIABLE_BANK_SIZE);
390 : 0 : if (rc)
391 : 0 : return rc;
392 : :
393 : 0 : if (memcmp(bank_hash,
394 : 0 : tpmnv_control_image->bank_hash[bit],
395 : : SHA256_DIGEST_LENGTH))
396 : : /* Tampered pnor space detected, abandon ship */
397 : 0 : return OPAL_PERMISSION;
398 : :
399 : 0 : return OPAL_SUCCESS;
400 : : }
401 : :
402 : :
403 : 2 : static int secboot_tpm_load_variable_bank(struct list_head *bank)
404 : : {
405 : 2 : uint64_t bit = tpmnv_control_image->active_bit;
406 : : int rc;
407 : :
408 : 2 : rc = secboot_tpm_deserialize_from_buffer(bank, tpmnv_vars_image->vars, tpmnv_vars_size, SECVAR_FLAG_PROTECTED);
409 : 2 : if (rc)
410 : 0 : return rc;
411 : :
412 : 2 : return secboot_tpm_deserialize_from_buffer(bank, secboot_image->bank[bit], SECBOOT_VARIABLE_BANK_SIZE, 0);
413 : : }
414 : :
415 : :
416 : 2 : static int secboot_tpm_load_bank(struct list_head *bank, int section)
417 : : {
418 : 2 : switch (section) {
419 : 2 : case SECVAR_VARIABLE_BANK:
420 : 2 : return secboot_tpm_load_variable_bank(bank);
421 : 0 : case SECVAR_UPDATE_BANK:
422 : 0 : return secboot_tpm_deserialize_from_buffer(bank, secboot_image->update, SECBOOT_UPDATE_BANK_SIZE, 0);
423 : : }
424 : :
425 : 0 : return OPAL_HARDWARE;
426 : : }
427 : :
428 : 0 : static int secboot_tpm_get_tpmnv_names(char *nv_vars_name, char *nv_control_name)
429 : : {
430 : : TPMS_NV_PUBLIC nv_public; /* Throwaway, we only want the name field */
431 : : TPM2B_NAME vars_tmp;
432 : : TPM2B_NAME control_tmp;
433 : : int rc;
434 : :
435 : 0 : rc = tpmnv_ops.readpublic(SECBOOT_TPMNV_VARS_INDEX,
436 : : &nv_public,
437 : : &vars_tmp);
438 : 0 : if (rc) {
439 : 0 : prlog(PR_ERR, "Failed to readpublic from the VARS index, rc=%d\n", rc);
440 : 0 : return rc;
441 : : }
442 : 0 : rc = tpmnv_ops.readpublic(SECBOOT_TPMNV_CONTROL_INDEX,
443 : : &nv_public,
444 : : &control_tmp);
445 : 0 : if (rc) {
446 : 0 : prlog(PR_ERR, "Failed to readpublic from the CONTROL index, rc=%d\n", rc);
447 : 0 : return rc;
448 : : }
449 : :
450 : 0 : memcpy(nv_vars_name, vars_tmp.t.name, MIN(sizeof(tpmnv_vars_name), vars_tmp.t.size));
451 : 0 : memcpy(nv_control_name, control_tmp.t.name, MIN(sizeof(tpmnv_control_name), control_tmp.t.size));
452 : :
453 : 0 : return OPAL_SUCCESS;
454 : : }
455 : :
456 : :
457 : : /* Ensure the NV indices were defined with the correct set of attributes */
458 : 0 : static int secboot_tpm_check_tpmnv_attrs(char *nv_vars_name, char *nv_control_name)
459 : : {
460 : 0 : if (memcmp(tpmnv_vars_name,
461 : : nv_vars_name,
462 : : sizeof(tpmnv_vars_name))) {
463 : 0 : prlog(PR_ERR, "VARS index not defined with the correct attributes\n");
464 : 0 : return OPAL_RESOURCE;
465 : : }
466 : 0 : if (memcmp(tpmnv_control_name,
467 : : nv_control_name,
468 : : sizeof(tpmnv_control_name))) {
469 : 0 : prlog(PR_ERR, "CONTROL index not defined with the correct attributes\n");
470 : 0 : return OPAL_RESOURCE;
471 : : }
472 : :
473 : 0 : return OPAL_SUCCESS;
474 : : }
475 : :
476 : 0 : static bool secboot_tpm_check_provisioned_indices(char *nv_vars_name, char *nv_control_name)
477 : : {
478 : : /* Check for provisioned NV indices, redefine them if detected. */
479 : 0 : if (!memcmp(tpmnv_vars_prov_name,
480 : : nv_vars_name,
481 : 0 : sizeof(tpmnv_vars_prov_name)) &&
482 : 0 : !memcmp(tpmnv_control_prov_name,
483 : : nv_control_name,
484 : : sizeof(tpmnv_control_prov_name))) {
485 : 0 : return true;
486 : : }
487 : :
488 : : /*
489 : : * If one matches but the other doesn't, do NOT redefine.
490 : : * The next step should detect they don't match the expected values
491 : : * and fail the boot.
492 : : */
493 : 0 : return false;
494 : : }
495 : :
496 : 1 : static int secboot_tpm_define_indices(void)
497 : : {
498 : 1 : int rc = OPAL_SUCCESS;
499 : :
500 : 1 : rc = tpmnv_ops.definespace(SECBOOT_TPMNV_VARS_INDEX, tpmnv_vars_size);
501 : 1 : if (rc) {
502 : 0 : prlog(PR_ERR, "Failed to define the VARS index, rc=%d\n", rc);
503 : 0 : return rc;
504 : : }
505 : :
506 : 1 : rc = tpmnv_ops.definespace(SECBOOT_TPMNV_CONTROL_INDEX, sizeof(struct tpmnv_control));
507 : 1 : if (rc) {
508 : 0 : prlog(PR_ERR, "Failed to define the CONTROL index, rc=%d\n", rc);
509 : 0 : return rc;
510 : : }
511 : :
512 : 1 : rc = tpmnv_format();
513 : 1 : if (rc)
514 : 0 : return rc;
515 : :
516 : : /* TPM NV just got redefined, so unconditionally format the SECBOOT partition */
517 : 1 : return secboot_format();
518 : : }
519 : :
520 : 0 : static int secboot_tpm_undefine_indices(bool *vars_defined, bool *control_defined)
521 : : {
522 : : int rc;
523 : :
524 : 0 : if (vars_defined) {
525 : 0 : rc = tpmnv_ops.undefinespace(SECBOOT_TPMNV_VARS_INDEX);
526 : 0 : if (rc) {
527 : 0 : prlog(PR_ERR, "Failed to undefine VARS, something is seriously wrong\n");
528 : 0 : return rc;
529 : : }
530 : : }
531 : :
532 : 0 : if (control_defined) {
533 : 0 : rc = tpmnv_ops.undefinespace(SECBOOT_TPMNV_CONTROL_INDEX);
534 : 0 : if (rc) {
535 : 0 : prlog(PR_ERR, "Failed to undefine CONTROL, something is seriously wrong\n");
536 : 0 : return rc;
537 : : }
538 : : }
539 : :
540 : 0 : *vars_defined = *control_defined = false;
541 : :
542 : 0 : return OPAL_SUCCESS;
543 : : }
544 : :
545 : :
546 : 1 : static int secboot_tpm_store_init(void)
547 : : {
548 : : int rc;
549 : : unsigned int secboot_size;
550 : :
551 : 1 : TPMI_RH_NV_INDEX *indices = NULL;
552 : : char nv_vars_name[sizeof(tpmnv_vars_name)];
553 : : char nv_control_name[sizeof(tpmnv_control_name)];
554 : 1 : size_t count = 0;
555 : 1 : bool control_defined = false;
556 : 1 : bool vars_defined = false;
557 : : int i;
558 : :
559 : 1 : if (secboot_image)
560 : 0 : return OPAL_SUCCESS;
561 : :
562 : 1 : prlog(PR_DEBUG, "Initializing for pnor+tpm based platform\n");
563 : :
564 : : /* Initialize SECBOOT first, we may need to format this later */
565 : 1 : rc = flash_secboot_info(&secboot_size);
566 : 1 : if (rc) {
567 : 0 : prlog(PR_ERR, "error %d retrieving keystore info\n", rc);
568 : 0 : goto error;
569 : : }
570 : 1 : if (sizeof(struct secboot) > secboot_size) {
571 : 0 : prlog(PR_ERR, "secboot partition %d KB too small. min=%ld\n",
572 : : secboot_size >> 10, sizeof(struct secboot));
573 : 0 : rc = OPAL_RESOURCE;
574 : 0 : goto error;
575 : : }
576 : :
577 : 1 : secboot_image = memalign(0x1000, sizeof(struct secboot));
578 : 1 : if (!secboot_image) {
579 : 0 : prlog(PR_ERR, "Failed to allocate space for the secboot image\n");
580 : 0 : rc = OPAL_NO_MEM;
581 : 0 : goto error;
582 : : }
583 : :
584 : : /* Read in the PNOR data, bank hash is checked on call to .load_bank() */
585 : 1 : rc = flash_secboot_read(secboot_image, 0, sizeof(struct secboot));
586 : 1 : if (rc) {
587 : 0 : prlog(PR_ERR, "failed to read the secboot partition, rc=%d\n", rc);
588 : 0 : goto error;
589 : : }
590 : :
591 : : /* Allocate the tpmnv data buffers */
592 : 1 : tpmnv_vars_image = zalloc(tpmnv_vars_size);
593 : 1 : if (!tpmnv_vars_image)
594 : 0 : return OPAL_NO_MEM;
595 : 1 : tpmnv_control_image = zalloc(sizeof(struct tpmnv_control));
596 : 1 : if (!tpmnv_control_image)
597 : 0 : return OPAL_NO_MEM;
598 : :
599 : : /* Check if the NV indices have been defined already */
600 : 1 : rc = tpmnv_ops.getindices(&indices, &count);
601 : 1 : if (rc) {
602 : 0 : prlog(PR_ERR, "Could not load defined indicies from TPM, rc=%d\n", rc);
603 : 0 : goto error;
604 : : }
605 : :
606 : 1 : for (i = 0; i < count; i++) {
607 : 0 : if (indices[i] == SECBOOT_TPMNV_VARS_INDEX)
608 : 0 : vars_defined = true;
609 : 0 : else if (indices[i] == SECBOOT_TPMNV_CONTROL_INDEX)
610 : 0 : control_defined = true;
611 : : }
612 : 1 : free(indices);
613 : :
614 : : /* Undefine the NV indices if physical presence has been asserted */
615 : 1 : if (secvar_check_physical_presence()) {
616 : 0 : prlog(PR_INFO, "Physical presence asserted, redefining NV indices, and resetting keystore\n");
617 : 0 : rc = secboot_tpm_undefine_indices(&vars_defined, &control_defined);
618 : 0 : if (rc)
619 : 0 : goto error;
620 : :
621 : 0 : rc = secboot_tpm_define_indices();
622 : 0 : if (rc)
623 : 0 : goto error;
624 : :
625 : : /* Indices got defined and formatted, we're done here */
626 : 0 : goto done;
627 : : }
628 : : /* Determine if we need to define the indices. These should BOTH be false or true */
629 : 1 : if (!vars_defined && !control_defined) {
630 : 1 : rc = secboot_tpm_define_indices();
631 : 1 : if (rc)
632 : 0 : goto error;
633 : :
634 : : /* Indices got defined and formatted, we're done here */
635 : 1 : goto done;
636 : : }
637 : 0 : if (vars_defined ^ control_defined) {
638 : : /* This should never happen. Both indices should be defined at the same
639 : : * time. Otherwise something seriously went wrong. */
640 : 0 : prlog(PR_ERR, "NV indices defined with unexpected attributes. Assert physical presence to clear\n");
641 : 0 : goto error;
642 : : }
643 : :
644 : : /* Both indices are defined, now need to validate their contents */
645 : :
646 : 0 : rc = secboot_tpm_get_tpmnv_names(nv_vars_name, nv_control_name);
647 : 0 : if (rc)
648 : 0 : goto error;
649 : :
650 : : /* Check for provisioned TPMNV indices, redefine them if detected */
651 : 0 : if (secboot_tpm_check_provisioned_indices(nv_vars_name, nv_control_name)) {
652 : 0 : prlog(PR_INFO, "Provisioned TPM NV indices detected, redefining NV indices, and resetting keystore\n");
653 : 0 : rc = secboot_tpm_undefine_indices(&vars_defined, &control_defined);
654 : 0 : if (rc)
655 : 0 : goto error;
656 : :
657 : 0 : rc = secboot_tpm_define_indices();
658 : 0 : if (rc)
659 : 0 : goto error;
660 : :
661 : : /* Indices got defined and formatted, we're done here */
662 : 0 : goto done;
663 : : }
664 : :
665 : : /* Otherwise, ensure the NV indices were defined with the correct set of attributes */
666 : 0 : rc = secboot_tpm_check_tpmnv_attrs(nv_vars_name, nv_control_name);
667 : 0 : if (rc)
668 : 0 : goto error;
669 : :
670 : :
671 : : /* TPMNV indices exist, are correct, and weren't just formatted, so read them in */
672 : 0 : rc = tpmnv_ops.read(SECBOOT_TPMNV_VARS_INDEX,
673 : : tpmnv_vars_image,
674 : : tpmnv_vars_size, 0);
675 : 0 : if (rc) {
676 : 0 : prlog(PR_ERR, "Failed to read from the VARS index\n");
677 : 0 : goto error;
678 : : }
679 : :
680 : 0 : rc = tpmnv_ops.read(SECBOOT_TPMNV_CONTROL_INDEX,
681 : : tpmnv_control_image,
682 : : sizeof(struct tpmnv_control), 0);
683 : 0 : if (rc) {
684 : 0 : prlog(PR_ERR, "Failed to read from the CONTROL index\n");
685 : 0 : goto error;
686 : : }
687 : :
688 : : /* Verify the header information is correct */
689 : 0 : if (tpmnv_vars_image->header.magic_number != SECBOOT_MAGIC_NUMBER ||
690 : 0 : tpmnv_control_image->header.magic_number != SECBOOT_MAGIC_NUMBER ||
691 : 0 : tpmnv_vars_image->header.version != SECBOOT_VERSION ||
692 : 0 : tpmnv_control_image->header.version != SECBOOT_VERSION) {
693 : 0 : prlog(PR_ERR, "TPMNV indices defined, but contain bad data. Assert physical presence to clear\n");
694 : 0 : goto error;
695 : : }
696 : :
697 : : /* Verify the secboot partition header information,
698 : : * reformat if incorrect
699 : : * Note: Future variants should attempt to handle older versions safely
700 : : */
701 : 0 : if (secboot_image->header.magic_number != SECBOOT_MAGIC_NUMBER ||
702 : 0 : secboot_image->header.version != SECBOOT_VERSION) {
703 : 0 : rc = secboot_format();
704 : 0 : if (rc)
705 : 0 : goto error;
706 : 0 : goto done;
707 : : }
708 : :
709 : : /* Verify the active bank's integrity by comparing against the hash in TPM.
710 : : * Reformat if it does not match -- we do not want to load potentially
711 : : * compromised data.
712 : : * Ideally, the backend driver should retain secure boot state in
713 : : * protected (TPM) storage, so secure boot state should be the same, albeit
714 : : * without the data in unprotected (PNOR) storage.
715 : : */
716 : 0 : rc = compare_bank_hash();
717 : 0 : if (rc == OPAL_PERMISSION) {
718 : 0 : rc = secboot_format();
719 : 0 : if (rc)
720 : 0 : goto error;
721 : : }
722 : 0 : else if (rc)
723 : 0 : goto error;
724 : :
725 : 0 : done:
726 : 1 : return OPAL_SUCCESS;
727 : :
728 : 0 : error:
729 : 0 : free(secboot_image);
730 : 0 : secboot_image = NULL;
731 : 0 : free(tpmnv_vars_image);
732 : 0 : tpmnv_vars_image = NULL;
733 : 0 : free(tpmnv_control_image);
734 : 0 : tpmnv_control_image = NULL;
735 : :
736 : 0 : return rc;
737 : : }
738 : :
739 : :
740 : 0 : static void secboot_tpm_lockdown(void)
741 : : {
742 : : /* Note: While write lock is called here on the two NV indices,
743 : : * both indices are also defined on the platform hierarchy.
744 : : * The platform hierarchy auth is set later in the skiboot
745 : : * initialization process, and not by any secvar-related code.
746 : : */
747 : : int rc;
748 : :
749 : 0 : rc = tpmnv_ops.writelock(SECBOOT_TPMNV_VARS_INDEX);
750 : 0 : if (rc) {
751 : 0 : prlog(PR_EMERG, "TSS Write Lock failed on VARS index, halting.\n");
752 : 0 : abort();
753 : : }
754 : :
755 : 0 : rc = tpmnv_ops.writelock(SECBOOT_TPMNV_CONTROL_INDEX);
756 : 0 : if (rc) {
757 : 0 : prlog(PR_EMERG, "TSS Write Lock failed on CONTROL index, halting.\n");
758 : 0 : abort();
759 : : }
760 : 0 : }
761 : :
762 : : struct secvar_storage_driver secboot_tpm_driver = {
763 : : .load_bank = secboot_tpm_load_bank,
764 : : .write_bank = secboot_tpm_write_bank,
765 : : .store_init = secboot_tpm_store_init,
766 : : .lockdown = secboot_tpm_lockdown,
767 : : .max_var_size = SECBOOT_TPM_MAX_VAR_SIZE,
768 : : };
|