TianoCore EDK2 master
Loading...
Searching...
No Matches
VariablePolicyLib.c
1
9#include <Uefi.h>
10
11#include <Library/BaseLib.h>
12#include <Library/SafeIntLib.h>
15#include <Library/DebugLib.h>
16#include <Library/PcdLib.h>
17
18#include <Protocol/VariablePolicy.h>
19#include <Library/VariablePolicyLib.h>
20
21// IMPORTANT NOTE: This library is currently rife with multiple return statements
22// for error handling. A refactor should remove these at some point.
23
24//
25// This library was designed with advanced unit-test features.
26// This define handles the configuration.
27#ifdef INTERNAL_UNIT_TEST
28 #undef STATIC
29#define STATIC // Nothing...
30#endif
31
32// An abstracted GetVariable interface that enables configuration regardless of the environment.
33EFI_GET_VARIABLE mGetVariableHelper = NULL;
34
35// Master switch to lock this entire interface. Does not stop enforcement,
36// just prevents the configuration from being changed for the rest of the boot.
37STATIC BOOLEAN mInterfaceLocked = FALSE;
38
39// Master switch to disable the entire interface for a single boot.
40// This will disable all policy enforcement for the duration of the boot.
41STATIC BOOLEAN mProtectionDisabled = FALSE;
42
43// Table to hold all the current policies.
44UINT8 *mPolicyTable = NULL;
45STATIC UINT32 mCurrentTableSize = 0;
46STATIC UINT32 mCurrentTableUsage = 0;
47STATIC UINT32 mCurrentTableCount = 0;
48
49#define POLICY_TABLE_STEP_SIZE 0x1000
50
51// NOTE: DO NOT USE THESE MACROS on any structure that has not been validated.
52// Current table data has already been sanitized.
53#define GET_NEXT_POLICY(CurPolicy) (VARIABLE_POLICY_ENTRY*)((UINT8*)CurPolicy + CurPolicy->Size)
54#define GET_POLICY_NAME(CurPolicy) (CHAR16*)((UINTN)CurPolicy + CurPolicy->OffsetToName)
55
56#define MATCH_PRIORITY_EXACT 0
57#define MATCH_PRIORITY_MAX MATCH_PRIORITY_EXACT
58#define MATCH_PRIORITY_MIN MAX_UINT8
59
69VariablePolicyExtraInit (
70 VOID
71 );
72
82VariablePolicyExtraDeinit (
83 VOID
84 );
85
98BOOLEAN
99IsValidVariablePolicyStructure (
101 )
102{
103 EFI_STATUS Status;
104 UINTN EntryEnd;
105 CHAR16 *CheckChar;
106 UINTN WildcardCount;
107
108 // Sanitize some quick values.
109 if ((NewPolicy == NULL) || (NewPolicy->Size == 0) ||
110 // Structure size should be at least as long as the minumum structure and a NULL string.
111 (NewPolicy->Size < sizeof (VARIABLE_POLICY_ENTRY)) ||
112 // Check for the known revision.
113 (NewPolicy->Version != VARIABLE_POLICY_ENTRY_REVISION))
114 {
115 return FALSE;
116 }
117
118 // Calculate the theoretical end of the structure and make sure
119 // that the structure can fit in memory.
120 Status = SafeUintnAdd ((UINTN)NewPolicy, NewPolicy->Size, &EntryEnd);
121 if (EFI_ERROR (Status)) {
122 return FALSE;
123 }
124
125 // Check for a valid Max Size.
126 if (NewPolicy->MaxSize == 0) {
127 return FALSE;
128 }
129
130 // Check for the valid list of lock policies.
131 if ((NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_NO_LOCK) &&
132 (NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_NOW) &&
133 (NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_CREATE) &&
134 (NewPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE))
135 {
136 return FALSE;
137 }
138
139 // If the policy type is VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE, make sure that the matching state variable Name
140 // terminates before the OffsetToName for the matching policy variable Name.
141 if (NewPolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE) {
142 // Adjust CheckChar to the offset of the LockPolicy->Name.
143 Status = SafeUintnAdd (
144 (UINTN)NewPolicy + sizeof (VARIABLE_POLICY_ENTRY),
146 (UINTN *)&CheckChar
147 );
148 if (EFI_ERROR (Status) || (EntryEnd <= (UINTN)CheckChar)) {
149 return FALSE;
150 }
151
152 while (*CheckChar != CHAR_NULL) {
153 if (EntryEnd <= (UINTN)CheckChar) {
154 return FALSE;
155 }
156
157 CheckChar++;
158 }
159
160 // At this point we should have either exeeded the structure or be pointing at the last char in LockPolicy->Name.
161 // We should check to make sure that the policy Name comes immediately after this charcter.
162 if ((UINTN)++ CheckChar != (UINTN)NewPolicy + NewPolicy->OffsetToName) {
163 return FALSE;
164 }
165
166 // If the policy type is any other value, make sure that the LockPolicy structure has a zero length.
167 } else {
168 if (NewPolicy->OffsetToName != sizeof (VARIABLE_POLICY_ENTRY)) {
169 return FALSE;
170 }
171 }
172
173 // Check to make sure that the name has a terminating character
174 // before the end of the structure.
175 // We've already checked that the name is within the bounds of the structure.
176 if (NewPolicy->Size != NewPolicy->OffsetToName) {
177 CheckChar = (CHAR16 *)((UINTN)NewPolicy + NewPolicy->OffsetToName);
178 WildcardCount = 0;
179 while (*CheckChar != CHAR_NULL) {
180 // Make sure there aren't excessive wildcards.
181 if (*CheckChar == L'#') {
182 WildcardCount++;
183 if (WildcardCount > MATCH_PRIORITY_MIN) {
184 return FALSE;
185 }
186 }
187
188 // Make sure you're still within the bounds of the policy structure.
189 if (EntryEnd <= (UINTN)CheckChar) {
190 return FALSE;
191 }
192
193 CheckChar++;
194 }
195
196 // Finally, we should be pointed at the very last character in Name, so we should be right
197 // up against the end of the structure.
198 if ((UINTN)++ CheckChar != EntryEnd) {
199 return FALSE;
200 }
201 }
202
203 return TRUE;
204}
205
225STATIC
226BOOLEAN
227EvaluatePolicyMatch (
228 IN CONST VARIABLE_POLICY_ENTRY *EvalEntry,
229 IN CONST CHAR16 *VariableName,
230 IN CONST EFI_GUID *VendorGuid,
231 OUT UINT8 *MatchPriority OPTIONAL
232 )
233{
234 BOOLEAN Result;
235 CHAR16 *PolicyName;
236 UINT8 CalculatedPriority;
237 UINTN Index;
238
239 Result = FALSE;
240 CalculatedPriority = MATCH_PRIORITY_EXACT;
241
242 // Step 1: If the GUID doesn't match, we're done. No need to evaluate anything else.
243 if (!CompareGuid (&EvalEntry->Namespace, VendorGuid)) {
244 goto Exit;
245 }
246
247 // If the GUID matches, check to see whether there is a Name associated
248 // with the policy. If not, this policy matches the entire namespace.
249 // Missing Name is indicated by size being equal to name.
250 if (EvalEntry->Size == EvalEntry->OffsetToName) {
251 CalculatedPriority = MATCH_PRIORITY_MIN;
252 Result = TRUE;
253 goto Exit;
254 }
255
256 // Now that we know the name exists, get it.
257 PolicyName = GET_POLICY_NAME (EvalEntry);
258
259 // Evaluate the name against the policy name and check for a match.
260 // Account for any wildcards.
261 Index = 0;
262 Result = TRUE;
263 // Keep going until the end of both strings.
264 while (PolicyName[Index] != CHAR_NULL || VariableName[Index] != CHAR_NULL) {
265 // If we don't have a match...
266 if ((PolicyName[Index] != VariableName[Index]) || (PolicyName[Index] == L'#')) {
267 // If this is a numerical wildcard, we can consider
268 // it a match if we alter the priority.
269 if ((PolicyName[Index] == L'#') &&
270 (((L'0' <= VariableName[Index]) && (VariableName[Index] <= L'9')) ||
271 ((L'A' <= VariableName[Index]) && (VariableName[Index] <= L'F')) ||
272 ((L'a' <= VariableName[Index]) && (VariableName[Index] <= L'f'))))
273 {
274 if (CalculatedPriority < MATCH_PRIORITY_MIN) {
275 CalculatedPriority++;
276 }
277
278 // Otherwise, not a match.
279 } else {
280 Result = FALSE;
281 goto Exit;
282 }
283 }
284
285 Index++;
286 }
287
288Exit:
289 if (Result && (MatchPriority != NULL)) {
290 *MatchPriority = CalculatedPriority;
291 }
292
293 return Result;
294}
295
311STATIC
313GetBestPolicyMatch (
314 IN CONST CHAR16 *VariableName,
315 IN CONST EFI_GUID *VendorGuid,
316 OUT UINT8 *ReturnPriority OPTIONAL
317 )
318{
319 VARIABLE_POLICY_ENTRY *BestResult;
320 VARIABLE_POLICY_ENTRY *CurrentEntry;
321 UINT8 MatchPriority;
322 UINT8 CurrentPriority;
323 UINTN Index;
324
325 BestResult = NULL;
326 MatchPriority = MATCH_PRIORITY_EXACT;
327
328 // Walk all entries in the table, looking for matches.
329 CurrentEntry = (VARIABLE_POLICY_ENTRY *)mPolicyTable;
330 for (Index = 0; Index < mCurrentTableCount; Index++) {
331 // Check for a match.
332 if (EvaluatePolicyMatch (CurrentEntry, VariableName, VendorGuid, &CurrentPriority)) {
333 // If match is better, take it.
334 if ((BestResult == NULL) || (CurrentPriority < MatchPriority)) {
335 BestResult = CurrentEntry;
336 MatchPriority = CurrentPriority;
337 }
338
339 // If you've hit the highest-priority match, can exit now.
340 if (MatchPriority == 0) {
341 break;
342 }
343 }
344
345 // If we're still in the loop, move to the next entry.
346 CurrentEntry = GET_NEXT_POLICY (CurrentEntry);
347 }
348
349 // If a return priority was requested, return it.
350 if (ReturnPriority != NULL) {
351 *ReturnPriority = MatchPriority;
352 }
353
354 return BestResult;
355}
356
374EFIAPI
375RegisterVariablePolicy (
377 )
378{
379 EFI_STATUS Status;
380 VARIABLE_POLICY_ENTRY *MatchPolicy;
381 UINT8 MatchPriority;
382 UINT32 NewSize;
383 UINT8 *NewTable;
384
385 if (!IsVariablePolicyLibInitialized ()) {
386 return EFI_NOT_READY;
387 }
388
389 if (mInterfaceLocked) {
390 return EFI_WRITE_PROTECTED;
391 }
392
393 if (!IsValidVariablePolicyStructure (NewPolicy)) {
394 return EFI_INVALID_PARAMETER;
395 }
396
397 // Check to see whether an exact matching policy already exists.
398 MatchPolicy = GetBestPolicyMatch (
399 GET_POLICY_NAME (NewPolicy),
400 &NewPolicy->Namespace,
401 &MatchPriority
402 );
403 if ((MatchPolicy != NULL) && (MatchPriority == MATCH_PRIORITY_EXACT)) {
404 return EFI_ALREADY_STARTED;
405 }
406
407 // If none exists, create it.
408 // If we need more space, allocate that now.
409 Status = SafeUint32Add (mCurrentTableUsage, NewPolicy->Size, &NewSize);
410 if (EFI_ERROR (Status)) {
411 return EFI_ABORTED;
412 }
413
414 if (NewSize > mCurrentTableSize) {
415 // Use NewSize to calculate the new table size in units of POLICY_TABLE_STEP_SIZE.
416 NewSize = (NewSize % POLICY_TABLE_STEP_SIZE) > 0 ?
417 (NewSize / POLICY_TABLE_STEP_SIZE) + 1 :
418 (NewSize / POLICY_TABLE_STEP_SIZE);
419 // Calculate the new table size in absolute bytes.
420 Status = SafeUint32Mult (NewSize, POLICY_TABLE_STEP_SIZE, &NewSize);
421 if (EFI_ERROR (Status)) {
422 return EFI_ABORTED;
423 }
424
425 // Reallocate and copy the table.
426 NewTable = AllocateRuntimePool (NewSize);
427 if (NewTable == NULL) {
428 return EFI_OUT_OF_RESOURCES;
429 }
430
431 CopyMem (NewTable, mPolicyTable, mCurrentTableUsage);
432 mCurrentTableSize = NewSize;
433 if (mPolicyTable != NULL) {
434 FreePool (mPolicyTable);
435 }
436
437 mPolicyTable = NewTable;
438 }
439
440 // Copy the policy into the table.
441 CopyMem (mPolicyTable + mCurrentTableUsage, NewPolicy, NewPolicy->Size);
442 mCurrentTableUsage += NewPolicy->Size;
443 mCurrentTableCount += 1;
444
445 // We're done here.
446
447 return EFI_SUCCESS;
448}
449
470EFIAPI
471ValidateSetVariable (
472 IN CHAR16 *VariableName,
473 IN EFI_GUID *VendorGuid,
474 IN UINT32 Attributes,
475 IN UINTN DataSize,
476 IN VOID *Data
477 )
478{
479 BOOLEAN IsDel;
480 VARIABLE_POLICY_ENTRY *ActivePolicy;
481 EFI_STATUS Status;
482 EFI_STATUS ReturnStatus;
483 VARIABLE_LOCK_ON_VAR_STATE_POLICY *StateVarPolicy;
484 CHAR16 *StateVarName;
485 UINTN StateVarSize;
486 UINT8 StateVar;
487
488 ReturnStatus = EFI_SUCCESS;
489
490 if (!IsVariablePolicyLibInitialized ()) {
491 ReturnStatus = EFI_NOT_READY;
492 goto Exit;
493 }
494
495 // Bail if the protections are currently disabled.
496 if (mProtectionDisabled) {
497 ReturnStatus = EFI_SUCCESS;
498 goto Exit;
499 }
500
501 // Determine whether this is a delete operation.
502 // If so, it will affect which tests are applied.
503 if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
504 IsDel = TRUE;
505 } else {
506 IsDel = FALSE;
507 }
508
509 // Find an active policy if one exists.
510 ActivePolicy = GetBestPolicyMatch (VariableName, VendorGuid, NULL);
511
512 // If we have an active policy, check it against the incoming data.
513 if (ActivePolicy != NULL) {
514 //
515 // Only enforce size and attribute constraints when updating data, not deleting.
516 if (!IsDel) {
517 // Check for size constraints.
518 if (((ActivePolicy->MinSize > 0) && (DataSize < ActivePolicy->MinSize)) ||
519 ((ActivePolicy->MaxSize > 0) && (DataSize > ActivePolicy->MaxSize)))
520 {
521 ReturnStatus = EFI_INVALID_PARAMETER;
522 DEBUG ((
523 DEBUG_VERBOSE,
524 "%a - Bad Size. 0x%X <> 0x%X-0x%X\n",
525 __func__,
526 DataSize,
527 ActivePolicy->MinSize,
528 ActivePolicy->MaxSize
529 ));
530 goto Exit;
531 }
532
533 // Check for attribute constraints.
534 if (((ActivePolicy->AttributesMustHave & Attributes) != ActivePolicy->AttributesMustHave) ||
535 ((ActivePolicy->AttributesCantHave & Attributes) != 0))
536 {
537 ReturnStatus = EFI_INVALID_PARAMETER;
538 DEBUG ((
539 DEBUG_VERBOSE,
540 "%a - Bad Attributes. 0x%X <> 0x%X:0x%X\n",
541 __func__,
542 Attributes,
543 ActivePolicy->AttributesMustHave,
544 ActivePolicy->AttributesCantHave
545 ));
546 goto Exit;
547 }
548 }
549
550 //
551 // Lock policy check.
552 //
553 // Check for immediate lock.
554 if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_NOW) {
555 ReturnStatus = EFI_WRITE_PROTECTED;
556 goto Exit;
557 // Check for lock on create.
558 } else if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_CREATE) {
559 StateVarSize = 0;
560 Status = mGetVariableHelper (
561 VariableName,
562 VendorGuid,
563 NULL,
564 &StateVarSize,
565 NULL
566 );
567 if (Status == EFI_BUFFER_TOO_SMALL) {
568 ReturnStatus = EFI_WRITE_PROTECTED;
569 goto Exit;
570 }
571
572 // Check for lock on state variable.
573 } else if (ActivePolicy->LockPolicyType == VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE) {
574 StateVarPolicy = (VARIABLE_LOCK_ON_VAR_STATE_POLICY *)((UINT8 *)ActivePolicy + sizeof (VARIABLE_POLICY_ENTRY));
575 StateVarName = (CHAR16 *)((UINT8 *)StateVarPolicy + sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY));
576 StateVarSize = sizeof (StateVar);
577 Status = mGetVariableHelper (
578 StateVarName,
579 &StateVarPolicy->Namespace,
580 NULL,
581 &StateVarSize,
582 &StateVar
583 );
584
585 // If the variable was found, check the state. If matched, this variable is locked.
586 if (!EFI_ERROR (Status)) {
587 if (StateVar == StateVarPolicy->Value) {
588 ReturnStatus = EFI_WRITE_PROTECTED;
589 goto Exit;
590 }
591
592 // EFI_NOT_FOUND and EFI_BUFFER_TOO_SMALL indicate that the state doesn't match.
593 } else if ((Status != EFI_NOT_FOUND) && (Status != EFI_BUFFER_TOO_SMALL)) {
594 // We don't know what happened, but it isn't good.
595 ReturnStatus = EFI_ABORTED;
596 goto Exit;
597 }
598 }
599 }
600
601Exit:
602 DEBUG ((DEBUG_VERBOSE, "%a - Variable (%g:%s) returning %r.\n", __func__, VendorGuid, VariableName, ReturnStatus));
603 return ReturnStatus;
604}
605
618EFIAPI
619DisableVariablePolicy (
620 VOID
621 )
622{
623 if (!IsVariablePolicyLibInitialized ()) {
624 return EFI_NOT_READY;
625 }
626
627 if (mProtectionDisabled) {
628 return EFI_ALREADY_STARTED;
629 }
630
631 if (mInterfaceLocked) {
632 return EFI_WRITE_PROTECTED;
633 }
634
635 if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable)) {
636 return EFI_WRITE_PROTECTED;
637 }
638
639 mProtectionDisabled = TRUE;
640 return EFI_SUCCESS;
641}
642
660EFIAPI
661DumpVariablePolicy (
662 OUT UINT8 *Policy,
663 IN OUT UINT32 *Size
664 )
665{
666 if (!IsVariablePolicyLibInitialized ()) {
667 return EFI_NOT_READY;
668 }
669
670 // Check the parameters.
671 if ((Size == NULL) || ((*Size > 0) && (Policy == NULL))) {
672 return EFI_INVALID_PARAMETER;
673 }
674
675 // Make sure the size is sufficient to hold the policy table.
676 if (*Size < mCurrentTableUsage) {
677 *Size = mCurrentTableUsage;
678 return EFI_BUFFER_TOO_SMALL;
679 }
680
681 // If we're still here, copy the table and bounce.
682 CopyMem (Policy, mPolicyTable, mCurrentTableUsage);
683 *Size = mCurrentTableUsage;
684
685 return EFI_SUCCESS;
686}
687
731EFIAPI
732GetVariablePolicyInfo (
733 IN CONST CHAR16 *VariableName,
734 IN CONST EFI_GUID *VendorGuid,
735 IN OUT UINTN *VariablePolicyVariableNameBufferSize OPTIONAL,
736 OUT VARIABLE_POLICY_ENTRY *VariablePolicy,
737 OUT CHAR16 *VariablePolicyVariableName OPTIONAL
738 )
739{
740 EFI_STATUS Status;
741 UINT8 MatchPriority;
742 UINTN LocalVariablePolicyVariableNameBufferSize;
743 UINTN RequiredVariablePolicyVariableNameBufferSize;
744 VARIABLE_POLICY_ENTRY *MatchPolicy;
745
746 Status = EFI_SUCCESS;
747
748 if (!IsVariablePolicyLibInitialized ()) {
749 return EFI_NOT_READY;
750 }
751
752 if ((VariableName == NULL) || (VendorGuid == NULL) || (VariablePolicy == NULL)) {
753 return EFI_INVALID_PARAMETER;
754 }
755
756 MatchPolicy = GetBestPolicyMatch (
757 VariableName,
758 VendorGuid,
759 &MatchPriority
760 );
761 if (MatchPolicy != NULL) {
762 CopyMem (VariablePolicy, MatchPolicy, sizeof (*VariablePolicy));
763
764 if (VariablePolicyVariableNameBufferSize == NULL) {
765 if (VariablePolicyVariableName != NULL) {
766 return EFI_INVALID_PARAMETER;
767 }
768
769 return Status;
770 }
771
772 if (MatchPolicy->Size != MatchPolicy->OffsetToName) {
773 if (MatchPolicy->Size < MatchPolicy->OffsetToName) {
774 ASSERT (MatchPolicy->Size > MatchPolicy->OffsetToName);
775 return EFI_BAD_BUFFER_SIZE;
776 }
777
778 RequiredVariablePolicyVariableNameBufferSize = (UINTN)(MatchPolicy->Size - MatchPolicy->OffsetToName);
779 ASSERT (RequiredVariablePolicyVariableNameBufferSize > 0);
780
781 if (*VariablePolicyVariableNameBufferSize < RequiredVariablePolicyVariableNameBufferSize) {
782 // Let the caller get the size needed to hold the policy variable name
783 *VariablePolicyVariableNameBufferSize = RequiredVariablePolicyVariableNameBufferSize;
784 return EFI_BUFFER_TOO_SMALL;
785 }
786
787 if (VariablePolicyVariableName == NULL) {
788 // If the policy variable name size given is valid, then a valid policy variable name buffer should be provided
789 *VariablePolicyVariableNameBufferSize = RequiredVariablePolicyVariableNameBufferSize;
790 return EFI_INVALID_PARAMETER;
791 }
792
793 LocalVariablePolicyVariableNameBufferSize = *VariablePolicyVariableNameBufferSize;
794
795 // Actual string size should match expected string size
796 if (
797 ((StrnLenS (GET_POLICY_NAME (MatchPolicy), RequiredVariablePolicyVariableNameBufferSize) + 1) * sizeof (CHAR16))
798 != RequiredVariablePolicyVariableNameBufferSize)
799 {
800 ASSERT_EFI_ERROR (EFI_BAD_BUFFER_SIZE);
801 return EFI_BAD_BUFFER_SIZE;
802 }
803
804 *VariablePolicyVariableNameBufferSize = RequiredVariablePolicyVariableNameBufferSize;
805
806 Status = StrnCpyS (
807 VariablePolicyVariableName,
808 LocalVariablePolicyVariableNameBufferSize / sizeof (CHAR16),
809 GET_POLICY_NAME (MatchPolicy),
810 RequiredVariablePolicyVariableNameBufferSize / sizeof (CHAR16)
811 );
812 ASSERT_EFI_ERROR (Status);
813 } else {
814 // A variable policy variable name is not present. Return values according to interface.
815 *VariablePolicyVariableNameBufferSize = 0;
816 }
817
818 return Status;
819 }
820
821 return EFI_NOT_FOUND;
822}
823
870EFIAPI
871GetLockOnVariableStateVariablePolicyInfo (
872 IN CONST CHAR16 *VariableName,
873 IN CONST EFI_GUID *VendorGuid,
874 IN OUT UINTN *VariableLockPolicyVariableNameBufferSize OPTIONAL,
876 OUT CHAR16 *VariableLockPolicyVariableName OPTIONAL
877 )
878{
879 EFI_STATUS Status;
880 UINT8 MatchPriority;
881 UINTN RequiredVariablePolicyVariableNameBufferSize;
882 UINTN RequiredVariableLockPolicyVariableNameBufferSize;
883 UINTN LocalVariablePolicyLockVariableNameBufferSize;
884 UINTN LockOnVarStatePolicyEndOffset;
885 CHAR16 *LocalVariableLockPolicyVariableName;
886 VARIABLE_LOCK_ON_VAR_STATE_POLICY *LocalLockOnVarStatePolicy;
887 VARIABLE_POLICY_ENTRY *MatchPolicy;
888
889 Status = EFI_SUCCESS;
890
891 if (!IsVariablePolicyLibInitialized ()) {
892 return EFI_NOT_READY;
893 }
894
895 if ((VariableName == NULL) || (VendorGuid == NULL) || (VariablePolicy == NULL)) {
896 return EFI_INVALID_PARAMETER;
897 }
898
899 MatchPolicy = GetBestPolicyMatch (
900 VariableName,
901 VendorGuid,
902 &MatchPriority
903 );
904 if (MatchPolicy != NULL) {
905 if (MatchPolicy->LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE) {
906 return EFI_NOT_FOUND;
907 }
908
909 Status = SafeUintnAdd (
910 sizeof (VARIABLE_POLICY_ENTRY),
912 &LockOnVarStatePolicyEndOffset
913 );
914 if (EFI_ERROR (Status) || (LockOnVarStatePolicyEndOffset > (UINTN)MatchPolicy->Size)) {
915 return EFI_BAD_BUFFER_SIZE;
916 }
917
918 LocalLockOnVarStatePolicy = (VARIABLE_LOCK_ON_VAR_STATE_POLICY *)(MatchPolicy + 1);
919 CopyMem (VariablePolicy, LocalLockOnVarStatePolicy, sizeof (*LocalLockOnVarStatePolicy));
920
921 if (VariableLockPolicyVariableNameBufferSize == NULL) {
922 if (VariableLockPolicyVariableName != NULL) {
923 return EFI_INVALID_PARAMETER;
924 }
925
926 return Status;
927 }
928
929 // The name offset should be less than or equal to the total policy size.
930 if (MatchPolicy->Size < MatchPolicy->OffsetToName) {
931 return EFI_BAD_BUFFER_SIZE;
932 }
933
934 RequiredVariablePolicyVariableNameBufferSize = (UINTN)(MatchPolicy->Size - MatchPolicy->OffsetToName);
935 RequiredVariableLockPolicyVariableNameBufferSize = MatchPolicy->Size -
936 (LockOnVarStatePolicyEndOffset + RequiredVariablePolicyVariableNameBufferSize);
937
938 LocalVariablePolicyLockVariableNameBufferSize = *VariableLockPolicyVariableNameBufferSize;
939 *VariableLockPolicyVariableNameBufferSize = RequiredVariableLockPolicyVariableNameBufferSize;
940
941 if (LocalVariablePolicyLockVariableNameBufferSize < RequiredVariableLockPolicyVariableNameBufferSize) {
942 // Let the caller get the size needed to hold the policy variable name
943 return EFI_BUFFER_TOO_SMALL;
944 }
945
946 if (VariableLockPolicyVariableName == NULL) {
947 // If the policy variable name size given is valid, then a valid policy variable name buffer should be provided
948 return EFI_INVALID_PARAMETER;
949 }
950
951 if (RequiredVariableLockPolicyVariableNameBufferSize == 0) {
952 return Status;
953 }
954
955 LocalVariableLockPolicyVariableName = (CHAR16 *)((UINT8 *)LocalLockOnVarStatePolicy + sizeof (*LocalLockOnVarStatePolicy));
956 *VariableLockPolicyVariableNameBufferSize = RequiredVariableLockPolicyVariableNameBufferSize;
957
958 // Actual string size should match expected string size (if a variable name is present)
959 if (
960 (RequiredVariablePolicyVariableNameBufferSize > 0) &&
961 (((StrnLenS (GET_POLICY_NAME (MatchPolicy), RequiredVariablePolicyVariableNameBufferSize) + 1) * sizeof (CHAR16)) !=
962 RequiredVariablePolicyVariableNameBufferSize))
963 {
964 ASSERT_EFI_ERROR (EFI_BAD_BUFFER_SIZE);
965 return EFI_BAD_BUFFER_SIZE;
966 }
967
968 // Actual string size should match expected string size (if here, variable lock variable name is present)
969 if (
970 ((StrnLenS (LocalVariableLockPolicyVariableName, RequiredVariableLockPolicyVariableNameBufferSize) + 1) * sizeof (CHAR16)) !=
971 RequiredVariableLockPolicyVariableNameBufferSize)
972 {
973 ASSERT_EFI_ERROR (EFI_BAD_BUFFER_SIZE);
974 return EFI_BAD_BUFFER_SIZE;
975 }
976
977 Status = StrnCpyS (
978 VariableLockPolicyVariableName,
979 LocalVariablePolicyLockVariableNameBufferSize / sizeof (CHAR16),
980 LocalVariableLockPolicyVariableName,
981 RequiredVariableLockPolicyVariableNameBufferSize / sizeof (CHAR16)
982 );
983 ASSERT_EFI_ERROR (Status);
984
985 return Status;
986 }
987
988 return EFI_NOT_FOUND;
989}
990
1000BOOLEAN
1001EFIAPI
1002IsVariablePolicyEnabled (
1003 VOID
1004 )
1005{
1006 if (!IsVariablePolicyLibInitialized ()) {
1007 return FALSE;
1008 }
1009
1010 return !mProtectionDisabled;
1011}
1012
1022EFIAPI
1023LockVariablePolicy (
1024 VOID
1025 )
1026{
1027 if (!IsVariablePolicyLibInitialized ()) {
1028 return EFI_NOT_READY;
1029 }
1030
1031 if (mInterfaceLocked) {
1032 return EFI_WRITE_PROTECTED;
1033 }
1034
1035 mInterfaceLocked = TRUE;
1036 return EFI_SUCCESS;
1037}
1038
1048BOOLEAN
1049EFIAPI
1050IsVariablePolicyInterfaceLocked (
1051 VOID
1052 )
1053{
1054 if (!IsVariablePolicyLibInitialized ()) {
1055 return FALSE;
1056 }
1057
1058 return mInterfaceLocked;
1059}
1060
1076EFIAPI
1077InitVariablePolicyLib (
1078 IN EFI_GET_VARIABLE GetVariableHelper
1079 )
1080{
1081 EFI_STATUS Status;
1082
1083 Status = EFI_SUCCESS;
1084
1085 if (mGetVariableHelper != NULL) {
1086 return EFI_ALREADY_STARTED;
1087 }
1088
1089 if (!EFI_ERROR (Status)) {
1090 Status = VariablePolicyExtraInit ();
1091 }
1092
1093 if (!EFI_ERROR (Status)) {
1094 // Save an internal pointer to the GetVariableHelper.
1095 mGetVariableHelper = GetVariableHelper;
1096
1097 // Initialize the global state.
1098 mInterfaceLocked = FALSE;
1099 mProtectionDisabled = FALSE;
1100 mPolicyTable = NULL;
1101 mCurrentTableSize = 0;
1102 mCurrentTableUsage = 0;
1103 mCurrentTableCount = 0;
1104 }
1105
1106 return Status;
1107}
1108
1116BOOLEAN
1117EFIAPI
1118IsVariablePolicyLibInitialized (
1119 VOID
1120 )
1121{
1122 return (mGetVariableHelper != NULL);
1123}
1124
1135EFIAPI
1136DeinitVariablePolicyLib (
1137 VOID
1138 )
1139{
1140 EFI_STATUS Status;
1141
1142 Status = EFI_SUCCESS;
1143
1144 if (mGetVariableHelper == NULL) {
1145 return EFI_NOT_READY;
1146 }
1147
1148 if (!EFI_ERROR (Status)) {
1149 Status = VariablePolicyExtraDeinit ();
1150 }
1151
1152 if (!EFI_ERROR (Status)) {
1153 mGetVariableHelper = NULL;
1154 mInterfaceLocked = FALSE;
1155 mProtectionDisabled = FALSE;
1156 mCurrentTableSize = 0;
1157 mCurrentTableUsage = 0;
1158 mCurrentTableCount = 0;
1159
1160 if (mPolicyTable != NULL) {
1161 FreePool (mPolicyTable);
1162 mPolicyTable = NULL;
1163 }
1164 }
1165
1166 return Status;
1167}
UINT64 UINTN
UINTN EFIAPI StrnLenS(IN CONST CHAR16 *String, IN UINTN MaxSize)
Definition: SafeString.c:119
RETURN_STATUS EFIAPI StrnCpyS(OUT CHAR16 *Destination, IN UINTN DestMax, IN CONST CHAR16 *Source, IN UINTN Length)
Definition: SafeString.c:310
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
VOID EFIAPI FreePool(IN VOID *Buffer)
VOID *EFIAPI AllocateRuntimePool(IN UINTN AllocationSize)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define PcdGetBool(TokenName)
Definition: PcdLib.h:401
RETURN_STATUS EFIAPI SafeUintnAdd(IN UINTN Augend, IN UINTN Addend, OUT UINTN *Result)
Definition: SafeIntLib32.c:338
RETURN_STATUS EFIAPI SafeUint32Add(IN UINT32 Augend, IN UINT32 Addend, OUT UINT32 *Result)
Definition: SafeIntLib.c:2927
RETURN_STATUS EFIAPI SafeUint32Mult(IN UINT32 Multiplicand, IN UINT32 Multiplier, OUT UINT32 *Result)
Definition: SafeIntLib.c:3283
VOID EFIAPI Exit(IN EFI_STATUS Status)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_STATUS(EFIAPI * EFI_GET_VARIABLE)(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, OUT UINT32 *Attributes OPTIONAL, IN OUT UINTN *DataSize, OUT VOID *Data OPTIONAL)
Definition: UefiSpec.h:696
Definition: Base.h:213