/** @file -- VariablePolicyHelperLib.c This library contains helper functions for marshalling and registering new policies with the VariablePolicy infrastructure. This library is currently written against VariablePolicy revision 0x00010000. Copyright (c) Microsoft Corporation. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include /** This internal helper function populates the header structure, all common fields, and takes care of fix-ups. NOTE: Only use this internally. Assumes correctly-sized buffers. @param[out] EntPtr Pointer to the buffer to be populated. @param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect. @param[in] MinSize MinSize for the VariablePolicy. @param[in] MaxSize MaxSize for the VariablePolicy. @param[in] AttributesMustHave AttributesMustHave for the VariablePolicy. @param[in] AttributesCantHave AttributesCantHave for the VariablePolicy. @param[in] LockPolicyType LockPolicyType for the VariablePolicy. **/ STATIC VOID PopulateCommonData ( OUT VARIABLE_POLICY_ENTRY *EntPtr, IN CONST EFI_GUID *Namespace, IN UINT32 MinSize, IN UINT32 MaxSize, IN UINT32 AttributesMustHave, IN UINT32 AttributesCantHave, IN UINT8 LockPolicyType ) { EntPtr->Version = VARIABLE_POLICY_ENTRY_REVISION; CopyGuid (&EntPtr->Namespace, Namespace); EntPtr->MinSize = MinSize; EntPtr->MaxSize = MaxSize; EntPtr->AttributesMustHave = AttributesMustHave; EntPtr->AttributesCantHave = AttributesCantHave; EntPtr->LockPolicyType = LockPolicyType; // NOTE: As a heler, fix up MaxSize for compatibility with the old model. if (EntPtr->MaxSize == 0) { EntPtr->MaxSize = VARIABLE_POLICY_NO_MAX_SIZE; } return; } /** This helper function will allocate and populate a new VariablePolicy structure for a policy that does not contain any sub-structures (such as VARIABLE_LOCK_ON_VAR_STATE_POLICY). NOTE: Caller will need to free structure once finished. @param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect. @param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name. Otherwise, will create a policy that targets an entire namespace. @param[in] MinSize MinSize for the VariablePolicy. @param[in] MaxSize MaxSize for the VariablePolicy. @param[in] AttributesMustHave AttributesMustHave for the VariablePolicy. @param[in] AttributesCantHave AttributesCantHave for the VariablePolicy. @param[in] LockPolicyType LockPolicyType for the VariablePolicy. @param[out] NewEntry If successful, will be set to a pointer to the allocated buffer containing the new policy. @retval EFI_SUCCESS Operation completed successfully and structure is populated. @retval EFI_INVALID_PARAMETER Namespace is NULL. @retval EFI_INVALID_PARAMETER LockPolicyType is invalid for a basic structure. @retval EFI_BUFFER_TOO_SMALL Finished structure would not fit in UINT16 size. @retval EFI_OUT_OF_RESOURCES Could not allocate sufficient space for structure. **/ EFI_STATUS EFIAPI CreateBasicVariablePolicy ( IN CONST EFI_GUID *Namespace, IN CONST CHAR16 *Name OPTIONAL, IN UINT32 MinSize, IN UINT32 MaxSize, IN UINT32 AttributesMustHave, IN UINT32 AttributesCantHave, IN UINT8 LockPolicyType, OUT VARIABLE_POLICY_ENTRY **NewEntry ) { UINTN TotalSize; UINTN NameSize; VARIABLE_POLICY_ENTRY *EntPtr; CHAR16 *CopyName; // Check some initial invalid parameters for this function. if ((Namespace == NULL) || (NewEntry == NULL)) { return EFI_INVALID_PARAMETER; } if ((LockPolicyType != VARIABLE_POLICY_TYPE_NO_LOCK) && (LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_NOW) && (LockPolicyType != VARIABLE_POLICY_TYPE_LOCK_ON_CREATE)) { return EFI_INVALID_PARAMETER; } // // Set NameSize to suppress incorrect compiler/analyzer warnings // NameSize = 0; // Now we've gotta determine the total size of the buffer required for // the VariablePolicy structure. TotalSize = sizeof (VARIABLE_POLICY_ENTRY); if (Name != NULL) { NameSize = StrnSizeS (Name, MAX_UINT16); TotalSize += NameSize; } // Make sure the size fits within a VARIABLE_POLICY_ENTRY.Size. ASSERT (TotalSize <= MAX_UINT16); if (TotalSize > MAX_UINT16) { return EFI_BUFFER_TOO_SMALL; } // Allocate a buffer to hold all the data. We're on the home stretch. *NewEntry = AllocatePool (TotalSize); if (*NewEntry == NULL) { return EFI_OUT_OF_RESOURCES; } // If we're still here, we're basically done. // Copy the data and GET... OUT.... EntPtr = *NewEntry; PopulateCommonData ( EntPtr, Namespace, MinSize, MaxSize, AttributesMustHave, AttributesCantHave, LockPolicyType ); EntPtr->Size = (UINT16)TotalSize; // This is safe because we've already checked. EntPtr->OffsetToName = sizeof (VARIABLE_POLICY_ENTRY); if (Name != NULL) { CopyName = (CHAR16 *)((UINT8 *)EntPtr + EntPtr->OffsetToName); CopyMem (CopyName, Name, NameSize); } return EFI_SUCCESS; } /** This helper function will allocate and populate a new VariablePolicy structure for a policy with a lock type of VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE. NOTE: Caller will need to free structure once finished. @param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect. @param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name. Otherwise, will create a policy that targets an entire namespace. @param[in] MinSize MinSize for the VariablePolicy. @param[in] MaxSize MaxSize for the VariablePolicy. @param[in] AttributesMustHave AttributesMustHave for the VariablePolicy. @param[in] AttributesCantHave AttributesCantHave for the VariablePolicy. @param[in] VarStateNamespace Pointer to the EFI_GUID for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Namespace. @param[in] VarStateValue Value for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Value. @param[in] VarStateName Pointer to the CHAR16 array for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Name. @param[out] NewEntry If successful, will be set to a pointer to the allocated buffer containing the new policy. @retval EFI_SUCCESS Operation completed successfully and structure is populated. @retval EFI_INVALID_PARAMETER Namespace, VarStateNamespace, VarStateName is NULL. @retval EFI_BUFFER_TOO_SMALL Finished structure would not fit in UINT16 size. @retval EFI_OUT_OF_RESOURCES Could not allocate sufficient space for structure. **/ EFI_STATUS EFIAPI CreateVarStateVariablePolicy ( IN CONST EFI_GUID *Namespace, IN CONST CHAR16 *Name OPTIONAL, IN UINT32 MinSize, IN UINT32 MaxSize, IN UINT32 AttributesMustHave, IN UINT32 AttributesCantHave, IN CONST EFI_GUID *VarStateNamespace, IN UINT8 VarStateValue, IN CONST CHAR16 *VarStateName, OUT VARIABLE_POLICY_ENTRY **NewEntry ) { UINTN TotalSize; UINTN NameSize; UINTN VarStateNameSize; VARIABLE_POLICY_ENTRY *EntPtr; CHAR16 *CopyName; VARIABLE_LOCK_ON_VAR_STATE_POLICY *CopyPolicy; // Check some initial invalid parameters for this function. if ((Namespace == NULL) || (VarStateNamespace == NULL) || (VarStateName == NULL) || (NewEntry == NULL)) { return EFI_INVALID_PARAMETER; } // Now we've gotta determine the total size of the buffer required for // the VariablePolicy structure. VarStateNameSize = StrnSizeS (VarStateName, MAX_UINT16); TotalSize = sizeof (VARIABLE_POLICY_ENTRY) + sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY) + VarStateNameSize; if (Name != NULL) { NameSize = StrnSizeS (Name, MAX_UINT16); TotalSize += NameSize; } // Make sure the size fits within a VARIABLE_POLICY_ENTRY.Size. ASSERT (TotalSize <= MAX_UINT16); if (TotalSize > MAX_UINT16) { return EFI_BUFFER_TOO_SMALL; } // Allocate a buffer to hold all the data. We're on the home stretch. *NewEntry = AllocatePool (TotalSize); if (*NewEntry == NULL) { return EFI_OUT_OF_RESOURCES; } // If we're still here, we're basically done. // Copy the data and GET... OUT.... EntPtr = *NewEntry; PopulateCommonData ( EntPtr, Namespace, MinSize, MaxSize, AttributesMustHave, AttributesCantHave, VARIABLE_POLICY_TYPE_LOCK_ON_VAR_STATE ); EntPtr->Size = (UINT16)TotalSize; // This is safe because we've already checked. EntPtr->OffsetToName = sizeof (VARIABLE_POLICY_ENTRY) + sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY) + (UINT16)VarStateNameSize; CopyPolicy = (VARIABLE_LOCK_ON_VAR_STATE_POLICY *)((UINT8 *)EntPtr + sizeof (VARIABLE_POLICY_ENTRY)); CopyName = (CHAR16 *)((UINT8 *)CopyPolicy + sizeof (VARIABLE_LOCK_ON_VAR_STATE_POLICY)); CopyGuid (&CopyPolicy->Namespace, VarStateNamespace); CopyPolicy->Value = VarStateValue; CopyMem (CopyName, VarStateName, VarStateNameSize); if (Name != NULL) { CopyName = (CHAR16 *)((UINT8 *)EntPtr + EntPtr->OffsetToName); CopyMem (CopyName, Name, NameSize); } return EFI_SUCCESS; } /** This helper function does everything that CreateBasicVariablePolicy() does, but also uses the passed in protocol to register the policy with the infrastructure. Does not return a buffer, does not require the caller to free anything. @param[in] VariablePolicy Pointer to a valid instance of the VariablePolicy protocol. @param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect. @param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name. Otherwise, will create a policy that targets an entire namespace. @param[in] MinSize MinSize for the VariablePolicy. @param[in] MaxSize MaxSize for the VariablePolicy. @param[in] AttributesMustHave AttributesMustHave for the VariablePolicy. @param[in] AttributesCantHave AttributesCantHave for the VariablePolicy. @param[in] LockPolicyType LockPolicyType for the VariablePolicy. @retval EFI_INVALID_PARAMETER VariablePolicy pointer is NULL. @retval EFI_STATUS Status returned by CreateBasicVariablePolicy() or RegisterVariablePolicy(). **/ EFI_STATUS EFIAPI RegisterBasicVariablePolicy ( IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy, IN CONST EFI_GUID *Namespace, IN CONST CHAR16 *Name OPTIONAL, IN UINT32 MinSize, IN UINT32 MaxSize, IN UINT32 AttributesMustHave, IN UINT32 AttributesCantHave, IN UINT8 LockPolicyType ) { VARIABLE_POLICY_ENTRY *NewEntry; EFI_STATUS Status; // Check the simple things. if (VariablePolicy == NULL) { return EFI_INVALID_PARAMETER; } // Create the new entry and make sure that everything worked. NewEntry = NULL; Status = CreateBasicVariablePolicy ( Namespace, Name, MinSize, MaxSize, AttributesMustHave, AttributesCantHave, LockPolicyType, &NewEntry ); // If that was successful, attempt to register the new policy. if (!EFI_ERROR (Status)) { Status = VariablePolicy->RegisterVariablePolicy (NewEntry); } // If we allocated the buffer, free the buffer. if (NewEntry != NULL) { FreePool (NewEntry); } return Status; } /** This helper function does everything that CreateBasicVariablePolicy() does, but also uses the passed in protocol to register the policy with the infrastructure. Does not return a buffer, does not require the caller to free anything. @param[in] VariablePolicy Pointer to a valid instance of the VariablePolicy protocol. @param[in] Namespace Pointer to an EFI_GUID for the target variable namespace that this policy will protect. @param[in] Name [Optional] If provided, a pointer to the CHAR16 array for the target variable name. Otherwise, will create a policy that targets an entire namespace. @param[in] MinSize MinSize for the VariablePolicy. @param[in] MaxSize MaxSize for the VariablePolicy. @param[in] AttributesMustHave AttributesMustHave for the VariablePolicy. @param[in] AttributesCantHave AttributesCantHave for the VariablePolicy. @param[in] VarStateNamespace Pointer to the EFI_GUID for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Namespace. @param[in] VarStateName Pointer to the CHAR16 array for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Name. @param[in] VarStateValue Value for the VARIABLE_LOCK_ON_VAR_STATE_POLICY.Value. @retval EFI_INVALID_PARAMETER VariablePolicy pointer is NULL. @retval EFI_STATUS Status returned by CreateBasicVariablePolicy() or RegisterVariablePolicy(). **/ EFI_STATUS EFIAPI RegisterVarStateVariablePolicy ( IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy, IN CONST EFI_GUID *Namespace, IN CONST CHAR16 *Name OPTIONAL, IN UINT32 MinSize, IN UINT32 MaxSize, IN UINT32 AttributesMustHave, IN UINT32 AttributesCantHave, IN CONST EFI_GUID *VarStateNamespace, IN CONST CHAR16 *VarStateName, IN UINT8 VarStateValue ) { VARIABLE_POLICY_ENTRY *NewEntry; EFI_STATUS Status; // Check the simple things. if (VariablePolicy == NULL) { return EFI_INVALID_PARAMETER; } // Create the new entry and make sure that everything worked. NewEntry = NULL; Status = CreateVarStateVariablePolicy ( Namespace, Name, MinSize, MaxSize, AttributesMustHave, AttributesCantHave, VarStateNamespace, VarStateValue, VarStateName, &NewEntry ); // If that was successful, attempt to register the new policy. if (!EFI_ERROR (Status)) { Status = VariablePolicy->RegisterVariablePolicy (NewEntry); } // If we allocated the buffer, free the buffer. if (NewEntry != NULL) { FreePool (NewEntry); } return Status; }