File: secvar_main.c

package info (click to toggle)
qemu 1%3A7.2%2Bdfsg-7%2Bdeb12u13
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 288,192 kB
  • sloc: ansic: 2,701,923; pascal: 112,708; python: 62,697; sh: 50,281; asm: 48,732; makefile: 17,260; cpp: 9,441; perl: 8,084; xml: 2,911; objc: 1,870; php: 1,299; tcl: 1,188; yacc: 604; lex: 363; sql: 71; awk: 35; sed: 11; javascript: 7
file content (144 lines) | stat: -rw-r--r-- 3,832 bytes parent folder | download | duplicates (8)
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;
}