blob: 9bb3f91d79dc22d958fbca014634dd59fd7173dd [file] [log] [blame]
Brad Bishopbec4ebc2022-08-03 09:55:16 -04001From da3bd0721f2403562b6ae6d1939f5f331fd141bb Mon Sep 17 00:00:00 2001
2From: Gowtham Suresh Kumar <gowtham.sureshkumar@arm.com>
3Date: Wed, 15 Dec 2021 17:23:25 +0000
4Subject: [PATCH] Revert "Add uefi variable append write support"
5
6This reverts commit e8758d9aff0eddae81a74b0191cd027bcdc92c04.
7
8Upstream-Status: Pending [Not submitted to upstream yet]
9Signed-off-by: Gowtham Suresh Kumar <gowtham.sureshkumar@arm.com>
10
11
12---
13 .../backend/test/variable_index_tests.cpp | 90 +++---
14 .../backend/test/variable_store_tests.cpp | 72 +----
15 .../backend/uefi_variable_store.c | 293 ++++++------------
16 .../smm_variable/backend/variable_index.c | 95 ++++--
17 .../smm_variable/backend/variable_index.h | 58 ++--
18 .../backend/variable_index_iterator.c | 4 +-
19 .../backend/variable_index_iterator.h | 2 +-
20 .../service/smm_variable_service_tests.cpp | 48 ---
21 protocols/service/smm_variable/parameters.h | 3 -
22 9 files changed, 239 insertions(+), 426 deletions(-)
23
24diff --git a/components/service/smm_variable/backend/test/variable_index_tests.cpp b/components/service/smm_variable/backend/test/variable_index_tests.cpp
25index 8edc0e70..c8bacf97 100644
26--- a/components/service/smm_variable/backend/test/variable_index_tests.cpp
27+++ b/components/service/smm_variable/backend/test/variable_index_tests.cpp
28@@ -69,37 +69,34 @@ TEST_GROUP(UefiVariableIndexTests)
29
30 void create_variables()
31 {
32- struct variable_info *info = NULL;
33+ const struct variable_info *info = NULL;
34
35- info = variable_index_add_entry(
36+ info = variable_index_add_variable(
37 &m_variable_index,
38 &guid_1,
39 name_1.size() * sizeof(int16_t),
40- name_1.data());
41- CHECK_TRUE(info);
42- variable_index_set_variable(
43- info,
44+ name_1.data(),
45 EFI_VARIABLE_BOOTSERVICE_ACCESS);
46
47- info = variable_index_add_entry(
48+ CHECK_TRUE(info);
49+
50+ info = variable_index_add_variable(
51 &m_variable_index,
52 &guid_2,
53 name_2.size() * sizeof(int16_t),
54- name_2.data());
55- CHECK_TRUE(info);
56- variable_index_set_variable(
57- info,
58+ name_2.data(),
59 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS);
60
61- info = variable_index_add_entry(
62+ CHECK_TRUE(info);
63+
64+ info = variable_index_add_variable(
65 &m_variable_index,
66 &guid_1,
67 name_3.size() * sizeof(int16_t),
68- name_3.data());
69- CHECK_TRUE(info);
70- variable_index_set_variable(
71- info,
72+ name_3.data(),
73 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS);
74+
75+ CHECK_TRUE(info);
76 }
77
78 static const size_t MAX_VARIABLES = 10;
79@@ -114,7 +111,7 @@ TEST_GROUP(UefiVariableIndexTests)
80
81 TEST(UefiVariableIndexTests, emptyIndexOperations)
82 {
83- struct variable_info *info = NULL;
84+ const struct variable_info *info = NULL;
85
86 /* Expect not to find a variable */
87 info = variable_index_find(
88@@ -133,34 +130,36 @@ TEST(UefiVariableIndexTests, emptyIndexOperations)
89 POINTERS_EQUAL(NULL, info);
90
91 /* Remove should silently return */
92- variable_index_clear_variable(
93+ variable_index_remove_variable(
94 &m_variable_index,
95 info);
96 }
97
98 TEST(UefiVariableIndexTests, addWithOversizedName)
99 {
100- struct variable_info *info = NULL;
101+ const struct variable_info *info = NULL;
102 std::vector<int16_t> name;
103
104 name = to_variable_name(L"a long variable name that exceeds the length limit");
105
106- info = variable_index_add_entry(
107+ info = variable_index_add_variable(
108 &m_variable_index,
109 &guid_1,
110 name.size() * sizeof(int16_t),
111- name.data());
112+ name.data(),
113+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
114
115 /* Expect the add to fail because of an oversized name */
116 POINTERS_EQUAL(NULL, info);
117
118 name = to_variable_name(L"a long variable name that fits!");
119
120- info = variable_index_add_entry(
121+ info = variable_index_add_variable(
122 &m_variable_index,
123 &guid_1,
124 name.size() * sizeof(int16_t),
125- name.data());
126+ name.data(),
127+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
128
129 /* Expect the add succeed */
130 CHECK_TRUE(info);
131@@ -168,17 +167,18 @@ TEST(UefiVariableIndexTests, addWithOversizedName)
132
133 TEST(UefiVariableIndexTests, variableIndexFull)
134 {
135- struct variable_info *info = NULL;
136+ const struct variable_info *info = NULL;
137 EFI_GUID guid = guid_1;
138
139 /* Expect to be able to fill the index */
140 for (size_t i = 0; i < MAX_VARIABLES; ++i) {
141
142- info = variable_index_add_entry(
143+ info = variable_index_add_variable(
144 &m_variable_index,
145 &guid,
146 name_1.size() * sizeof(int16_t),
147- name_1.data());
148+ name_1.data(),
149+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
150
151 CHECK_TRUE(info);
152
153@@ -187,11 +187,12 @@ TEST(UefiVariableIndexTests, variableIndexFull)
154 }
155
156 /* Variable index should now be full */
157- info = variable_index_add_entry(
158+ info = variable_index_add_variable(
159 &m_variable_index,
160 &guid,
161 name_1.size() * sizeof(int16_t),
162- name_1.data());
163+ name_1.data(),
164+ EFI_VARIABLE_BOOTSERVICE_ACCESS);
165
166 POINTERS_EQUAL(NULL, info);
167 }
168@@ -322,7 +323,7 @@ TEST(UefiVariableIndexTests, dumpBufferTooSmall)
169 TEST(UefiVariableIndexTests, removeVariable)
170 {
171 uint8_t buffer[MAX_VARIABLES * sizeof(struct variable_metadata)];
172- struct variable_info *info = NULL;
173+ const struct variable_info *info = NULL;
174
175 create_variables();
176
177@@ -333,7 +334,7 @@ TEST(UefiVariableIndexTests, removeVariable)
178 name_2.size() * sizeof(int16_t),
179 name_2.data());
180
181- variable_index_clear_variable(
182+ variable_index_remove_variable(
183 &m_variable_index,
184 info);
185
186@@ -351,7 +352,7 @@ TEST(UefiVariableIndexTests, removeVariable)
187 name_1.size() * sizeof(int16_t),
188 name_1.data());
189
190- variable_index_clear_variable(
191+ variable_index_remove_variable(
192 &m_variable_index,
193 info);
194
195@@ -369,7 +370,7 @@ TEST(UefiVariableIndexTests, removeVariable)
196 name_3.size() * sizeof(int16_t),
197 name_3.data());
198
199- variable_index_clear_variable(
200+ variable_index_remove_variable(
201 &m_variable_index,
202 info);
203
204@@ -394,7 +395,7 @@ TEST(UefiVariableIndexTests, removeVariable)
205
206 TEST(UefiVariableIndexTests, checkIterator)
207 {
208- struct variable_info *info = NULL;
209+ const struct variable_info *info = NULL;
210
211 create_variables();
212
213@@ -418,7 +419,7 @@ TEST(UefiVariableIndexTests, checkIterator)
214 UNSIGNED_LONGS_EQUAL(name_2.size() * sizeof(int16_t), info->metadata.name_size);
215 MEMCMP_EQUAL(name_2.data(), info->metadata.name, info->metadata.name_size);
216
217- struct variable_info *info_to_remove = info;
218+ const struct variable_info *info_to_remove = info;
219
220 variable_index_iterator_next(&iter);
221 CHECK_FALSE(variable_index_iterator_is_done(&iter));
222@@ -434,8 +435,7 @@ TEST(UefiVariableIndexTests, checkIterator)
223 CHECK_TRUE(variable_index_iterator_is_done(&iter));
224
225 /* Now remove the middle entry */
226- variable_index_clear_variable(&m_variable_index, info_to_remove);
227- variable_index_remove_unused_entry(&m_variable_index, info_to_remove);
228+ variable_index_remove_variable(&m_variable_index, info_to_remove);
229
230 /* Iterate again but this time there should only be two entries */
231 variable_index_iterator_first(&iter, &m_variable_index);
232@@ -478,7 +478,7 @@ TEST(UefiVariableIndexTests, setCheckConstraintsExistingVar)
233 constraints.max_size = 100;
234
235 /* Set check constraints on one of the variables */
236- struct variable_info *info = variable_index_find(
237+ const struct variable_info *info = variable_index_find(
238 &m_variable_index,
239 &guid_2,
240 name_2.size() * sizeof(int16_t),
241@@ -488,7 +488,7 @@ TEST(UefiVariableIndexTests, setCheckConstraintsExistingVar)
242 CHECK_TRUE(info->is_variable_set);
243 CHECK_FALSE(info->is_constraints_set);
244
245- variable_index_set_constraints(info, &constraints);
246+ variable_index_update_constraints(info, &constraints);
247
248 CHECK_TRUE(info->is_constraints_set);
249 CHECK_TRUE(info->is_variable_set);
250@@ -496,7 +496,7 @@ TEST(UefiVariableIndexTests, setCheckConstraintsExistingVar)
251 /* Remove the variable but still expect the variable to be indexed
252 * because of the set constraints.
253 */
254- variable_index_clear_variable(
255+ variable_index_remove_variable(
256 &m_variable_index,
257 info);
258
259@@ -588,7 +588,7 @@ TEST(UefiVariableIndexTests, setCheckConstraintsNonExistingVar)
260 constraints.max_size = 100;
261
262 /* Initially expect no variable_info */
263- struct variable_info *info = variable_index_find(
264+ const struct variable_info *info = variable_index_find(
265 &m_variable_index,
266 &guid_2,
267 name_2.size() * sizeof(int16_t),
268@@ -597,19 +597,19 @@ TEST(UefiVariableIndexTests, setCheckConstraintsNonExistingVar)
269 CHECK_FALSE(info);
270
271 /* Adding the check constraints should result in an entry being added */
272- info = variable_index_add_entry(
273+ info = variable_index_add_constraints(
274 &m_variable_index,
275 &guid_2,
276 name_2.size() * sizeof(int16_t),
277- name_2.data());
278- CHECK_TRUE(info);
279+ name_2.data(),
280+ &constraints);
281
282- variable_index_set_constraints(info, &constraints);
283+ CHECK_TRUE(info);
284 CHECK_FALSE(info->is_variable_set);
285 CHECK_TRUE(info->is_constraints_set);
286
287 /* Updating the variable should cause the variable to be marked as set */
288- variable_index_set_variable(info, EFI_VARIABLE_RUNTIME_ACCESS);
289+ variable_index_update_variable(info, EFI_VARIABLE_RUNTIME_ACCESS);
290
291 CHECK_TRUE(info->is_variable_set);
292 CHECK_TRUE(info->is_constraints_set);
293diff --git a/components/service/smm_variable/backend/test/variable_store_tests.cpp b/components/service/smm_variable/backend/test/variable_store_tests.cpp
294index e90c1067..235642e6 100644
295--- a/components/service/smm_variable/backend/test/variable_store_tests.cpp
296+++ b/components/service/smm_variable/backend/test/variable_store_tests.cpp
297@@ -305,37 +305,6 @@ TEST(UefiVariableStoreTests, setGetRoundtrip)
298 /* Expect got variable data to be the same as the set value */
299 UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
300 LONGS_EQUAL(0, input_data.compare(output_data));
301-
302- /* Extend the variable using an append write */
303- std::string input_data2 = " jumps over the lazy dog";
304-
305- status = set_variable(var_name, input_data2, EFI_VARIABLE_APPEND_WRITE);
306- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
307-
308- status = get_variable(var_name, output_data);
309- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
310-
311- std::string expected_output = input_data + input_data2;
312-
313- /* Expect the append write operation to have extended the variable */
314- UNSIGNED_LONGLONGS_EQUAL(expected_output.size(), output_data.size());
315- LONGS_EQUAL(0, expected_output.compare(output_data));
316-
317- /* Expect query_variable_info to return consistent values */
318- size_t max_variable_storage_size = 0;
319- size_t remaining_variable_storage_size = 0;
320- size_t max_variable_size = 0;
321-
322- status = query_variable_info(
323- 0,
324- &max_variable_storage_size,
325- &remaining_variable_storage_size,
326- &max_variable_size);
327- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
328-
329- UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY, max_variable_storage_size);
330- UNSIGNED_LONGLONGS_EQUAL(MAX_VARIABLE_SIZE, max_variable_size);
331- UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY - expected_output.size(), remaining_variable_storage_size);
332 }
333
334 TEST(UefiVariableStoreTests, persistentSetGet)
335@@ -345,8 +314,7 @@ TEST(UefiVariableStoreTests, persistentSetGet)
336 std::string input_data = "quick brown fox";
337 std::string output_data;
338
339- status = set_variable(var_name, input_data,
340- EFI_VARIABLE_NON_VOLATILE);
341+ status = set_variable(var_name, input_data, EFI_VARIABLE_NON_VOLATILE);
342 UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
343
344 status = get_variable(var_name, output_data);
345@@ -356,22 +324,6 @@ TEST(UefiVariableStoreTests, persistentSetGet)
346 UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
347 LONGS_EQUAL(0, input_data.compare(output_data));
348
349- /* Extend the variable using an append write */
350- std::string input_data2 = " jumps over the lazy dog";
351-
352- status = set_variable(var_name, input_data2,
353- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_APPEND_WRITE);
354- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
355-
356- status = get_variable(var_name, output_data);
357- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
358-
359- std::string expected_output = input_data + input_data2;
360-
361- /* Expect the append write operation to have extended the variable */
362- UNSIGNED_LONGLONGS_EQUAL(expected_output.size(), output_data.size());
363- LONGS_EQUAL(0, expected_output.compare(output_data));
364-
365 /* Expect the variable to survive a power cycle */
366 power_cycle();
367
368@@ -380,24 +332,8 @@ TEST(UefiVariableStoreTests, persistentSetGet)
369 UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
370
371 /* Still expect got variable data to be the same as the set value */
372- UNSIGNED_LONGLONGS_EQUAL(expected_output.size(), output_data.size());
373- LONGS_EQUAL(0, expected_output.compare(output_data));
374-
375- /* Expect query_variable_info to return consistent values */
376- size_t max_variable_storage_size = 0;
377- size_t remaining_variable_storage_size = 0;
378- size_t max_variable_size = 0;
379-
380- status = query_variable_info(
381- EFI_VARIABLE_NON_VOLATILE,
382- &max_variable_storage_size,
383- &remaining_variable_storage_size,
384- &max_variable_size);
385- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
386-
387- UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY, max_variable_storage_size);
388- UNSIGNED_LONGLONGS_EQUAL(MAX_VARIABLE_SIZE, max_variable_size);
389- UNSIGNED_LONGLONGS_EQUAL(STORE_CAPACITY - expected_output.size(), remaining_variable_storage_size);
390+ UNSIGNED_LONGLONGS_EQUAL(input_data.size(), output_data.size());
391+ LONGS_EQUAL(0, input_data.compare(output_data));
392 }
393
394 TEST(UefiVariableStoreTests, removeVolatile)
395@@ -436,7 +372,7 @@ TEST(UefiVariableStoreTests, removePersistent)
396 UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
397
398 /* Remove by setting with zero data length */
399- status = set_variable(var_name, std::string(), EFI_VARIABLE_NON_VOLATILE);
400+ status = set_variable(var_name, std::string(), 0);
401 UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, status);
402
403 /* Expect variable to no loger exist */
404diff --git a/components/service/smm_variable/backend/uefi_variable_store.c b/components/service/smm_variable/backend/uefi_variable_store.c
405index b7cfff40..6a90f46a 100644
406--- a/components/service/smm_variable/backend/uefi_variable_store.c
407+++ b/components/service/smm_variable/backend/uefi_variable_store.c
408@@ -47,20 +47,6 @@ static efi_status_t load_variable_data(
409 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var,
410 size_t max_data_len);
411
412-static psa_status_t store_overwrite(
413- struct delegate_variable_store *delegate_store,
414- uint32_t client_id,
415- uint64_t uid,
416- size_t data_length,
417- const void *data);
418-
419-static psa_status_t store_append_write(
420- struct delegate_variable_store *delegate_store,
421- uint32_t client_id,
422- uint64_t uid,
423- size_t data_length,
424- const void *data);
425-
426 static void purge_orphan_index_entries(
427 struct uefi_variable_store *context);
428
429@@ -168,45 +154,40 @@ efi_status_t uefi_variable_store_set_variable(
430 struct uefi_variable_store *context,
431 const SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var)
432 {
433- bool should_sync_index = false;
434-
435- /* Validate incoming request */
436 efi_status_t status = check_name_terminator(var->Name, var->NameSize);
437 if (status != EFI_SUCCESS) return status;
438
439 status = check_capabilities(var);
440+ bool should_sync_index = false;
441+
442 if (status != EFI_SUCCESS) return status;
443
444- /* Find an existing entry in the variable index or add a new one */
445- struct variable_info *info = variable_index_find(
446+ /* Find in index */
447+ const struct variable_info *info = variable_index_find(
448 &context->variable_index,
449 &var->Guid,
450 var->NameSize,
451 var->Name);
452
453- if (!info) {
454+ if (info) {
455
456- info = variable_index_add_entry(
457- &context->variable_index,
458- &var->Guid,
459- var->NameSize,
460- var->Name);
461+ /* Variable info already exists */
462+ status = check_access_permitted_on_set(context, info, var);
463
464- if (!info) return EFI_OUT_OF_RESOURCES;
465- }
466+ if (status == EFI_SUCCESS) {
467
468- /* Control access */
469- status = check_access_permitted_on_set(context, info, var);
470+ should_sync_index =
471+ (var->Attributes & EFI_VARIABLE_NON_VOLATILE) ||
472+ (info->is_variable_set && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE));
473
474- if (status == EFI_SUCCESS) {
475+ if (var->DataSize) {
476
477- /* Access permitted */
478- if (info->is_variable_set) {
479-
480- /* It's a request to update to an existing variable */
481- if (!(var->Attributes &
482- (EFI_VARIABLE_APPEND_WRITE | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS_MASK)) &&
483- !var->DataSize) {
484+ /* It's a set rather than a remove operation */
485+ variable_index_update_variable(
486+ info,
487+ var->Attributes);
488+ }
489+ else {
490
491 /* It's a remove operation - for a remove, the variable
492 * data must be removed from the storage backend before
493@@ -215,30 +196,31 @@ efi_status_t uefi_variable_store_set_variable(
494 * the storage backend without a corresponding index entry.
495 */
496 remove_variable_data(context, info);
497- variable_index_clear_variable(&context->variable_index, info);
498+ variable_index_remove_variable(&context->variable_index, info);
499
500- should_sync_index = (var->Attributes & EFI_VARIABLE_NON_VOLATILE);
501- }
502- else {
503-
504- /* It's a set operation where variable data is potentially
505- * being overwritten or extended.
506- */
507- if ((var->Attributes & ~EFI_VARIABLE_APPEND_WRITE) != info->metadata.attributes) {
508-
509- /* Modifying attributes is forbidden */
510- return EFI_INVALID_PARAMETER;
511- }
512+ /* Variable info no longer valid */
513+ info = NULL;
514 }
515 }
516 else {
517
518- /* It's a request to create a new variable */
519- variable_index_set_variable(info, var->Attributes);
520-
521- should_sync_index = (var->Attributes & EFI_VARIABLE_NON_VOLATILE);
522+ /* Access forbidden */
523+ info = NULL;
524 }
525 }
526+ else if (var->DataSize) {
527+
528+ /* It's a new variable */
529+ info = variable_index_add_variable(
530+ &context->variable_index,
531+ &var->Guid,
532+ var->NameSize,
533+ var->Name,
534+ var->Attributes);
535+
536+ if (!info) status = EFI_OUT_OF_RESOURCES;
537+ should_sync_index = info && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE);
538+ }
539
540 /* The order of these operations is important. For an update
541 * or create operation, The variable index is always synchronized
542@@ -254,13 +236,11 @@ efi_status_t uefi_variable_store_set_variable(
543 }
544
545 /* Store any variable data to the storage backend */
546- if (info->is_variable_set && (status == EFI_SUCCESS)) {
547+ if (info && (status == EFI_SUCCESS)) {
548
549 status = store_variable_data(context, info, var);
550 }
551
552- variable_index_remove_unused_entry(&context->variable_index, info);
553-
554 return status;
555 }
556
557@@ -373,41 +353,53 @@ efi_status_t uefi_variable_store_set_var_check_property(
558 efi_status_t status = check_name_terminator(property->Name, property->NameSize);
559 if (status != EFI_SUCCESS) return status;
560
561- /* Find in index or create a new entry */
562- struct variable_info *info = variable_index_find(
563+ /* Find in index */
564+ const struct variable_info *info = variable_index_find(
565 &context->variable_index,
566 &property->Guid,
567 property->NameSize,
568 property->Name);
569
570- if (!info) {
571+ if (info) {
572
573- info = variable_index_add_entry(
574- &context->variable_index,
575- &property->Guid,
576- property->NameSize,
577- property->Name);
578+ /* Applying check constraints to an existing variable that may have
579+ * constraints already set. These could constrain the setting of
580+ * the constraints.
581+ */
582+ struct variable_constraints constraints = info->check_constraints;
583+
584+ status = variable_checker_set_constraints(
585+ &constraints,
586+ info->is_constraints_set,
587+ &property->VariableProperty);
588+
589+ if (status == EFI_SUCCESS) {
590
591- if (!info) return EFI_OUT_OF_RESOURCES;
592+ variable_index_update_constraints(info, &constraints);
593+ }
594 }
595+ else {
596
597- /* Applying check constraints to an existing variable that may have
598- * constraints already set. These could constrain the setting of
599- * the constraints.
600- */
601- struct variable_constraints constraints = info->check_constraints;
602+ /* Applying check constraints for a new variable */
603+ struct variable_constraints constraints;
604
605- status = variable_checker_set_constraints(
606- &constraints,
607- info->is_constraints_set,
608- &property->VariableProperty);
609+ status = variable_checker_set_constraints(
610+ &constraints,
611+ false,
612+ &property->VariableProperty);
613
614- if (status == EFI_SUCCESS) {
615+ if (status == EFI_SUCCESS) {
616
617- variable_index_set_constraints(info, &constraints);
618- }
619+ info = variable_index_add_constraints(
620+ &context->variable_index,
621+ &property->Guid,
622+ property->NameSize,
623+ property->Name,
624+ &constraints);
625
626- variable_index_remove_unused_entry(&context->variable_index, info);
627+ if (!info) status = EFI_OUT_OF_RESOURCES;
628+ }
629+ }
630
631 return status;
632 }
633@@ -514,8 +506,7 @@ static efi_status_t check_capabilities(
634 if (var->Attributes & ~(
635 EFI_VARIABLE_NON_VOLATILE |
636 EFI_VARIABLE_BOOTSERVICE_ACCESS |
637- EFI_VARIABLE_RUNTIME_ACCESS |
638- EFI_VARIABLE_APPEND_WRITE)) {
639+ EFI_VARIABLE_RUNTIME_ACCESS)) {
640
641 /* An unsupported attribute has been requested */
642 status = EFI_UNSUPPORTED;
643@@ -561,6 +552,17 @@ static efi_status_t check_access_permitted_on_set(
644 var->DataSize);
645 }
646
647+ if ((status == EFI_SUCCESS) && var->DataSize) {
648+
649+ /* Restrict which attributes can be modified for an existing variable */
650+ if ((var->Attributes & EFI_VARIABLE_NON_VOLATILE) !=
651+ (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE)) {
652+
653+ /* Don't permit change of storage class */
654+ status = EFI_INVALID_PARAMETER;
655+ }
656+ }
657+
658 return status;
659 }
660
661@@ -581,33 +583,20 @@ static efi_status_t store_variable_data(
662
663 if (delegate_store->storage_backend) {
664
665- if (!(var->Attributes & EFI_VARIABLE_APPEND_WRITE)) {
666-
667- /* Create or overwrite variable data */
668- psa_status = store_overwrite(
669- delegate_store,
670- context->owner_id,
671- info->metadata.uid,
672- data_len,
673- data);
674- }
675- else {
676-
677- /* Append new data to existing variable data */
678- psa_status = store_append_write(
679- delegate_store,
680- context->owner_id,
681- info->metadata.uid,
682- data_len,
683- data);
684- }
685+ psa_status = delegate_store->storage_backend->interface->set(
686+ delegate_store->storage_backend->context,
687+ context->owner_id,
688+ info->metadata.uid,
689+ data_len,
690+ data,
691+ PSA_STORAGE_FLAG_NONE);
692 }
693
694 if ((psa_status != PSA_SUCCESS) && delegate_store->is_nv) {
695
696 /* A storage failure has occurred so attempt to fix any
697- * mismatch between the variable index and stored NV variables.
698- */
699+ * mismatch between the variable index and stored NV variables.
700+ */
701 purge_orphan_index_entries(context);
702 }
703
704@@ -674,100 +663,6 @@ static efi_status_t load_variable_data(
705 return psa_to_efi_storage_status(psa_status);
706 }
707
708-static psa_status_t store_overwrite(
709- struct delegate_variable_store *delegate_store,
710- uint32_t client_id,
711- uint64_t uid,
712- size_t data_length,
713- const void *data)
714-{
715- /* Police maximum variable size limit */
716- if (data_length > delegate_store->max_variable_size) return PSA_ERROR_INVALID_ARGUMENT;
717-
718- psa_status_t psa_status = delegate_store->storage_backend->interface->set(
719- delegate_store->storage_backend->context,
720- client_id,
721- uid,
722- data_length,
723- data,
724- PSA_STORAGE_FLAG_NONE);
725-
726- return psa_status;
727-}
728-
729-static psa_status_t store_append_write(
730- struct delegate_variable_store *delegate_store,
731- uint32_t client_id,
732- uint64_t uid,
733- size_t data_length,
734- const void *data)
735-{
736- struct psa_storage_info_t storage_info;
737-
738- if (data_length == 0) return PSA_SUCCESS;
739-
740- psa_status_t psa_status = delegate_store->storage_backend->interface->get_info(
741- delegate_store->storage_backend->context,
742- client_id,
743- uid,
744- &storage_info);
745-
746- if (psa_status != PSA_SUCCESS) return psa_status;
747-
748- /* Determine size of appended variable */
749- size_t new_size = storage_info.size + data_length;
750-
751- /* Defend against integer overflow */
752- if (new_size < storage_info.size) return PSA_ERROR_INVALID_ARGUMENT;
753-
754- /* Police maximum variable size limit */
755- if (new_size > delegate_store->max_variable_size) return PSA_ERROR_INVALID_ARGUMENT;
756-
757- /* Storage backend doesn't support an append operation so we need
758- * need to read the current variable data, extend it and write it back.
759- */
760- uint8_t *rw_buf = malloc(new_size);
761- if (!rw_buf) return PSA_ERROR_INSUFFICIENT_MEMORY;
762-
763- size_t old_size = 0;
764- psa_status = delegate_store->storage_backend->interface->get(
765- delegate_store->storage_backend->context,
766- client_id,
767- uid,
768- 0,
769- new_size,
770- rw_buf,
771- &old_size);
772-
773- if (psa_status == PSA_SUCCESS) {
774-
775- if ((old_size + data_length) <= new_size) {
776-
777- /* Extend the variable data */
778- memcpy(&rw_buf[old_size], data, data_length);
779-
780- psa_status = delegate_store->storage_backend->interface->set(
781- delegate_store->storage_backend->context,
782- client_id,
783- uid,
784- old_size + data_length,
785- rw_buf,
786- storage_info.flags);
787- }
788- else {
789-
790- /* There's a mismatch between the length obtained from
791- * get_info() and the subsequent length returned by get().
792- */
793- psa_status = PSA_ERROR_STORAGE_FAILURE;
794- }
795- }
796-
797- free(rw_buf);
798-
799- return psa_status;
800-}
801-
802 static void purge_orphan_index_entries(
803 struct uefi_variable_store *context)
804 {
805@@ -782,7 +677,7 @@ static void purge_orphan_index_entries(
806 */
807 while (!variable_index_iterator_is_done(&iter)) {
808
809- struct variable_info *info = variable_index_iterator_current(&iter);
810+ const struct variable_info *info = variable_index_iterator_current(&iter);
811
812 if (info->is_variable_set && (info->metadata.attributes & EFI_VARIABLE_NON_VOLATILE)) {
813
814@@ -799,7 +694,7 @@ static void purge_orphan_index_entries(
815 if (psa_status != PSA_SUCCESS) {
816
817 /* Detected a mismatch between the index and storage */
818- variable_index_clear_variable(&context->variable_index, info);
819+ variable_index_remove_variable(&context->variable_index, info);
820 any_orphans = true;
821 }
822 }
823diff --git a/components/service/smm_variable/backend/variable_index.c b/components/service/smm_variable/backend/variable_index.c
824index a8a55753..99d7c97a 100644
825--- a/components/service/smm_variable/backend/variable_index.c
826+++ b/components/service/smm_variable/backend/variable_index.c
827@@ -132,13 +132,13 @@ size_t variable_index_max_dump_size(
828 return sizeof(struct variable_metadata) * context->max_variables;
829 }
830
831-struct variable_info *variable_index_find(
832- struct variable_index *context,
833+const struct variable_info *variable_index_find(
834+ const struct variable_index *context,
835 const EFI_GUID *guid,
836 size_t name_size,
837 const int16_t *name)
838 {
839- struct variable_info *result = NULL;
840+ const struct variable_info *result = NULL;
841 int pos = find_variable(context, guid, name_size, name);
842
843 if (pos >= 0) {
844@@ -149,13 +149,13 @@ struct variable_info *variable_index_find(
845 return result;
846 }
847
848-struct variable_info *variable_index_find_next(
849+const struct variable_info *variable_index_find_next(
850 const struct variable_index *context,
851 const EFI_GUID *guid,
852 size_t name_size,
853 const int16_t *name)
854 {
855- struct variable_info *result = NULL;
856+ const struct variable_info *result = NULL;
857
858 if (name_size >= sizeof(int16_t)) {
859
860@@ -263,11 +263,12 @@ static struct variable_entry *add_entry(
861 return entry;
862 }
863
864-struct variable_info *variable_index_add_entry(
865+const struct variable_info *variable_index_add_variable(
866 struct variable_index *context,
867 const EFI_GUID *guid,
868 size_t name_size,
869- const int16_t *name)
870+ const int16_t *name,
871+ uint32_t attributes)
872 {
873 struct variable_info *info = NULL;
874 struct variable_entry *entry = add_entry(context, guid, name_size, name);
875@@ -275,41 +276,40 @@ struct variable_info *variable_index_add_entry(
876 if (entry) {
877
878 info = &entry->info;
879+
880+ info->metadata.attributes = attributes;
881+ info->is_variable_set = true;
882+
883+ mark_dirty(entry);
884 }
885
886 return info;
887 }
888
889-void variable_index_remove_unused_entry(
890+const struct variable_info *variable_index_add_constraints(
891 struct variable_index *context,
892- struct variable_info *info)
893+ const EFI_GUID *guid,
894+ size_t name_size,
895+ const int16_t *name,
896+ const struct variable_constraints *constraints)
897 {
898- if (info &&
899- !info->is_constraints_set &&
900- !info->is_variable_set) {
901-
902- struct variable_entry *entry = containing_entry(info);
903- entry->in_use = false;
904+ struct variable_info *info = NULL;
905+ struct variable_entry *entry = add_entry(context, guid, name_size, name);
906
907- memset(info, 0, sizeof(struct variable_info));
908- }
909-}
910+ if (entry) {
911
912-void variable_index_set_variable(
913- struct variable_info *info,
914- uint32_t attributes)
915-{
916- struct variable_entry *entry = containing_entry(info);
917+ info = &entry->info;
918
919- info->metadata.attributes = attributes;
920- info->is_variable_set = true;
921+ info->check_constraints = *constraints;
922+ info->is_constraints_set = true;
923+ }
924
925- mark_dirty(entry);
926+ return info;
927 }
928
929-void variable_index_clear_variable(
930+void variable_index_remove_variable(
931 struct variable_index *context,
932- struct variable_info *info)
933+ const struct variable_info *info)
934 {
935 if (info) {
936
937@@ -318,17 +318,48 @@ void variable_index_clear_variable(
938
939 /* Mark variable as no longer set */
940 entry->info.is_variable_set = false;
941+
942+ /* Entry may still be needed if check constraints were set */
943+ entry->in_use = info->is_constraints_set;
944+
945+ if (!entry->in_use) {
946+
947+ /* Entry not needed so wipe */
948+ memset(&entry->info, 0, sizeof(struct variable_info));
949+ }
950 }
951 }
952
953-void variable_index_set_constraints(
954- struct variable_info *info,
955+void variable_index_update_variable(
956+ const struct variable_info *info,
957+ uint32_t attributes)
958+{
959+ if (info) {
960+
961+ struct variable_info *modified_info = (struct variable_info*)info;
962+ struct variable_entry *entry = containing_entry(modified_info);
963+
964+ if (!modified_info->is_variable_set ||
965+ (attributes != modified_info->metadata.attributes)) {
966+
967+ /* The update changes the variable_info state */
968+ modified_info->is_variable_set = true;
969+ modified_info->metadata.attributes = attributes;
970+ mark_dirty(entry);
971+ }
972+ }
973+}
974+
975+void variable_index_update_constraints(
976+ const struct variable_info *info,
977 const struct variable_constraints *constraints)
978 {
979 if (info) {
980
981- info->check_constraints = *constraints;
982- info->is_constraints_set = true;
983+ struct variable_info *modified_info = (struct variable_info*)info;
984+
985+ modified_info->check_constraints = *constraints;
986+ modified_info->is_constraints_set = true;
987 }
988 }
989
990diff --git a/components/service/smm_variable/backend/variable_index.h b/components/service/smm_variable/backend/variable_index.h
991index 63f42ab6..e109d0d1 100644
992--- a/components/service/smm_variable/backend/variable_index.h
993+++ b/components/service/smm_variable/backend/variable_index.h
994@@ -119,8 +119,8 @@ size_t variable_index_max_dump_size(
995 *
996 * @return Pointer to variable_info or NULL
997 */
998-struct variable_info *variable_index_find(
999- struct variable_index *context,
1000+const struct variable_info *variable_index_find(
1001+ const struct variable_index *context,
1002 const EFI_GUID *guid,
1003 size_t name_size,
1004 const int16_t *name);
1005@@ -135,76 +135,78 @@ struct variable_info *variable_index_find(
1006 *
1007 * @return Pointer to variable_info or NULL
1008 */
1009-struct variable_info *variable_index_find_next(
1010+const struct variable_info *variable_index_find_next(
1011 const struct variable_index *context,
1012 const EFI_GUID *guid,
1013 size_t name_size,
1014 const int16_t *name);
1015
1016 /**
1017- * @brief Add a new entry to the index
1018- *
1019- * An entry is needed either when a new variable is created or
1020- * when variable constraints are set for a variable that doesn't
1021- * yet exist.
1022+ * @brief Add a new variable to the index
1023 *
1024 * @param[in] context variable_index
1025 * @param[in] guid The variable's guid
1026 * @param[in] name_size The name parameter's size
1027 * @param[in] name The variable's name
1028+ * @param[in] attributes The variable's attributes
1029 *
1030 * @return Pointer to variable_info or NULL
1031 */
1032-struct variable_info *variable_index_add_entry(
1033+const struct variable_info *variable_index_add_variable(
1034 struct variable_index *context,
1035 const EFI_GUID *guid,
1036 size_t name_size,
1037- const int16_t *name);
1038+ const int16_t *name,
1039+ uint32_t attributes);
1040
1041 /**
1042- * @brief Remove an unused entry from the index
1043+ * @brief Remove a variable from the index
1044 *
1045- * Removes an entry if it is not in use.
1046+ * Removes a variable from the index if it exists.
1047 *
1048 * @param[in] context variable_index
1049 * @param[in] info The variable info corresponding to the entry to remove
1050 */
1051-void variable_index_remove_unused_entry(
1052+void variable_index_remove_variable(
1053 struct variable_index *context,
1054- struct variable_info *info);
1055+ const struct variable_info *info);
1056
1057 /**
1058- * @brief Set a variable to the index
1059- *
1060- * An entry for the variable must already exist.
1061+ * @brief Update a variable that's already in the index
1062 *
1063 * @param[in] info variable info
1064 * @param[in] attributes The variable's attributes
1065 */
1066-void variable_index_set_variable(
1067- struct variable_info *info,
1068+void variable_index_update_variable(
1069+ const struct variable_info *info,
1070 uint32_t attributes);
1071
1072 /**
1073- * @brief Clear a variable from the index
1074- *
1075- * Clears a variable from the index
1076+ * @brief Add a new check constraints object to the index
1077 *
1078 * @param[in] context variable_index
1079- * @param[in] info The variable info corresponding to the variable to clear
1080+ * @param[in] guid The variable's guid
1081+ * @param[in] name_size The name parameter's size
1082+ * @param[in] name The variable's name
1083+ * @param[in] constraints The check constraints
1084+ *
1085+ * @return Pointer to variable_info or NULL
1086 */
1087-void variable_index_clear_variable(
1088+const struct variable_info *variable_index_add_constraints(
1089 struct variable_index *context,
1090- struct variable_info *info);
1091+ const EFI_GUID *guid,
1092+ size_t name_size,
1093+ const int16_t *name,
1094+ const struct variable_constraints *constraints);
1095
1096 /**
1097- * @brief Set a check constraints object associated with a variavle
1098+ * @brief Update variable constraints that are already in the index
1099 *
1100 * @param[in] info variable info
1101 * @param[in] constraints The check constraints
1102 */
1103-void variable_index_set_constraints(
1104- struct variable_info *info,
1105+void variable_index_update_constraints(
1106+ const struct variable_info *info,
1107 const struct variable_constraints *constraints);
1108
1109 /**
1110diff --git a/components/service/smm_variable/backend/variable_index_iterator.c b/components/service/smm_variable/backend/variable_index_iterator.c
1111index 8f8fc741..7cc6dc7a 100644
1112--- a/components/service/smm_variable/backend/variable_index_iterator.c
1113+++ b/components/service/smm_variable/backend/variable_index_iterator.c
1114@@ -31,10 +31,10 @@ bool variable_index_iterator_is_done(
1115 return iter->current_pos >= iter->variable_index->max_variables;
1116 }
1117
1118-struct variable_info *variable_index_iterator_current(
1119+const struct variable_info *variable_index_iterator_current(
1120 const struct variable_index_iterator *iter)
1121 {
1122- struct variable_info *current = NULL;
1123+ const struct variable_info *current = NULL;
1124
1125 if (!variable_index_iterator_is_done(iter)) {
1126
1127diff --git a/components/service/smm_variable/backend/variable_index_iterator.h b/components/service/smm_variable/backend/variable_index_iterator.h
1128index 7ff77c50..f64a2c49 100644
1129--- a/components/service/smm_variable/backend/variable_index_iterator.h
1130+++ b/components/service/smm_variable/backend/variable_index_iterator.h
1131@@ -54,7 +54,7 @@ bool variable_index_iterator_is_done(
1132 *
1133 * @return Pointer to variable_info or NULL
1134 */
1135-struct variable_info *variable_index_iterator_current(
1136+const struct variable_info *variable_index_iterator_current(
1137 const struct variable_index_iterator *iter);
1138
1139 /**
1140diff --git a/components/service/smm_variable/test/service/smm_variable_service_tests.cpp b/components/service/smm_variable/test/service/smm_variable_service_tests.cpp
1141index 15556e9d..38c08ebe 100644
1142--- a/components/service/smm_variable/test/service/smm_variable_service_tests.cpp
1143+++ b/components/service/smm_variable/test/service/smm_variable_service_tests.cpp
1144@@ -249,30 +249,6 @@ TEST(SmmVariableServiceTests, setAndGet)
1145 UNSIGNED_LONGS_EQUAL(set_data.size(), get_data.size());
1146 LONGS_EQUAL(0, get_data.compare(set_data));
1147
1148- /* Extend the variable using an append write */
1149- std::string append_data = " values added with append write";
1150-
1151- efi_status = m_client->set_variable(
1152- m_common_guid,
1153- var_name,
1154- append_data,
1155- EFI_VARIABLE_APPEND_WRITE);
1156-
1157- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
1158-
1159- efi_status = m_client->get_variable(
1160- m_common_guid,
1161- var_name,
1162- get_data);
1163-
1164- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
1165-
1166- std::string appended_data = set_data + append_data;
1167-
1168- /* Expect the append write operation to have extended the variable */
1169- UNSIGNED_LONGLONGS_EQUAL(appended_data.size(), get_data.size());
1170- LONGS_EQUAL(0, appended_data.compare(get_data));
1171-
1172 /* Expect remove to be permitted */
1173 efi_status = m_client->remove_variable(m_common_guid, var_name);
1174 UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
1175@@ -303,30 +279,6 @@ TEST(SmmVariableServiceTests, setAndGetNv)
1176 UNSIGNED_LONGS_EQUAL(set_data.size(), get_data.size());
1177 LONGS_EQUAL(0, get_data.compare(set_data));
1178
1179- /* Extend the variable using an append write */
1180- std::string append_data = " values added with append write";
1181-
1182- efi_status = m_client->set_variable(
1183- m_common_guid,
1184- var_name,
1185- append_data,
1186- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_APPEND_WRITE);
1187-
1188- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
1189-
1190- efi_status = m_client->get_variable(
1191- m_common_guid,
1192- var_name,
1193- get_data);
1194-
1195- UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
1196-
1197- std::string appended_data = set_data + append_data;
1198-
1199- /* Expect the append write operation to have extended the variable */
1200- UNSIGNED_LONGLONGS_EQUAL(appended_data.size(), get_data.size());
1201- LONGS_EQUAL(0, appended_data.compare(get_data));
1202-
1203 /* Expect remove to be permitted */
1204 efi_status = m_client->remove_variable(m_common_guid, var_name);
1205 UNSIGNED_LONGLONGS_EQUAL(EFI_SUCCESS, efi_status);
1206diff --git a/protocols/service/smm_variable/parameters.h b/protocols/service/smm_variable/parameters.h
1207index 233f301b..1f795a9b 100644
1208--- a/protocols/service/smm_variable/parameters.h
1209+++ b/protocols/service/smm_variable/parameters.h
1210@@ -47,9 +47,6 @@ typedef struct {
1211 EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
1212 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \
1213 EFI_VARIABLE_APPEND_WRITE)
1214-#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS_MASK \
1215- (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \
1216- EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
1217
1218 /**
1219 * Parameter structure for SetVariable and GetVariable.