1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
/* Copyright 2019 IBM Corp. */
#ifndef pr_fmt
#define pr_fmt(fmt) "SECVAR: " fmt
#endif
#include <stdlib.h>
#include <skiboot.h>
#include <opal.h>
#include <libstb/secureboot.h>
#include "secvar.h"
#include "secvar_devtree.h"
struct list_head variable_bank;
struct list_head update_bank;
int secvar_enabled = 0; // Set to 1 if secvar is supported
int secvar_ready = 0; // Set to 1 when base secvar inits correctly
// To be filled in by platform.secvar_init
struct secvar_storage_driver secvar_storage = {0};
struct secvar_backend_driver secvar_backend = {0};
int secvar_main(struct secvar_storage_driver storage_driver,
struct secvar_backend_driver backend_driver)
{
int rc = OPAL_UNSUPPORTED;
prlog(PR_INFO, "Secure variables are supported, initializing secvar\n");
secvar_storage = storage_driver;
secvar_backend = backend_driver;
secvar_init_devnode(secvar_backend.compatible);
secvar_enabled = 1;
list_head_init(&variable_bank);
list_head_init(&update_bank);
/*
* Failures here should indicate some kind of hardware problem,
* therefore we don't even attempt to continue
*/
rc = secvar_storage.store_init();
if (rc)
secureboot_enforce();
rc = secvar_storage.load_bank(&variable_bank, SECVAR_VARIABLE_BANK);
if (rc)
goto fail;
rc = secvar_storage.load_bank(&update_bank, SECVAR_UPDATE_BANK);
if (rc)
goto fail;
/*
* At this point, base secvar is functional.
* In the event of some error, boot up to Petitboot in secure mode
* with an empty keyring, for an admin to attempt to debug.
*/
secvar_ready = 1;
secvar_set_status("okay");
if (secvar_backend.pre_process) {
rc = secvar_backend.pre_process(&variable_bank, &update_bank);
if (rc) {
prlog(PR_ERR, "Error in backend pre_process = %d\n", rc);
/* Early failure state, lock the storage */
secvar_storage.lockdown();
goto soft_fail;
}
}
// Process is required, error if it doesn't exist
if (!secvar_backend.process)
goto soft_fail;
/* Process variable updates from the update bank. */
rc = secvar_backend.process(&variable_bank, &update_bank);
/* Create and set the update-status device tree property */
secvar_set_update_status(rc);
/*
* Only write to the storage if we actually processed updates
* OPAL_EMPTY implies no updates were processed
* Refer to full table in doc/device-tree/ibm,opal/secvar.rst
*/
if (rc == OPAL_SUCCESS) {
rc = secvar_storage.write_bank(&variable_bank, SECVAR_VARIABLE_BANK);
if (rc)
goto soft_fail;
}
/*
* Write (and probably clear) the update bank if .process() actually detected
* and handled updates in the update bank. Unlike above, this includes error
* cases, where the backend should probably be clearing the bank.
*/
if (rc != OPAL_EMPTY) {
rc = secvar_storage.write_bank(&update_bank,
SECVAR_UPDATE_BANK);
if (rc)
goto soft_fail;
}
/* Unconditionally lock the storage at this point */
secvar_storage.lockdown();
if (secvar_backend.post_process) {
rc = secvar_backend.post_process(&variable_bank, &update_bank);
if (rc) {
prlog(PR_ERR, "Error in backend post_process = %d\n", rc);
goto soft_fail;
}
}
prlog(PR_INFO, "secvar initialized successfully\n");
return OPAL_SUCCESS;
fail:
/* Early failure, base secvar support failed to initialize */
secvar_set_status("fail");
secvar_storage.lockdown();
secvar_set_secure_mode();
prerror("secvar failed to initialize, rc = %04x\n", rc);
return rc;
soft_fail:
/*
* Soft-failure, enforce secure boot with an empty keyring in
* bootloader for debug/recovery
*/
clear_bank_list(&variable_bank);
clear_bank_list(&update_bank);
secvar_storage.lockdown();
secvar_set_secure_mode();
prerror("secvar failed to initialize, rc = %04x\n", rc);
return rc;
}
|