public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Taylor Beebe" <t@taylorbeebe.com>
To: Ard Biesheuvel <ardb@kernel.org>, devel@edk2.groups.io
Cc: Michael Kinney <michael.d.kinney@intel.com>,
	Liming Gao <gaoliming@byosoft.com.cn>,
	Jiewen Yao <jiewen.yao@intel.com>,
	Michael Kubacki <michael.kubacki@microsoft.com>,
	Sean Brogan <sean.brogan@microsoft.com>,
	Rebecca Cran <quic_rcran@quicinc.com>,
	Leif Lindholm <quic_llindhol@quicinc.com>,
	Sami Mujawar <sami.mujawar@arm.com>
Subject: Re: [edk2-devel] [PATCH 4/4] ArmPkg/CpuDxe: Implement EFI memory attributes protocol
Date: Fri, 3 Feb 2023 11:08:58 -0800	[thread overview]
Message-ID: <db7c3126-2741-d1dc-0ed9-6690a432724f@taylorbeebe.com> (raw)
In-Reply-To: <CAMj1kXEZkLNB8XeMqbZwMVLneccaHak7G39Zymd-RT7M=oP3jg@mail.gmail.com>



On 2/2/2023 1:43 AM, Ard Biesheuvel wrote:
> On Wed, 1 Feb 2023 at 19:41, Taylor Beebe <t@taylorbeebe.com> wrote:
>>
>> Hey Ard,
>>
>> Have you encountered complications which stem from the lack of
>> pre-allocated page table memory on ARM devices utilizing the memory
>> protection policy?
>>
> 
> Interesting. No I haven't, but I agree it is a potential concern.
> 
>> My observation is the call stack can end up something like:
>>
>> 1. MemoryAttributeProtocol->SetMemoryAttributes(EFI_MEMORY_RO)
>> 2. ArmSetMemoryRegionReadOnly ()
>> 3. SetMemoryRegionAttribute()
>> 4. UpdateRegionMapping()
>> 5. UpdateRegionMappingRecursive()
>> 6. AllocatePages() -> Need memory for a translation table entry
>> 7. CoreAllocatePages()
>> 8. ApplyMemoryProtectionPolicy() -> Policy says new page should be XN
>> 9. gCpu->SetMemoryAttributes()
>> 10. Back to 3 and loop infinitely
>>
> 
> So one thing that makes this scenario unlikely (I think) is that by
> default, all unallocated space has the XP attribute set already, and
> so allocating a page table with XP attributes should not result in the
> need for a block entry split, and therefore no allocation for a next
> level table. Perhaps we need some asserts to diagnose this at runtime?

Ah yes, you're right. On Project Mu, we make an explicit check to the 
attributes of the region in ApplyMemoryProtectionPolicy() to determine 
if the attributes need to be updated. We do this to account for the 
introduction of the memory attribute protocol and to mitigate a rare 
issue where an allocation might not have consistent attributes when 
allocating a type other than BootServicesData. This change to 
ApplyMemoryProtectionPolicy() means an infinite loop is possible during 
the memory protection initialization phase.

> 
>> On 1/31/2023 2:35 PM, Ard Biesheuvel wrote:
>>> Expose the protocol introduced in v2.10 that permits the caller to
>>> manage mapping permissions in the page tables.
>>>
>>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
>>> ---
>>>    ArmPkg/Drivers/CpuDxe/CpuDxe.c          |   2 +
>>>    ArmPkg/Drivers/CpuDxe/CpuDxe.h          |   3 +
>>>    ArmPkg/Drivers/CpuDxe/CpuDxe.inf        |   2 +
>>>    ArmPkg/Drivers/CpuDxe/MemoryAttribute.c | 242 ++++++++++++++++++++
>>>    4 files changed, 249 insertions(+)
>>>
>>> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>>> index e6742f0a25fc..d04958e79e52 100644
>>> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>>> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
>>> @@ -244,6 +244,8 @@ CpuDxeInitialize (
>>>                      &mCpuHandle,
>>>
>>>                      &gEfiCpuArchProtocolGuid,
>>>
>>>                      &mCpu,
>>>
>>> +                  &gEfiMemoryAttributeProtocolGuid,
>>>
>>> +                  &mMemoryAttribute,
>>>
>>>                      NULL
>>>
>>>                      );
>>>
>>>
>>>
>>> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
>>> index 8933fa90c4ed..f45d2bc101a3 100644
>>> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h
>>> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
>>> @@ -30,9 +30,12 @@
>>>    #include <Protocol/Cpu.h>
>>>
>>>    #include <Protocol/DebugSupport.h>
>>>
>>>    #include <Protocol/LoadedImage.h>
>>>
>>> +#include <Protocol/MemoryAttribute.h>
>>>
>>>
>>>
>>>    extern BOOLEAN  mIsFlushingGCD;
>>>
>>>
>>>
>>> +extern EFI_MEMORY_ATTRIBUTE_PROTOCOL  mMemoryAttribute;
>>>
>>> +
>>>
>>>    /**
>>>
>>>      This function registers and enables the handler specified by InterruptHandler for a processor
>>>
>>>      interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
>>>
>>> diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
>>> index 10792b393fc8..e732e21cb94a 100644
>>> --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
>>> +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
>>> @@ -23,6 +23,7 @@ [Sources.Common]
>>>      CpuDxe.h
>>>
>>>      CpuMmuCommon.c
>>>
>>>      Exception.c
>>>
>>> +  MemoryAttribute.c
>>>
>>>
>>>
>>>    [Sources.ARM]
>>>
>>>      Arm/Mmu.c
>>>
>>> @@ -53,6 +54,7 @@ [LibraryClasses]
>>>
>>>
>>>    [Protocols]
>>>
>>>      gEfiCpuArchProtocolGuid
>>>
>>> +  gEfiMemoryAttributeProtocolGuid
>>>
>>>
>>>
>>>    [Guids]
>>>
>>>      gEfiDebugImageInfoTableGuid
>>>
>>> diff --git a/ArmPkg/Drivers/CpuDxe/MemoryAttribute.c b/ArmPkg/Drivers/CpuDxe/MemoryAttribute.c
>>> new file mode 100644
>>> index 000000000000..9aeb83fff1b9
>>> --- /dev/null
>>> +++ b/ArmPkg/Drivers/CpuDxe/MemoryAttribute.c
>>> @@ -0,0 +1,242 @@
>>> +/** @file
>>>
>>> +
>>>
>>> +  Copyright (c) 2023, Google LLC. All rights reserved.
>>>
>>> +
>>>
>>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>>>
>>> +
>>>
>>> +**/
>>>
>>> +
>>>
>>> +#include "CpuDxe.h"
>>>
>>> +
>>>
>>> +/**
>>>
>>> +  This function retrieves the attributes of the memory region specified by
>>>
>>> +  BaseAddress and Length. If different attributes are got from different part
>>>
>>> +  of the memory region, EFI_NO_MAPPING will be returned.
>>>
>>> +
>>>
>>> +  @param  This              The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
>>>
>>> +  @param  BaseAddress       The physical address that is the start address of
>>>
>>> +                            a memory region.
>>>
>>> +  @param  Length            The size in bytes of the memory region.
>>>
>>> +  @param  Attributes        Pointer to attributes returned.
>>>
>>> +
>>>
>>> +  @retval EFI_SUCCESS           The attributes got for the memory region.
>>>
>>> +  @retval EFI_INVALID_PARAMETER Length is zero.
>>>
>>> +                                Attributes is NULL.
>>>
>>> +  @retval EFI_NO_MAPPING        Attributes are not consistent cross the memory
>>>
>>> +                                region.
>>>
>>> +  @retval EFI_UNSUPPORTED       The processor does not support one or more
>>>
>>> +                                bytes of the memory resource range specified
>>>
>>> +                                by BaseAddress and Length.
>>>
>>> +
>>>
>>> +**/
>>>
>>> +STATIC
>>>
>>> +EFI_STATUS
>>>
>>> +GetMemoryAttributes (
>>>
>>> +  IN  EFI_MEMORY_ATTRIBUTE_PROTOCOL       *This,
>>>
>>> +  IN  EFI_PHYSICAL_ADDRESS                BaseAddress,
>>>
>>> +  IN  UINT64                              Length,
>>>
>>> +  OUT UINT64                              *Attributes
>>>
>>> +  )
>>>
>>> +{
>>>
>>> +  UINTN       RegionAddress;
>>>
>>> +  UINTN       RegionLength;
>>>
>>> +  UINTN       RegionAttributes;
>>>
>>> +  UINTN       Union;
>>>
>>> +  UINTN       Intersection;
>>>
>>> +  EFI_STATUS  Status;
>>>
>>> +
>>>
>>> +  if ((Length == 0) || (Attributes == NULL)) {
>>>
>>> +    return EFI_INVALID_PARAMETER;
>>>
>>> +  }
>>>
>>> +
>>>
>>> +  DEBUG ((DEBUG_INFO,
>>>
>>> +          "%a: BaseAddress == 0x%lx, Length == 0x%lx\n",
>>>
>>> +          __FUNCTION__,
>>>
>>> +          (UINTN)BaseAddress,
>>>
>>> +          (UINTN)Length
>>>
>>> +          ));
>>>
>>> +
>>>
>>> +  Union         = 0;
>>>
>>> +  Intersection  = MAX_UINTN;
>>>
>>> +
>>>
>>> +  for (RegionAddress = (UINTN)BaseAddress;
>>>
>>> +       RegionAddress < (UINTN)(BaseAddress + Length);
>>>
>>> +       RegionAddress += RegionLength) {
>>>
>>> +
>>>
>>> +    Status = GetMemoryRegion (&RegionAddress,
>>>
>>> +                              &RegionLength,
>>>
>>> +                              &RegionAttributes
>>>
>>> +                              );
>>>
>>> +
>>>
>>> +    DEBUG ((DEBUG_INFO,
>>>
>>> +            "%a: RegionAddress == 0x%lx, RegionLength == 0x%lx, RegionAttributes == 0x%lx\n",
>>>
>>> +            __FUNCTION__,
>>>
>>> +            RegionAddress,
>>>
>>> +            RegionLength,
>>>
>>> +            RegionAttributes
>>>
>>> +            ));
>>>
>>> +
>>>
>>> +    if (EFI_ERROR (Status)) {
>>>
>>> +      return EFI_NO_MAPPING;
>>>
>>> +    }
>>>
>>> +
>>>
>>> +    Union         |= RegionAttributes;
>>>
>>> +    Intersection  &= RegionAttributes;
>>>
>>> +  }
>>>
>>> +
>>>
>>> +  DEBUG ((DEBUG_INFO,
>>>
>>> +          "%a: Union == %lx, Intersection == %lx\n",
>>>
>>> +          __FUNCTION__,
>>>
>>> +          Union,
>>>
>>> +          Intersection
>>>
>>> +          ));
>>>
>>> +
>>>
>>> +  if (Union != Intersection) {
>>>
>>> +    return EFI_NO_MAPPING;
>>>
>>> +  }
>>>
>>> +
>>>
>>> +  *Attributes = PageAttributeToGcdAttribute (Union) & (EFI_MEMORY_RO | EFI_MEMORY_XP);
>>>
>>> +  return EFI_SUCCESS;
>>>
>>> +}
>>>
>>> +
>>>
>>> +/**
>>>
>>> +  This function set given attributes of the memory region specified by
>>>
>>> +  BaseAddress and Length.
>>>
>>> +
>>>
>>> +  The valid Attributes is EFI_MEMORY_RP, EFI_MEMORY_XP, and EFI_MEMORY_RO.
>>>
>>> +
>>>
>>> +  @param  This              The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
>>>
>>> +  @param  BaseAddress       The physical address that is the start address of
>>>
>>> +                            a memory region.
>>>
>>> +  @param  Length            The size in bytes of the memory region.
>>>
>>> +  @param  Attributes        The bit mask of attributes to set for the memory
>>>
>>> +                            region.
>>>
>>> +
>>>
>>> +  @retval EFI_SUCCESS           The attributes were set for the memory region.
>>>
>>> +  @retval EFI_INVALID_PARAMETER Length is zero.
>>>
>>> +                                Attributes specified an illegal combination of
>>>
>>> +                                attributes that cannot be set together.
>>>
>>> +  @retval EFI_UNSUPPORTED       The processor does not support one or more
>>>
>>> +                                bytes of the memory resource range specified
>>>
>>> +                                by BaseAddress and Length.
>>>
>>> +                                The bit mask of attributes is not supported for
>>>
>>> +                                the memory resource range specified by
>>>
>>> +                                BaseAddress and Length.
>>>
>>> +
>>>
>>> +**/
>>>
>>> +STATIC
>>>
>>> +EFI_STATUS
>>>
>>> +SetMemoryAttributes (
>>>
>>> +  IN  EFI_MEMORY_ATTRIBUTE_PROTOCOL       *This,
>>>
>>> +  IN  EFI_PHYSICAL_ADDRESS                BaseAddress,
>>>
>>> +  IN  UINT64                              Length,
>>>
>>> +  IN  UINT64                              Attributes
>>>
>>> +  )
>>>
>>> +{
>>>
>>> +  EFI_STATUS  Status;
>>>
>>> +
>>>
>>> +  DEBUG ((DEBUG_INFO,
>>>
>>> +          "%a: BaseAddress == 0x%lx, Length == 0x%lx, Attributes == 0x%lx\n",
>>>
>>> +          __FUNCTION__,
>>>
>>> +          (UINTN)BaseAddress,
>>>
>>> +          (UINTN)Length,
>>>
>>> +          (UINTN)Attributes
>>>
>>> +          ));
>>>
>>> +
>>>
>>> +  if ((Length == 0) ||
>>>
>>> +      ((Attributes & ~(EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP)) != 0)) {
>>>
>>> +    return EFI_INVALID_PARAMETER;
>>>
>>> +  }
>>>
>>> +
>>>
>>> +  if ((Attributes & EFI_MEMORY_RP) != 0) {
>>>
>>> +    return EFI_UNSUPPORTED;
>>>
>>> +  }
>>>
>>> +
>>>
>>> +  if ((Attributes & EFI_MEMORY_RO) != 0) {
>>>
>>> +    Status = ArmSetMemoryRegionReadOnly (BaseAddress, Length);
>>>
>>> +    if (EFI_ERROR (Status)) {
>>>
>>> +      return EFI_UNSUPPORTED;
>>>
>>> +    }
>>>
>>> +  }
>>>
>>> +
>>>
>>> +  if ((Attributes & EFI_MEMORY_XP) != 0) {
>>>
>>> +    Status = ArmSetMemoryRegionNoExec (BaseAddress, Length);
>>>
>>> +    if (EFI_ERROR (Status)) {
>>>
>>> +      return EFI_UNSUPPORTED;
>>>
>>> +    }
>>>
>>> +  }
>>>
>>> +
>>>
>>> +  return EFI_SUCCESS;
>>>
>>> +}
>>>
>>> +
>>>
>>> +/**
>>>
>>> +  This function clears given attributes of the memory region specified by
>>>
>>> +  BaseAddress and Length.
>>>
>>> +
>>>
>>> +  The valid Attributes is EFI_MEMORY_RP, EFI_MEMORY_XP, and EFI_MEMORY_RO.
>>>
>>> +
>>>
>>> +  @param  This              The EFI_MEMORY_ATTRIBUTE_PROTOCOL instance.
>>>
>>> +  @param  BaseAddress       The physical address that is the start address of
>>>
>>> +                            a memory region.
>>>
>>> +  @param  Length            The size in bytes of the memory region.
>>>
>>> +  @param  Attributes        The bit mask of attributes to clear for the memory
>>>
>>> +                            region.
>>>
>>> +
>>>
>>> +  @retval EFI_SUCCESS           The attributes were cleared for the memory region.
>>>
>>> +  @retval EFI_INVALID_PARAMETER Length is zero.
>>>
>>> +                                Attributes specified an illegal combination of
>>>
>>> +                                attributes that cannot be cleared together.
>>>
>>> +  @retval EFI_UNSUPPORTED       The processor does not support one or more
>>>
>>> +                                bytes of the memory resource range specified
>>>
>>> +                                by BaseAddress and Length.
>>>
>>> +                                The bit mask of attributes is not supported for
>>>
>>> +                                the memory resource range specified by
>>>
>>> +                                BaseAddress and Length.
>>>
>>> +
>>>
>>> +**/
>>>
>>> +STATIC
>>>
>>> +EFI_STATUS
>>>
>>> +ClearMemoryAttributes (
>>>
>>> +  IN  EFI_MEMORY_ATTRIBUTE_PROTOCOL       *This,
>>>
>>> +  IN  EFI_PHYSICAL_ADDRESS                BaseAddress,
>>>
>>> +  IN  UINT64                              Length,
>>>
>>> +  IN  UINT64                              Attributes
>>>
>>> +  )
>>>
>>> +{
>>>
>>> +  EFI_STATUS  Status;
>>>
>>> +
>>>
>>> +  DEBUG ((DEBUG_INFO,
>>>
>>> +          "%a: BaseAddress == 0x%lx, Length == 0x%lx, Attributes == 0x%lx\n",
>>>
>>> +          __FUNCTION__,
>>>
>>> +          (UINTN)BaseAddress,
>>>
>>> +          (UINTN)Length,
>>>
>>> +          (UINTN)Attributes
>>>
>>> +          ));
>>>
>>> +
>>>
>>> +  if ((Length == 0) ||
>>>
>>> +      ((Attributes & ~(EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP)) != 0)) {
>>>
>>> +    return EFI_INVALID_PARAMETER;
>>>
>>> +  }
>>>
>>> +
>>>
>>> +  if ((Attributes & EFI_MEMORY_RO) != 0) {
>>>
>>> +    Status = ArmClearMemoryRegionReadOnly (BaseAddress, Length);
>>>
>>> +    if (EFI_ERROR (Status)) {
>>>
>>> +      return EFI_UNSUPPORTED;
>>>
>>> +    }
>>>
>>> +  }
>>>
>>> +
>>>
>>> +  if ((Attributes & EFI_MEMORY_XP) != 0) {
>>>
>>> +    Status = ArmClearMemoryRegionNoExec (BaseAddress, Length);
>>>
>>> +    if (EFI_ERROR (Status)) {
>>>
>>> +      return EFI_UNSUPPORTED;
>>>
>>> +    }
>>>
>>> +  }
>>>
>>> +
>>>
>>> +  return EFI_SUCCESS;
>>>
>>> +}
>>>
>>> +
>>>
>>> +EFI_MEMORY_ATTRIBUTE_PROTOCOL  mMemoryAttribute = {
>>>
>>> +  GetMemoryAttributes,
>>>
>>> +  SetMemoryAttributes,
>>>
>>> +  ClearMemoryAttributes
>>>
>>> +};
>>>
>>
>> --
>> Taylor Beebe
>> Software Engineer @ Microsoft
>>
>>
>> 
>>
>>

-- 
Taylor Beebe
Software Engineer @ Microsoft

  reply	other threads:[~2023-02-03 19:09 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-31 22:35 [PATCH 0/4] ArmPkg: implement EFI memory attributes protocol Ard Biesheuvel
2023-01-31 22:35 ` [PATCH 1/4] MdePkg: Add Memory Attribute Protocol definition Ard Biesheuvel
2023-02-02  3:19   ` 回复: " gaoliming
2023-02-02  9:25     ` [edk2-devel] " Ard Biesheuvel
2023-01-31 22:35 ` [PATCH 2/4] MdePkg: Bump implemented UEFI version to v2.10 Ard Biesheuvel
2023-02-01  0:10   ` Michael D Kinney
2023-02-01  7:54     ` Ard Biesheuvel
2023-01-31 22:35 ` [PATCH 3/4] ArmPkg/CpuDxe: Unify PageAttributeToGcdAttribute helper Ard Biesheuvel
2023-01-31 22:35 ` [PATCH 4/4] ArmPkg/CpuDxe: Implement EFI memory attributes protocol Ard Biesheuvel
2023-02-01 18:41   ` [edk2-devel] " Taylor Beebe
2023-02-02  9:43     ` Ard Biesheuvel
2023-02-03 19:08       ` Taylor Beebe [this message]
2023-02-03 19:58         ` Marvin Häuser
2023-02-07  1:18           ` Taylor Beebe
2023-02-07  8:29             ` Ard Biesheuvel
2023-02-07  8:56               ` Marvin Häuser
2023-02-07  9:16                 ` Ard Biesheuvel
2023-02-07 10:00                   ` Marvin Häuser
2023-02-07 10:01                   ` Ard Biesheuvel
2023-02-07 10:13                     ` Marvin Häuser
2023-02-07 17:56                       ` Ard Biesheuvel
2023-02-07 18:19                         ` Taylor Beebe
2023-02-07 18:50                           ` Marvin Häuser
2023-02-07 18:19                         ` Marvin Häuser

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=db7c3126-2741-d1dc-0ed9-6690a432724f@taylorbeebe.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox