1 comment inline, please check.


Thanks,
Dandan
> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Bret
> Barkelew
> Sent: Tuesday, June 23, 2020 2:41 PM
> To: devel@edk2.groups.io
> Cc: Wang, Jian J <jian.j.w...@intel.com>; Wu, Hao A <hao.a...@intel.com>;
> Gao, Liming <liming....@intel.com>
> Subject: [edk2-devel] [PATCH v6 09/14] MdeModulePkg: Connect
> VariablePolicy business logic to VariableServices
> 
> https://bugzilla.tianocore.org/show_bug.cgi?id=2522
> 
> VariablePolicy is an updated interface to
> replace VarLock and VarCheckProtocol.
> 
> Add connective code to publish the VariablePolicy protocol
> and wire it to either the SMM communication interface
> or directly into the VariablePolicyLib business logic.
> 
> Cc: Jian J Wang <jian.j.w...@intel.com>
> Cc: Hao A Wu <hao.a...@intel.com>
> Cc: Liming Gao <liming....@intel.com>
> Cc: Bret Barkelew <brbar...@microsoft.com>
> Signed-off-by: Bret Barkelew <brbar...@microsoft.com>
> ---
>  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c             |  53
> ++
>  MdeModulePkg/Universal/Variable/RuntimeDxe/VariablePolicySmmDxe.c
> | 642 ++++++++++++++++++++
> 
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.
> c   |  14 +
>  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> |   2 +
>  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf           |   3
> +
> 
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.i
> nf |  10 +
>  6 files changed, 724 insertions(+)
> 
> diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> index 7d2b6c8e1fad..d404d4763e54 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c
> @@ -5,18 +5,34 @@
>  Copyright (C) 2013, Red Hat, Inc.
> 
>  Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> 
>  (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
> 
> +Copyright (c) Microsoft Corporation.
> 
>  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> 
> 
>  **/
> 
> 
> 
>  #include "Variable.h"
> 
> 
> 
> +#include <Protocol/VariablePolicy.h>
> 
> +#include <Library/VariablePolicyLib.h>
> 
> +
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +ProtocolIsVariablePolicyEnabled (
> 
> +  OUT BOOLEAN *State
> 
> +  );
> 
> +
> 
>  EFI_HANDLE                          mHandle                    = NULL;
> 
>  EFI_EVENT                           mVirtualAddressChangeEvent = NULL;
> 
>  VOID                                *mFtwRegistration          = NULL;
> 
>  VOID                                ***mVarCheckAddressPointer = NULL;
> 
>  UINTN                               mVarCheckAddressPointerCount = 0;
> 
>  EDKII_VARIABLE_LOCK_PROTOCOL        mVariableLock              =
> { VariableLockRequestToLock };
> 
> +EDKII_VARIABLE_POLICY_PROTOCOL      mVariablePolicyProtocol    =
> { EDKII_VARIABLE_POLICY_PROTOCOL_REVISION,
> 
> +                                                                    
> DisableVariablePolicy,
> 
> +                                                                    
> ProtocolIsVariablePolicyEnabled,
> 
> +                                                                    
> RegisterVariablePolicy,
> 
> +                                                                    
> DumpVariablePolicy,
> 
> +                                                                    
> LockVariablePolicy };
> 
>  EDKII_VAR_CHECK_PROTOCOL            mVarCheck                  =
> { VarCheckRegisterSetVariableCheckHandler,
> 
>                                                                      
> VarCheckVariablePropertySet,
> 
>                                                                      
> VarCheckVariablePropertyGet };
> 
> @@ -303,6 +319,8 @@ OnReadyToBoot (
>      }
> 
>    }
> 
> 
> 
> +  ASSERT_EFI_ERROR (LockVariablePolicy ());
> 
> +
> 
>    gBS->CloseEvent (Event);
> 
>  }
> 
> 
> 
> @@ -466,6 +484,28 @@ FtwNotificationEvent (
>  }
> 
> 
> 
> 
> 
> +/**
> 
> +  This API function returns whether or not the policy engine is
> 
> +  currently being enforced.
> 
> +
> 
> +  @param[out]   State       Pointer to a return value for whether the policy
> enforcement
> 
> +                            is currently enabled.
> 
> +
> 
> +  @retval     EFI_SUCCESS
> 
> +  @retval     Others        An error has prevented this command from
> completing.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +ProtocolIsVariablePolicyEnabled (
> 
> +  OUT BOOLEAN *State
> 
> +  )
> 
> +{
> 
> +  *State = IsVariablePolicyEnabled ();
> 
> +  return EFI_SUCCESS;
> 
> +}

1. [Dandan]: I see other APIs in the VariablePolicyProtocol are using the APIs 
in VariablePolicyLib directly, expect this one.
Could we make the IsVariablePolicyEnabled API aligned in protocol and Lib?

> 
> +
> 
> +
> 
>  /**
> 
>    Variable Driver main entry point. The Variable driver places the 4 EFI
> 
>    runtime services in the EFI System Table and installs arch protocols
> 
> @@ -576,6 +616,19 @@ VariableServiceInitialize (
>                    );
> 
>    ASSERT_EFI_ERROR (Status);
> 
> 
> 
> +  // Register and initialize the VariablePolicy engine.
> 
> +  Status = InitVariablePolicyLib (VariableServiceGetVariable);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +  Status = VarCheckRegisterSetVariableCheckHandler (ValidateSetVariable);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> 
> +                    &mHandle,
> 
> +                    &gEdkiiVariablePolicyProtocolGuid,
> 
> +                    &mVariablePolicyProtocol,
> 
> +                    NULL
> 
> +                    );
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
>    return EFI_SUCCESS;
> 
>  }
> 
> 
> 
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariablePolicySmmDxe.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariablePolicySmmDxe.c
> new file mode 100644
> index 000000000000..e2d4cf4cec1a
> --- /dev/null
> +++
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariablePolicySmmDxe.c
> @@ -0,0 +1,642 @@
> +/** @file -- VariablePolicySmmDxe.c
> 
> +This protocol allows communication with Variable Policy Engine.
> 
> +
> 
> +Copyright (c) Microsoft Corporation.
> 
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +
> 
> +**/
> 
> +
> 
> +#include <Library/BaseLib.h>
> 
> +#include <Library/UefiLib.h>
> 
> +#include <Library/DebugLib.h>
> 
> +#include <Library/SafeIntLib.h>
> 
> +#include <Library/UefiBootServicesTableLib.h>
> 
> +#include <Library/BaseMemoryLib.h>
> 
> +#include <Library/MemoryAllocationLib.h>
> 
> +
> 
> +#include <Protocol/VariablePolicy.h>
> 
> +#include <Protocol/MmCommunication2.h>
> 
> +
> 
> +#include <Guid/VarCheckPolicyMmi.h>
> 
> +
> 
> +#include "Variable.h"
> 
> +
> 
> +EDKII_VARIABLE_POLICY_PROTOCOL  mVariablePolicyProtocol;
> 
> +EFI_MM_COMMUNICATION2_PROTOCOL  *mMmCommunication;
> 
> +
> 
> +VOID      *mMmCommunicationBuffer;
> 
> +UINTN     mMmCommunicationBufferSize;
> 
> +EFI_LOCK  mMmCommunicationLock;
> 
> +
> 
> +/**
> 
> +  Internal helper function to consolidate communication method.
> 
> +
> 
> +  @param[in,out]  CommBuffer
> 
> +  @param[in,out]  CommSize    Size of the CommBuffer.
> 
> +
> 
> +  @retval   EFI_STATUS    Result from communication method.
> 
> +
> 
> +**/
> 
> +STATIC
> 
> +EFI_STATUS
> 
> +InternalMmCommunicate (
> 
> +  IN OUT VOID             *CommBuffer,
> 
> +  IN OUT UINTN            *CommSize
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS    Status;
> 
> +  if (CommBuffer == NULL || CommSize == NULL) {
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +  Status = mMmCommunication->Communicate (mMmCommunication,
> CommBuffer, CommBuffer, CommSize);
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  This API function disables the variable policy enforcement. If it's
> 
> +  already been called once, will return EFI_ALREADY_STARTED.
> 
> +
> 
> +  @retval     EFI_SUCCESS
> 
> +  @retval     EFI_ALREADY_STARTED   Has already been called once this boot.
> 
> +  @retval     EFI_WRITE_PROTECTED   Interface has been locked until reboot.
> 
> +  @retval     EFI_WRITE_PROTECTED   Interface option is disabled by platform
> PCD.
> 
> +
> 
> +**/
> 
> +STATIC
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +ProtocolDisableVariablePolicy (
> 
> +  VOID
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  EFI_MM_COMMUNICATE_HEADER     *CommHeader;
> 
> +  VAR_CHECK_POLICY_COMM_HEADER  *PolicyHeader;
> 
> +  UINTN                         BufferSize;
> 
> +
> 
> +  // Check the PCD for convenience.
> 
> +  // This would also be rejected by the lib, but why go to MM if we don't
> have to?
> 
> +  if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable)) {
> 
> +    return EFI_WRITE_PROTECTED;
> 
> +  }
> 
> +
> 
> +  AcquireLockOnlyAtBootTime (&mMmCommunicationLock);
> 
> +
> 
> +  // Set up the MM communication.
> 
> +  BufferSize    = mMmCommunicationBufferSize;
> 
> +  CommHeader    = mMmCommunicationBuffer;
> 
> +  PolicyHeader  = (VAR_CHECK_POLICY_COMM_HEADER*)&CommHeader-
> >Data;
> 
> +  CopyGuid( &CommHeader->HeaderGuid,
> &gVarCheckPolicyLibMmiHandlerGuid );
> 
> +  CommHeader->MessageLength = BufferSize;
> 
> +  PolicyHeader->Signature   = VAR_CHECK_POLICY_COMM_SIG;
> 
> +  PolicyHeader->Revision    = VAR_CHECK_POLICY_COMM_REVISION;
> 
> +  PolicyHeader->Command     = VAR_CHECK_POLICY_COMMAND_DISABLE;
> 
> +
> 
> +  Status = InternalMmCommunicate (CommHeader, &BufferSize);
> 
> +  DEBUG(( DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n",
> __FUNCTION__, Status ));
> 
> +
> 
> +  ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);
> 
> +
> 
> +  return (EFI_ERROR( Status )) ? Status : PolicyHeader->Result;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  This API function returns whether or not the policy engine is
> 
> +  currently being enforced.
> 
> +
> 
> +  @param[out]   State       Pointer to a return value for whether the policy
> enforcement
> 
> +                            is currently enabled.
> 
> +
> 
> +  @retval     EFI_SUCCESS
> 
> +  @retval     Others        An error has prevented this command from
> completing.
> 
> +
> 
> +**/
> 
> +STATIC
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +ProtocolIsVariablePolicyEnabled (
> 
> +  OUT BOOLEAN     *State
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                                Status;
> 
> +  EFI_MM_COMMUNICATE_HEADER                 *CommHeader;
> 
> +  VAR_CHECK_POLICY_COMM_HEADER              *PolicyHeader;
> 
> +  VAR_CHECK_POLICY_COMM_IS_ENABLED_PARAMS   *CommandParams;
> 
> +  UINTN                                     BufferSize;
> 
> +
> 
> +  if (State == NULL) {
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +
> 
> +  AcquireLockOnlyAtBootTime (&mMmCommunicationLock);
> 
> +
> 
> +  // Set up the MM communication.
> 
> +  BufferSize    = mMmCommunicationBufferSize;
> 
> +  CommHeader    = mMmCommunicationBuffer;
> 
> +  PolicyHeader  = (VAR_CHECK_POLICY_COMM_HEADER*)&CommHeader-
> >Data;
> 
> +  CommandParams =
> (VAR_CHECK_POLICY_COMM_IS_ENABLED_PARAMS*)(PolicyHeader + 1);
> 
> +  CopyGuid( &CommHeader->HeaderGuid,
> &gVarCheckPolicyLibMmiHandlerGuid );
> 
> +  CommHeader->MessageLength = BufferSize;
> 
> +  PolicyHeader->Signature   = VAR_CHECK_POLICY_COMM_SIG;
> 
> +  PolicyHeader->Revision    = VAR_CHECK_POLICY_COMM_REVISION;
> 
> +  PolicyHeader->Command     =
> VAR_CHECK_POLICY_COMMAND_IS_ENABLED;
> 
> +
> 
> +  Status = InternalMmCommunicate (CommHeader, &BufferSize);
> 
> +  DEBUG(( DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n",
> __FUNCTION__, Status ));
> 
> +
> 
> +  if (!EFI_ERROR( Status )) {
> 
> +    Status = PolicyHeader->Result;
> 
> +    *State = CommandParams->State;
> 
> +  }
> 
> +
> 
> +  ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  This API function validates and registers a new policy with
> 
> +  the policy enforcement engine.
> 
> +
> 
> +  @param[in]  NewPolicy     Pointer to the incoming policy structure.
> 
> +
> 
> +  @retval     EFI_SUCCESS
> 
> +  @retval     EFI_INVALID_PARAMETER   NewPolicy is NULL or is internally
> inconsistent.
> 
> +  @retval     EFI_ALREADY_STARTED     An identical matching policy already
> exists.
> 
> +  @retval     EFI_WRITE_PROTECTED     The interface has been locked until
> the next reboot.
> 
> +  @retval     EFI_UNSUPPORTED         Policy enforcement has been disabled.
> No reason to add more policies.
> 
> +  @retval     EFI_ABORTED             A calculation error has prevented this
> function from completing.
> 
> +  @retval     EFI_OUT_OF_RESOURCES    Cannot grow the table to hold any
> more policies.
> 
> +
> 
> +**/
> 
> +STATIC
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +ProtocolRegisterVariablePolicy (
> 
> +  IN CONST VARIABLE_POLICY_ENTRY    *NewPolicy
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                                Status;
> 
> +  EFI_MM_COMMUNICATE_HEADER                 *CommHeader;
> 
> +  VAR_CHECK_POLICY_COMM_HEADER              *PolicyHeader;
> 
> +  VOID                                      *PolicyBuffer;
> 
> +  UINTN                                     BufferSize;
> 
> +  UINTN                                     RequiredSize;
> 
> +
> 
> +  if (NewPolicy == NULL) {
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +
> 
> +  // First, make sure that the required size does not exceed the capabilities
> 
> +  // of the MmCommunication buffer.
> 
> +  RequiredSize = OFFSET_OF(EFI_MM_COMMUNICATE_HEADER, Data) +
> sizeof(VAR_CHECK_POLICY_COMM_HEADER);
> 
> +  Status = SafeUintnAdd( RequiredSize, NewPolicy->Size, &RequiredSize );
> 
> +  if (EFI_ERROR( Status ) || RequiredSize > mMmCommunicationBufferSize)
> {
> 
> +    DEBUG(( DEBUG_ERROR, "%a - Policy too large for buffer! %r, %d > %d
> \n", __FUNCTION__,
> 
> +            Status, RequiredSize, mMmCommunicationBufferSize ));
> 
> +    return EFI_OUT_OF_RESOURCES;
> 
> +  }
> 
> +
> 
> +  AcquireLockOnlyAtBootTime (&mMmCommunicationLock);
> 
> +
> 
> +  // Set up the MM communication.
> 
> +  BufferSize    = mMmCommunicationBufferSize;
> 
> +  CommHeader    = mMmCommunicationBuffer;
> 
> +  PolicyHeader  = (VAR_CHECK_POLICY_COMM_HEADER*)&CommHeader-
> >Data;
> 
> +  PolicyBuffer  = (VOID*)(PolicyHeader + 1);
> 
> +  CopyGuid( &CommHeader->HeaderGuid,
> &gVarCheckPolicyLibMmiHandlerGuid );
> 
> +  CommHeader->MessageLength = BufferSize;
> 
> +  PolicyHeader->Signature   = VAR_CHECK_POLICY_COMM_SIG;
> 
> +  PolicyHeader->Revision    = VAR_CHECK_POLICY_COMM_REVISION;
> 
> +  PolicyHeader->Command     = VAR_CHECK_POLICY_COMMAND_REGISTER;
> 
> +
> 
> +  // Copy the policy into place. This copy is safe because we've already
> tested above.
> 
> +  CopyMem( PolicyBuffer, NewPolicy, NewPolicy->Size );
> 
> +
> 
> +  Status = InternalMmCommunicate (CommHeader, &BufferSize);
> 
> +  DEBUG(( DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n",
> __FUNCTION__, Status ));
> 
> +
> 
> +  ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);
> 
> +
> 
> +  return (EFI_ERROR( Status )) ? Status : PolicyHeader->Result;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  This helper function takes care of the overhead of formatting, sending,
> and interpreting
> 
> +  the results for a single DumpVariablePolicy request.
> 
> +
> 
> +  @param[in]      PageRequested   The page of the paginated results from
> MM. 0 for metadata.
> 
> +  @param[out]     TotalSize       The total size of the entire buffer. 
> Returned as
> part of metadata.
> 
> +  @param[out]     PageSize        The size of the current page being 
> returned.
> Not valid as part of metadata.
> 
> +  @param[out]     HasMore         A flag indicating whether there are more
> pages after this one.
> 
> +  @param[out]     Buffer          The start of the current page from MM.
> 
> +
> 
> +  @retval     EFI_SUCCESS             Output params have been updated (either
> metadata or dump page).
> 
> +  @retval     EFI_INVALID_PARAMETER   One of the output params is NULL.
> 
> +  @retval     Others                  Response from MM handler.
> 
> +
> 
> +**/
> 
> +STATIC
> 
> +EFI_STATUS
> 
> +DumpVariablePolicyHelper (
> 
> +  IN  UINT32        PageRequested,
> 
> +  OUT UINT32        *TotalSize,
> 
> +  OUT UINT32        *PageSize,
> 
> +  OUT BOOLEAN       *HasMore,
> 
> +  OUT UINT8         **Buffer
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                              Status;
> 
> +  EFI_MM_COMMUNICATE_HEADER               *CommHeader;
> 
> +  VAR_CHECK_POLICY_COMM_HEADER            *PolicyHeader;
> 
> +  VAR_CHECK_POLICY_COMM_DUMP_PARAMS       *CommandParams;
> 
> +  UINTN                                   BufferSize;
> 
> +
> 
> +  if (TotalSize == NULL || PageSize == NULL || HasMore == NULL || Buffer
> == NULL) {
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +
> 
> +  // Set up the MM communication.
> 
> +  BufferSize    = mMmCommunicationBufferSize;
> 
> +  CommHeader    = mMmCommunicationBuffer;
> 
> +  PolicyHeader  = (VAR_CHECK_POLICY_COMM_HEADER*)&CommHeader-
> >Data;
> 
> +  CommandParams =
> (VAR_CHECK_POLICY_COMM_DUMP_PARAMS*)(PolicyHeader + 1);
> 
> +  CopyGuid( &CommHeader->HeaderGuid,
> &gVarCheckPolicyLibMmiHandlerGuid );
> 
> +  CommHeader->MessageLength = BufferSize;
> 
> +  PolicyHeader->Signature   = VAR_CHECK_POLICY_COMM_SIG;
> 
> +  PolicyHeader->Revision    = VAR_CHECK_POLICY_COMM_REVISION;
> 
> +  PolicyHeader->Command     = VAR_CHECK_POLICY_COMMAND_DUMP;
> 
> +
> 
> +  CommandParams->PageRequested = PageRequested;
> 
> +
> 
> +  Status = InternalMmCommunicate (CommHeader, &BufferSize);
> 
> +  DEBUG(( DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n",
> __FUNCTION__, Status ));
> 
> +
> 
> +  if (!EFI_ERROR( Status )) {
> 
> +    Status = PolicyHeader->Result;
> 
> +    *TotalSize = CommandParams->TotalSize;
> 
> +    *PageSize = CommandParams->PageSize;
> 
> +    *HasMore = CommandParams->HasMore;
> 
> +    *Buffer = (UINT8*)(CommandParams + 1);
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  This API function will dump the entire contents of the variable policy 
> table.
> 
> +
> 
> +  Similar to GetVariable, the first call can be made with a 0 size and it 
> will
> return
> 
> +  the size of the buffer required to hold the entire table.
> 
> +
> 
> +  @param[out]     Policy  Pointer to the policy buffer. Can be NULL if Size 
> is 0.
> 
> +  @param[in,out]  Size    On input, the size of the output buffer. On output,
> the size
> 
> +                          of the data returned.
> 
> +
> 
> +  @retval     EFI_SUCCESS             Policy data is in the output buffer 
> and Size
> has been updated.
> 
> +  @retval     EFI_INVALID_PARAMETER   Size is NULL, or Size is non-zero and
> Policy is NULL.
> 
> +  @retval     EFI_BUFFER_TOO_SMALL    Size is insufficient to hold policy. 
> Size
> updated with required size.
> 
> +
> 
> +**/
> 
> +STATIC
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +ProtocolDumpVariablePolicy (
> 
> +  OUT UINT8             *Policy OPTIONAL,
> 
> +  IN OUT UINT32         *Size
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS    Status;
> 
> +  UINT8         *Source;
> 
> +  UINT8         *Destination;
> 
> +  UINT32        PolicySize;
> 
> +  UINT32        PageSize;
> 
> +  BOOLEAN       HasMore;
> 
> +  UINT32        PageIndex;
> 
> +
> 
> +  if (Size == NULL || (*Size > 0 && Policy == NULL)) {
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +
> 
> +  AcquireLockOnlyAtBootTime (&mMmCommunicationLock);
> 
> +
> 
> +  // Repeat this whole process until we either have a failure case or get the
> entire buffer.
> 
> +  do {
> 
> +    // First, we must check the zero page to determine the buffer size and
> 
> +    // reset the internal state.
> 
> +    PolicySize = 0;
> 
> +    PageSize = 0;
> 
> +    HasMore = FALSE;
> 
> +    Status = DumpVariablePolicyHelper (0, &PolicySize, &PageSize, &HasMore,
> &Source);
> 
> +    if (EFI_ERROR (Status)) {
> 
> +      break;
> 
> +    }
> 
> +
> 
> +    // If we're good, we can at least check the required size now.
> 
> +    if (*Size < PolicySize) {
> 
> +      *Size = PolicySize;
> 
> +      Status = EFI_BUFFER_TOO_SMALL;
> 
> +      break;
> 
> +    }
> 
> +
> 
> +    // On further thought, let's update the size either way.
> 
> +    *Size = PolicySize;
> 
> +    // And get ready to ROCK.
> 
> +    Destination = Policy;
> 
> +
> 
> +    // Keep looping and copying until we're either done or freak out.
> 
> +    for (PageIndex = 1; !EFI_ERROR (Status) && HasMore && PageIndex <
> MAX_UINT32; PageIndex++) {
> 
> +      Status = DumpVariablePolicyHelper (PageIndex, &PolicySize, &PageSize,
> &HasMore, &Source);
> 
> +      if (!EFI_ERROR (Status)) {
> 
> +        CopyMem (Destination, Source, PageSize);
> 
> +        Destination += PageSize;
> 
> +      }
> 
> +    }
> 
> +
> 
> +    // Next, we check to see whether
> 
> +  } while (Status == EFI_TIMEOUT);
> 
> +
> 
> +  ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);
> 
> +
> 
> +  // There's currently no use for this, but it shouldn't be hard to 
> implement.
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  This API function locks the interface so that no more policy updates
> 
> +  can be performed or changes made to the enforcement until the next
> boot.
> 
> +
> 
> +  @retval     EFI_SUCCESS
> 
> +  @retval     Others        An error has prevented this command from
> completing.
> 
> +
> 
> +**/
> 
> +STATIC
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +ProtocolLockVariablePolicy (
> 
> +  VOID
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                    Status;
> 
> +  EFI_MM_COMMUNICATE_HEADER     *CommHeader;
> 
> +  VAR_CHECK_POLICY_COMM_HEADER  *PolicyHeader;
> 
> +  UINTN                         BufferSize;
> 
> +
> 
> +  AcquireLockOnlyAtBootTime (&mMmCommunicationLock);
> 
> +
> 
> +  // Set up the MM communication.
> 
> +  BufferSize    = mMmCommunicationBufferSize;
> 
> +  CommHeader    = mMmCommunicationBuffer;
> 
> +  PolicyHeader  = (VAR_CHECK_POLICY_COMM_HEADER*)&CommHeader-
> >Data;
> 
> +  CopyGuid( &CommHeader->HeaderGuid,
> &gVarCheckPolicyLibMmiHandlerGuid );
> 
> +  CommHeader->MessageLength = BufferSize;
> 
> +  PolicyHeader->Signature   = VAR_CHECK_POLICY_COMM_SIG;
> 
> +  PolicyHeader->Revision    = VAR_CHECK_POLICY_COMM_REVISION;
> 
> +  PolicyHeader->Command     = VAR_CHECK_POLICY_COMMAND_LOCK;
> 
> +
> 
> +  Status = InternalMmCommunicate (CommHeader, &BufferSize);
> 
> +  DEBUG(( DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n",
> __FUNCTION__, Status ));
> 
> +
> 
> +  ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);
> 
> +
> 
> +  return (EFI_ERROR( Status )) ? Status : PolicyHeader->Result;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  This helper function locates the shared comm buffer and assigns it to input
> pointers.
> 
> +
> 
> +  @param[in,out]  BufferSize      On input, the minimum buffer size required
> INCLUDING the MM communicate header.
> 
> +                                  On output, the size of the matching buffer 
> found.
> 
> +  @param[out]     LocatedBuffer   A pointer to the matching buffer.
> 
> +
> 
> +  @retval     EFI_SUCCESS
> 
> +  @retval     EFI_INVALID_PARAMETER   One of the output pointers was
> NULL.
> 
> +  @retval     EFI_OUT_OF_RESOURCES    Not enough memory to allocate a
> comm buffer.
> 
> +
> 
> +**/
> 
> +STATIC
> 
> +EFI_STATUS
> 
> +InitMmCommonCommBuffer (
> 
> +  IN OUT  UINTN       *BufferSize,
> 
> +  OUT     VOID        **LocatedBuffer
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS                  Status;
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +
> 
> +  // Make sure that we're working with good pointers.
> 
> +  if (BufferSize == NULL || LocatedBuffer == NULL) {
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +
> 
> +  // Allocate the runtime memory for the comm buffer.
> 
> +  *LocatedBuffer = AllocateRuntimePool (*BufferSize);
> 
> +  if (*LocatedBuffer == NULL) {
> 
> +    Status = EFI_OUT_OF_RESOURCES;
> 
> +    *BufferSize = 0;
> 
> +  }
> 
> +
> 
> +  EfiInitializeLock (&mMmCommunicationLock, TPL_NOTIFY);
> 
> +
> 
> +  return Status;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  This helper is responsible for telemetry and any other actions that
> 
> +  need to be taken if the VariablePolicy fails to lock.
> 
> +
> 
> +  NOTE: It's possible that parts of this handling will need to become
> 
> +        part of a platform policy.
> 
> +
> 
> +  @param[in]  FailureStatus   The failure that was reported by
> LockVariablePolicy
> 
> +
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +VariablePolicyHandleFailureToLock (
> 
> +  IN  EFI_STATUS      FailureStatus
> 
> +  )
> 
> +{
> 
> +  // For now, there's no agreed-upon policy for this.
> 
> +  return;
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  ReadyToBoot Callback
> 
> +  Lock the VariablePolicy interface if it hasn't already been locked.
> 
> +
> 
> +  @param[in]  Event     Event whose notification function is being invoked
> 
> +  @param[in]  Context   Pointer to the notification function's context
> 
> +
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +EFIAPI
> 
> +LockPolicyInterfaceAtReadyToBoot (
> 
> +  IN      EFI_EVENT                 Event,
> 
> +  IN      VOID                      *Context
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS  Status;
> 
> +
> 
> +  Status = ProtocolLockVariablePolicy();
> 
> +
> 
> +  if (EFI_ERROR( Status )) {
> 
> +    VariablePolicyHandleFailureToLock( Status );
> 
> +  }
> 
> +  else {
> 
> +    gBS->CloseEvent( Event );
> 
> +  }
> 
> +
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  Convert internal pointer addresses to virtual addresses.
> 
> +
> 
> +  @param[in] Event      Event whose notification function is being invoked.
> 
> +  @param[in] Context    The pointer to the notification function's context,
> which
> 
> +                        is implementation-dependent.
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +EFIAPI
> 
> +VariablePolicyVirtualAddressCallback (
> 
> +  IN  EFI_EVENT   Event,
> 
> +  IN  VOID        *Context
> 
> +  )
> 
> +{
> 
> +  EfiConvertPointer (0, (VOID **)&mMmCommunication);
> 
> +  EfiConvertPointer (0, (VOID **)&mMmCommunicationBuffer);
> 
> +}
> 
> +
> 
> +
> 
> +/**
> 
> +  The driver's entry point.
> 
> +
> 
> +  @param[in] ImageHandle  The firmware allocated handle for the EFI image.
> 
> +  @param[in] SystemTable  A pointer to the EFI System Table.
> 
> +
> 
> +  @retval EFI_SUCCESS     The entry point executed successfully.
> 
> +  @retval other           Some error occured when executing this entry point.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VariablePolicySmmDxeMain (
> 
> +  IN    EFI_HANDLE                  ImageHandle,
> 
> +  IN    EFI_SYSTEM_TABLE            *SystemTable
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS              Status;
> 
> +  BOOLEAN                 ProtocolInstalled;
> 
> +  BOOLEAN                 CallbackRegistered;
> 
> +  BOOLEAN                 VirtualAddressChangeRegistered;
> 
> +  EFI_EVENT               ReadyToBootEvent;
> 
> +  EFI_EVENT               VirtualAddressChangeEvent;
> 
> +
> 
> +  Status = EFI_SUCCESS;
> 
> +  ProtocolInstalled = FALSE;
> 
> +  CallbackRegistered = FALSE;
> 
> +  VirtualAddressChangeRegistered = FALSE;
> 
> +
> 
> +  // Update the minimum buffer size.
> 
> +  mMmCommunicationBufferSize =
> VAR_CHECK_POLICY_MM_COMM_BUFFER_SIZE;
> 
> +  // Locate the shared comm buffer to use for sending MM commands.
> 
> +  Status = InitMmCommonCommBuffer( &mMmCommunicationBufferSize,
> &mMmCommunicationBuffer );
> 
> +  if (EFI_ERROR( Status )) {
> 
> +    DEBUG((DEBUG_ERROR, "%a - Failed to locate a viable MM comm
> buffer! %r\n", __FUNCTION__, Status));
> 
> +    ASSERT_EFI_ERROR( Status );
> 
> +    return Status;
> 
> +  }
> 
> +
> 
> +  // Locate the MmCommunication protocol.
> 
> +  Status = gBS->LocateProtocol( &gEfiMmCommunication2ProtocolGuid,
> NULL, (VOID**)&mMmCommunication );
> 
> +  if (EFI_ERROR( Status )) {
> 
> +    DEBUG((DEBUG_ERROR, "%a - Failed to locate MmCommunication
> protocol! %r\n", __FUNCTION__, Status));
> 
> +    ASSERT_EFI_ERROR( Status );
> 
> +    return Status;
> 
> +  }
> 
> +
> 
> +  // Configure the VariablePolicy protocol structure.
> 
> +  mVariablePolicyProtocol.Revision                =
> EDKII_VARIABLE_POLICY_PROTOCOL_REVISION;
> 
> +  mVariablePolicyProtocol.DisableVariablePolicy   =
> ProtocolDisableVariablePolicy;
> 
> +  mVariablePolicyProtocol.IsVariablePolicyEnabled =
> ProtocolIsVariablePolicyEnabled;
> 
> +  mVariablePolicyProtocol.RegisterVariablePolicy  =
> ProtocolRegisterVariablePolicy;
> 
> +  mVariablePolicyProtocol.DumpVariablePolicy      =
> ProtocolDumpVariablePolicy;
> 
> +  mVariablePolicyProtocol.LockVariablePolicy      = 
> ProtocolLockVariablePolicy;
> 
> +
> 
> +  // Register all the protocols and return the status.
> 
> +  Status = gBS->InstallMultipleProtocolInterfaces( &ImageHandle,
> 
> +                                                   
> &gEdkiiVariablePolicyProtocolGuid,
> &mVariablePolicyProtocol,
> 
> +                                                   NULL );
> 
> +  if (EFI_ERROR( Status )) {
> 
> +    DEBUG(( DEBUG_ERROR, "%a - Failed to install protocol! %r\n",
> __FUNCTION__, Status ));
> 
> +    goto Exit;
> 
> +  }
> 
> +  else {
> 
> +    ProtocolInstalled = TRUE;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Register a callback for ReadyToBoot so that the interface is at least
> locked before
> 
> +  // dispatching any bootloaders or UEFI apps.
> 
> +  Status = gBS->CreateEventEx( EVT_NOTIFY_SIGNAL,
> 
> +                               TPL_CALLBACK,
> 
> +                               LockPolicyInterfaceAtReadyToBoot,
> 
> +                               NULL,
> 
> +                               &gEfiEventReadyToBootGuid,
> 
> +                               &ReadyToBootEvent );
> 
> +  if (EFI_ERROR( Status )) {
> 
> +    DEBUG(( DEBUG_ERROR, "%a - Failed to create ReadyToBoot
> event! %r\n", __FUNCTION__, Status ));
> 
> +    goto Exit;
> 
> +  }
> 
> +  else {
> 
> +    CallbackRegistered = TRUE;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // Register a VirtualAddressChange callback for the MmComm protocol
> and Comm buffer.
> 
> +  Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,
> 
> +                                TPL_NOTIFY,
> 
> +                                VariablePolicyVirtualAddressCallback,
> 
> +                                NULL,
> 
> +                                &gEfiEventVirtualAddressChangeGuid,
> 
> +                                &VirtualAddressChangeEvent);
> 
> +  if (EFI_ERROR( Status )) {
> 
> +    DEBUG(( DEBUG_ERROR, "%a - Failed to create VirtualAddressChange
> event! %r\n", __FUNCTION__, Status ));
> 
> +    goto Exit;
> 
> +  }
> 
> +  else {
> 
> +    VirtualAddressChangeRegistered = TRUE;
> 
> +  }
> 
> +
> 
> +
> 
> +Exit:
> 
> +  //
> 
> +  // If we're about to return a failed status (and unload this driver), we 
> must
> first undo anything that
> 
> +  // has been successfully done.
> 
> +  if (EFI_ERROR( Status )) {
> 
> +    if (ProtocolInstalled) {
> 
> +      gBS->UninstallProtocolInterface( &ImageHandle,
> &gEdkiiVariablePolicyProtocolGuid, &mVariablePolicyProtocol );
> 
> +    }
> 
> +    if (CallbackRegistered) {
> 
> +      gBS->CloseEvent( ReadyToBootEvent );
> 
> +    }
> 
> +    if (VirtualAddressChangeRegistered) {
> 
> +      gBS->CloseEvent( VirtualAddressChangeEvent );
> 
> +    }
> 
> +  }
> 
> +
> 
> +  return Status;
> 
> +}
> 
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx
> e.c
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx
> e.c
> index 663a1aaa128f..c47e614d81f4 100644
> ---
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx
> e.c
> +++
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx
> e.c
> @@ -65,6 +65,17 @@ EFI_LOCK                         mVariableServicesLock;
>  EDKII_VARIABLE_LOCK_PROTOCOL     mVariableLock;
> 
>  EDKII_VAR_CHECK_PROTOCOL         mVarCheck;
> 
> 
> 
> +/**
> 
> +  The logic to initialize the VariablePolicy engine is in its own file.
> 
> +
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +VariablePolicySmmDxeMain (
> 
> +  IN    EFI_HANDLE                  ImageHandle,
> 
> +  IN    EFI_SYSTEM_TABLE            *SystemTable
> 
> +  );
> 
> +
> 
>  /**
> 
>    Some Secure Boot Policy Variable may update following other variable
> changes(SecureBoot follows PK change, etc).
> 
>    Record their initial State when variable write service is ready.
> 
> @@ -1796,6 +1807,9 @@ VariableSmmRuntimeInitialize (
>           &mVirtualAddressChangeEvent
> 
>           );
> 
> 
> 
> +  // Initialize the VariablePolicy protocol and engine.
> 
> +  VariablePolicySmmDxeMain (ImageHandle, SystemTable);
> 
> +
> 
>    return EFI_SUCCESS;
> 
>  }
> 
> 
> 
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> index ceea5d1ff9ac..48ac167906f7 100644
> ---
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> +++
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> @@ -10,6 +10,7 @@
>  #  buffer overflow or integer overflow.
> 
>  #
> 
>  # Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
> 
> +# Copyright (c) Microsoft Corporation.
> 
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
> 
>  #
> 
>  ##
> 
> @@ -69,6 +70,7 @@ [LibraryClasses]
>    TpmMeasurementLib
> 
>    AuthVariableLib
> 
>    VarCheckLib
> 
> +  VariablePolicyLib
> 
> 
> 
>  [Protocols]
> 
>    gEfiFirmwareVolumeBlockProtocolGuid           ## CONSUMES
> 
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
> index bc3033588d40..bbc8d2080193 100644
> --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
> +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf
> @@ -19,6 +19,7 @@
>  #  the authentication service provided in this driver will be broken, and the
> behavior is undefined.
> 
>  #
> 
>  # Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
> 
> +# Copyright (c) Microsoft Corporation.
> 
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
> 
>  #
> 
>  ##
> 
> @@ -78,6 +79,8 @@ [LibraryClasses]
>    AuthVariableLib
> 
>    VarCheckLib
> 
>    UefiBootServicesTableLib
> 
> +  VariablePolicyLib
> 
> +  VariablePolicyHelperLib
> 
> 
> 
>  [Protocols]
> 
>    gEfiSmmFirmwareVolumeBlockProtocolGuid        ## CONSUMES
> 
> diff --git
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx
> e.inf
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx
> e.inf
> index 01564e4c5068..f217530b2985 100644
> ---
> a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx
> e.inf
> +++
> b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDx
> e.inf
> @@ -14,6 +14,7 @@
>  #  the authentication service provided in this driver will be broken, and the
> behavior is undefined.
> 
>  #
> 
>  # Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
> 
> +# Copyright (c) Microsoft Corporation.<BR>
> 
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
> 
>  #
> 
>  ##
> 
> @@ -42,6 +43,7 @@ [Sources]
>    VariableParsing.c
> 
>    VariableParsing.h
> 
>    Variable.h
> 
> +  VariablePolicySmmDxe.c
> 
> 
> 
>  [Packages]
> 
>    MdePkg/MdePkg.dec
> 
> @@ -56,6 +58,8 @@ [LibraryClasses]
>    DxeServicesTableLib
> 
>    UefiDriverEntryPoint
> 
>    TpmMeasurementLib
> 
> +  SafeIntLib
> 
> +  PcdLib
> 
> 
> 
>  [Protocols]
> 
>    gEfiVariableWriteArchProtocolGuid             ## PRODUCES
> 
> @@ -67,11 +71,15 @@ [Protocols]
>    gEfiSmmVariableProtocolGuid
> 
>    gEdkiiVariableLockProtocolGuid                ## PRODUCES
> 
>    gEdkiiVarCheckProtocolGuid                    ## PRODUCES
> 
> +  gEdkiiVariablePolicyProtocolGuid              ## PRODUCES
> 
> 
> 
>  [FeaturePcd]
> 
>    gEfiMdeModulePkgTokenSpaceGuid.PcdEnableVariableRuntimeCache
> ## CONSUMES
> 
>    gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics            ##
> CONSUMES
> 
> 
> 
> +[Pcd]
> 
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdAllowVariablePolicyEnforcementDis
> able     ## CONSUMES
> 
> +
> 
>  [Guids]
> 
>    ## PRODUCES             ## GUID # Signature of Variable store header
> 
>    ## CONSUMES             ## GUID # Signature of Variable store header
> 
> @@ -99,6 +107,8 @@ [Guids]
>    ## SOMETIMES_CONSUMES   ## Variable:L"dbt"
> 
>    gEfiImageSecurityDatabaseGuid
> 
> 
> 
> +  gVarCheckPolicyLibMmiHandlerGuid
> 
> +
> 
>  [Depex]
> 
>    gEfiMmCommunication2ProtocolGuid
> 
> 
> 
> --
> 2.26.2.windows.1.8.g01c50adf56.20200515075929
> 
> 
> -=-=-=-=-=-=
> Groups.io Links: You receive all messages sent to this group.
> 
> View/Reply Online (#61585): https://edk2.groups.io/g/devel/message/61585
> Mute This Topic: https://groups.io/mt/75057694/1768738
> Group Owner: devel+ow...@edk2.groups.io
> Unsubscribe: https://edk2.groups.io/g/devel/unsub  [dandan...@intel.com]
> -=-=-=-=-=-=


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#61931): https://edk2.groups.io/g/devel/message/61931
Mute This Topic: https://groups.io/mt/75057694/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to