blob: a1167ca2de74fb867b8ba01d767e133e23740ff5 [file] [log] [blame]
Sergii Dmytruk04bd9652023-11-17 19:31:20 +02001/* SPDX-License-Identifier: GPL-2.0-or-later */
2
3#include "vs.h"
4
5#include <limits.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9
10#include "udk2017.h"
11#include "utils.h"
12
13static size_t get_var_hdr_size(bool auth_vars)
14{
15 if (auth_vars)
16 return sizeof(AUTHENTICATED_VARIABLE_HEADER);
17 return sizeof(VARIABLE_HEADER);
18}
19
20struct var_store_t vs_load(struct mem_range_t vs_data, bool auth_vars)
21{
22 uint8_t *var_hdr = vs_data.start;
23
24 struct var_store_t vs = {
25 .auth_vars = auth_vars,
26 .vars = NULL,
27 };
28
29 struct var_t *last_var = NULL;
30
31 const size_t var_hdr_size = get_var_hdr_size(auth_vars);
32 while (var_hdr + var_hdr_size < vs_data.start + vs_data.length) {
33 uint16_t start_id;
34 uint8_t state;
35 struct var_t var = {0};
36 uint8_t *var_data = var_hdr;
37
38 if (auth_vars) {
39 const AUTHENTICATED_VARIABLE_HEADER *auth_hdr =
40 (void *)var_data;
41
42 start_id = auth_hdr->StartId;
43 state = auth_hdr->State;
44
45 var.reserved = auth_hdr->Reserved;
46 var.attrs = auth_hdr->Attributes;
47 var.name_size = auth_hdr->NameSize;
48 var.data_size = auth_hdr->DataSize;
49 var.guid = auth_hdr->VendorGuid;
50 } else {
51 const VARIABLE_HEADER *no_auth_hdr = (void *)var_data;
52
53 start_id = no_auth_hdr->StartId;
54 state = no_auth_hdr->State;
55
56 var.reserved = no_auth_hdr->Reserved;
57 var.attrs = no_auth_hdr->Attributes;
58 var.name_size = no_auth_hdr->NameSize;
59 var.data_size = no_auth_hdr->DataSize;
60 var.guid = no_auth_hdr->VendorGuid;
61 }
62
63 var_hdr += HEADER_ALIGN(var_hdr_size +
64 var.name_size +
65 var.data_size);
66
67 if (start_id != VARIABLE_DATA)
68 break;
69
70 if (state != VAR_ADDED)
71 continue;
72
73 if (var.data_size == UINT32_MAX ||
74 var.name_size == UINT32_MAX ||
75 var.attrs == UINT32_MAX)
76 continue;
77
78 CHAR16 *name = (void *)(var_data + var_hdr_size);
79 var.name = xmalloc(var.name_size);
80 memcpy(var.name, name, var.name_size);
81
82 uint8_t *data =
83 (void *)(var_data + var_hdr_size + var.name_size);
84 var.data = xmalloc(var.data_size);
85 memcpy(var.data, data, var.data_size);
86
87 struct var_t *var_node = xmalloc(sizeof(*var_node));
88 *var_node = var;
89 if (last_var != NULL)
90 last_var->next = var_node;
91 else if (vs.vars == NULL)
92 vs.vars = var_node;
93 last_var = var_node;
94 }
95
96 return vs;
97}
98
99static void store_var(const struct var_t *var, bool auth_vars, uint8_t *data)
100{
101 if (auth_vars) {
102 AUTHENTICATED_VARIABLE_HEADER hdr;
103 memset(&hdr, 0xff, sizeof(hdr));
104
105 hdr.StartId = VARIABLE_DATA;
106 hdr.State = VAR_ADDED;
107 hdr.Reserved = var->reserved;
108 hdr.Attributes = var->attrs;
109 hdr.VendorGuid = var->guid;
110 hdr.NameSize = var->name_size;
111 hdr.DataSize = var->data_size;
112
113 memcpy(data, &hdr, sizeof(hdr));
114 data += sizeof(hdr);
115 } else {
116 VARIABLE_HEADER hdr;
117 memset(&hdr, 0xff, sizeof(hdr));
118
119 hdr.StartId = VARIABLE_DATA;
120 hdr.State = VAR_ADDED;
121 hdr.Reserved = var->reserved;
122 hdr.Attributes = var->attrs;
123 hdr.VendorGuid = var->guid;
124 hdr.NameSize = var->name_size;
125 hdr.DataSize = var->data_size;
126
127 memcpy(data, &hdr, sizeof(hdr));
128 data += sizeof(hdr);
129 }
130
131 memcpy(data, var->name, var->name_size);
132 memcpy(data + var->name_size, var->data, var->data_size);
133}
134
135bool vs_store(struct var_store_t *vs, struct mem_range_t vs_data)
136{
137 uint8_t *out_data = vs_data.start;
138
139 const size_t var_hdr_size = get_var_hdr_size(vs->auth_vars);
140 for (struct var_t *var = vs->vars; var != NULL; var = var->next) {
141 const size_t var_size =
142 var_hdr_size + var->name_size + var->data_size;
143 if (out_data + var_size > vs_data.start + vs_data.length) {
144 fprintf(stderr,
145 "Not enough space to serialize Variable Store.\n");
146 return false;
147 }
148
149 store_var(var, vs->auth_vars, out_data);
150 out_data += HEADER_ALIGN(var_size);
151 }
152
153 // The rest is "uninitialized".
154 memset(out_data, 0xff, vs_data.length - (out_data - vs_data.start));
155
156 return true;
157}
158
159struct var_t *vs_new_var(struct var_store_t *vs)
160{
161 struct var_t *new_var = xmalloc(sizeof(*new_var));
162
163 memset(new_var, 0, sizeof(*new_var));
164 new_var->attrs = EFI_VARIABLE_NON_VOLATILE
165 | EFI_VARIABLE_BOOTSERVICE_ACCESS
166 | EFI_VARIABLE_RUNTIME_ACCESS;
167
168 struct var_t *var = vs->vars;
169 if (var == NULL) {
170 vs->vars = new_var;
171 } else {
172 while (var->next != NULL)
173 var = var->next;
174 var->next = new_var;
175 }
176
177 return new_var;
178}
179
180struct var_t *vs_find(struct var_store_t *vs,
181 const char name[],
182 const EFI_GUID *guid)
183{
184 size_t name_size;
185 CHAR16 *uchar_name = to_uchars(name, &name_size);
186
187 struct var_t *var;
188 for (var = vs->vars; var != NULL; var = var->next) {
189 if (var->name_size != name_size)
190 continue;
191 if (memcmp(var->name, uchar_name, name_size) != 0)
192 continue;
193 if (memcmp(&var->guid, guid, sizeof(*guid)) != 0)
194 continue;
195 break;
196 }
197
198 free(uchar_name);
199 return var;
200}
201
202static void free_var(struct var_t *var)
203{
204 free(var->name);
205 free(var->data);
206 free(var);
207}
208
209void vs_delete(struct var_store_t *vs, struct var_t *var)
210{
211 if (vs->vars == var) {
212 vs->vars = var->next;
213 free_var(var);
214 return;
215 }
216
217 for (struct var_t *v = vs->vars; v != NULL; v = v->next) {
218 if (v->next == var) {
219 v->next = var->next;
220 free_var(var);
221 return;
222 }
223 }
224}
225
226void vs_free(struct var_store_t *vs)
227{
228 for (struct var_t *next, *var = vs->vars; var != NULL; var = next) {
229 next = var->next;
230 free_var(var);
231 }
232}