-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathsecvarctl.c
More file actions
256 lines (227 loc) · 6.97 KB
/
secvarctl.c
File metadata and controls
256 lines (227 loc) · 6.97 KB
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright 2022-2023 IBM Corp.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "prlog.h"
#include "secvarctl.h"
#ifdef SECVAR_HOST_BACKEND
#include "host_svc_backend.h"
#endif
#ifdef SECVAR_GUEST_BACKEND
#include "guest_svc_backend.h"
#endif
int verbose = PR_WARNING;
enum backends {
#ifdef SECVAR_HOST_BACKEND
BACKEND_HOST,
#endif
#ifdef SECVAR_GUEST_BACKEND
BACKEND_GUEST,
#endif
BACKEND_UNKNOWN,
};
// Lookup table for string -> backend enum, allows for aliasing backend names to use format or shortname
static struct {
char name[32];
enum backends backend;
} backend_names[] = {
#ifdef SECVAR_HOST_BACKEND
{ .name = "host", .backend = BACKEND_HOST },
{ .name = HOST_BACKEND_FORMAT, .backend = BACKEND_HOST },
#endif
#ifdef SECVAR_GUEST_BACKEND
{ .name = "guest", .backend = BACKEND_GUEST },
{ .name = GUEST_BACKEND_FORMAT, .backend = BACKEND_GUEST },
#endif
};
// Backend command table
static struct backend backends[] = {
#ifdef SECVAR_HOST_BACKEND
[BACKEND_HOST] = { .format = HOST_BACKEND_FORMAT,
.countCmds = sizeof(edk2_compat_command_table) / sizeof(struct command),
.commands = edk2_compat_command_table },
#endif
#ifdef SECVAR_GUEST_BACKEND
[BACKEND_GUEST] = { .format = GUEST_BACKEND_FORMAT,
.countCmds = sizeof(guest_command_table) / sizeof(struct command),
.commands = guest_command_table },
#endif
};
void enabled_backends()
{
printf("Enabled backends:\n");
for (enum backends back = 0; back < BACKEND_UNKNOWN; back++) {
printf(" - %s\n", backends[back].format);
}
}
void version()
{
printf("secvarctl v" SECVARCTL_VERSION "\n");
}
void usage()
{
version();
printf("\nUSAGE: \n\t$ secvarctl [MODE] [COMMAND]\n"
"MODEs:\n"
"-m, --mode\tsupports both the Guest and Host secure boot variables "
"in two different modes\n"
"\t\tand either -m host or -m guest are acceptable values.\n"
"COMMANDs:\n"
"\t--help/--usage\n\t"
"read\t\tprints info on secure variables,\n\t\t\t"
"use 'secvarctl [MODE] read --usage/help' for more information\n\t"
"write\t\tupdates secure variable with new auth,\n\t\t\t"
"use 'secvarctl [MODE] write --usage/help' for more information"
"\n\tvalidate\tvalidates format of given esl/cert/auth,\n\t\t\t"
"use 'secvarctl [MODE] validate --usage/help' for more "
"information\n\t"
"verify\t\tcompares proposed variable to the current "
"variables,\n\t\t\t"
"use 'secvarctl [MODE] verify --usage/help' for more information\n"
"\tgenerate\tcreates relevant files for secure variable "
"management,\n\t\t\t"
"use 'secvarctl [MODE] generate --usage/help' for more information\n"
"\n");
enabled_backends();
}
void help()
{
printf("\nHELP:\n\t"
"A command line tool for simplifying the reading and writing of "
"secure boot variables.\n\t"
"Commands are:\n\t\t"
"read - print out information on their current secure vaiables\n\t\t"
"write - update the given variable's key value, committed upon "
"reboot\n\t\t"
"validate - checks format requirements are met for the given file "
"type\n\t\t"
"verify - checks that the given files are correctly signed by the "
"current variables\n"
"\t\tgenerate - create files that are relevant to the secure "
"variable management process\n");
usage();
}
int is_known_backend(const char *buff, struct backend **backend)
{
int i = 0;
int total_backend = sizeof(backends) / sizeof(struct backend);
/* loop through all known backends */
for (i = 0; i < total_backend; i++) {
if (!strncmp(buff, backends[i].format, strlen(backends[i].format))) {
prlog(PR_NOTICE, "found backend %s\n", backends[i].format);
*backend = &backends[i];
return i; // enum in the command table -> which backend
}
}
return BACKEND_UNKNOWN;
}
/*
* Checks what backend the platform is running, CURRENTLY ONLY KNOWS EDK2
* @return type of backend, or NULL if file could not be found or contained wrong contents,
*/
static struct backend *get_backend()
{
char *buff = NULL, *secvar_format_location = "/sys/firmware/secvar/format";
size_t buffSize = 0, max_buff_size = 0;
struct backend *result = NULL;
int i = 0;
/* if file doesnt exist then print warning and keep going */
if (is_file(secvar_format_location)) {
prlog(PR_WARNING, "WARNING!! platform does not support secure variables\n");
return result;
}
/* get max size of backend name */
max_buff_size = strlen(backends[0].format);
for (i = 0; i < sizeof(backends) / sizeof(struct backend); i++) {
if (strlen(backends[i].format) > max_buff_size)
max_buff_size = strlen(backends[i].format);
}
// Contents of format file should be a string
buff = (char *)get_data_from_file(secvar_format_location, max_buff_size, &buffSize);
if (buff == NULL) {
prlog(PR_WARNING,
"WARNING!! could not extract data from %s , "
"assuming platform does not support secure variables\n",
secvar_format_location);
} else if (!is_known_backend(buff, &result))
prlog(PR_WARNING, "WARNING!! %s does not contain known backend format.\n",
secvar_format_location);
if (buff != NULL)
free(buff);
return result;
}
int main(int argc, char *argv[])
{
int rc, i;
char *subcommand = NULL;
struct backend *backend = NULL;
if (argc < 2) {
usage();
return ARG_PARSE_FAIL;
}
argv++;
argc--;
for (; argc > 0 && *argv[0] == '-'; argc--, argv++) {
if (!strcmp("--usage", *argv)) {
usage();
return SUCCESS;
} else if (!strcmp("--help", *argv) || !strcmp("-h", *argv)) {
help();
return SUCCESS;
} else if (!strcmp("--version", *argv)) {
version();
return SUCCESS;
} else if (!strcmp("-m", *argv) || !strcmp("--mode", *argv)) {
argv++;
argc--;
if (*argv == NULL) {
enabled_backends();
return SUCCESS;
}
for (i = 0; i < sizeof(backend_names) / sizeof(backend_names[0]); i++) {
if (!strcmp(*argv, backend_names[i].name)) {
backend = &backends[backend_names[i].backend];
break;
}
}
if (!backend) {
prlog(PR_WARNING, "Backend '%s' not supported or enabled\n", *argv);
return UNKNOWN_COMMAND;
}
} else if (!strcmp("-v", *argv) || !strcmp("--verbose", *argv))
verbose = PR_DEBUG;
else {
usage();
return SUCCESS;
}
}
if (argc <= 0) {
prlog(PR_ERR, "\nERROR: commands not found\n");
usage();
return ARG_PARSE_FAIL;
}
if (!backend)
backend = get_backend();
if (!backend) {
prlog(PR_WARNING,
"Backend cannot be determined by your system, use -m <backend> to specify.\n");
return UNKNOWN_COMMAND;
}
/* next command should be one of main subcommands */
subcommand = *argv;
rc = UNKNOWN_COMMAND;
for (i = 0; i < backend->countCmds; i++) {
if (!strncmp(subcommand, backend->commands[i].name, 32)) {
rc = backend->commands[i].func(argc, argv);
break;
}
}
if (rc == UNKNOWN_COMMAND) {
prlog(PR_ERR, "ERROR: unknown command %s\n", subcommand);
usage();
}
return rc;
}