From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by mx.groups.io with SMTP id smtpd.web11.92836.1682946136885935870 for ; Mon, 01 May 2023 06:02:17 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=ezGOxvre; spf=pass (domain: kernel.org, ip: 139.178.84.217, mailfrom: ardb@kernel.org) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 584F760F25 for ; Mon, 1 May 2023 13:02:16 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id BF2ACC433A0 for ; Mon, 1 May 2023 13:02:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1682946135; bh=3V3j3nLuIEtTD1WfPmdAbGikAkOibs5ey08OpjI9Fmk=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=ezGOxvreDzFqTKYoyfaAwp9vJO17DTSzggrTi6UOhILXKAj/qm/qyx+l1r6OGaUz/ zfzl/UYuqfa8YLKfqestPqyKZB6eeoA3ISBNbpU86DOwpy0dmMevCxEhggoQ0yJnfK xLcHpeo+2BzO9IEKEA6WU5xkkVHfU4Ng4gpBOq6rB5F42D5P85/MqRtTzJFkxzAgxj kkcZIWdpbRlUFjjEhKHy2yObZJUWC3gVEjV2hyLtHUewKy6NywQ6VSB1PRiv0yPbIp EEtHyU+XziUfsrWnrWK/dqsNjn14ELiW4VIDY23aMQI9eD0ZZzQw2cLRvaZ5Y/PGts KQ2vOAmb4RFFA== Received: by mail-lf1-f47.google.com with SMTP id 2adb3069b0e04-4f004cc54f4so3401228e87.3 for ; Mon, 01 May 2023 06:02:15 -0700 (PDT) X-Gm-Message-State: AC+VfDyO/omFvEhbz8mpoCYs+e8NRfRu/9U3nkaHSaPPkZ+golquUs6w cpxEjOReldjH3y3qePUO7uJy/W7a/KblYTEFEio= X-Google-Smtp-Source: ACHHUZ75zXLQMqK8u40hU8TWaOd6OfhcUW8BiWnEFJwgj2fESKHsfviL4bdubtAYEwY+zE6MitvVuaVEHeWCTjpkcrk= X-Received: by 2002:ac2:44d2:0:b0:4db:3847:12f0 with SMTP id d18-20020ac244d2000000b004db384712f0mr3240189lfm.50.1682946133720; Mon, 01 May 2023 06:02:13 -0700 (PDT) MIME-Version: 1.0 References: <20230426000930.5748-1-osde@linux.microsoft.com> In-Reply-To: <20230426000930.5748-1-osde@linux.microsoft.com> From: "Ard Biesheuvel" Date: Mon, 1 May 2023 15:02:02 +0200 X-Gmail-Original-Message-ID: Message-ID: Subject: Re: [edk2-devel][PATCH v1 1/1] ArmPkg: CpuDxe: Sync GCD Capabilities With Page Table Attributes To: Oliver Smith-Denny Cc: devel@edk2.groups.io, Leif Lindholm , Ard Biesheuvel , Sami Mujawar , Michael Kubacki , Sean Brogan Content-Type: text/plain; charset="UTF-8" On Wed, 26 Apr 2023 at 02:09, Oliver Smith-Denny wrote: > > When ArmPkg's CpuDxe driver initializes, it attempts to sync the > GCD with the page table. However, unlike when the UefiCpuPkg's > CpuDxe initializes, the Arm version does not update the GCD > capabilities with EFI_MEMORY_[RO|RP|XP] (this could also set > the capabilities to be the existing page table attributes for > this range, but the UefiCpuPkg CpuDxe sets the above attributes > as they are software constructs, possible to set for any memory > hardware). > > As a result, when the GCD attributes are attempted to be set > against the old GCD capabilities, attributes that are set in the > page table can get lost because the new attributes are not in the > old GCD capabilities (and yet they are already set in the page > table) meaning that the attempted sync between the GCD and the > page table was a failure and drivers querying one vs the other > will see different state. This can lead to RWX memory regions > even with the no-execute policy set, because core drivers (such > as NonDiscoverablePciDeviceIo, to be fixed up in a later patchset) > allocate pages, query the GCD attributes, attempt to set a new > cache attribute and end up clearing the XP bit in the page table > because the GCD attributes do not have XP set. > > This patch follows the UefiCpuPkg pattern and adds > EFI_MEMORY_[RO|RP|XP] to the GCD capabilities during CpuDxe > initialization. This ensures that memory regions which already have > these attributes set get them set in the GCD attributes, properly > syncing between the GCD and the page table. > > This mitigates the issue seen, however, additional investigations > into setting the GCD attributes earlier and maintaining a better > sync between the GCD and the page table are being done. > > Feedback on this proposal is greatly appreciated, particularly > any pitfalls or more architectural solutions to issues seen > with syncing the GCD and the page table. > I think this is conceptually correct. However, I've played with this in the past, and IIRC, these attributes are inherited by the EFI memory map too, and not updated when allocations are made. This means that all code and data regions will be listed as RP, RO and XP in the EFI memory map, which is going to confuse Linux at the very least, and potentially other OSes as well. Generally, the EFI and PI specs are very vague when it comes to defining whether memory region attributes apply to the memory region itself ("this memory can be mapped as read-only or non-exec") or its contents ("these pages can be mapped read-only because the code does not expect to be able to write to it"). Before we have some clarification and some rigid wording in the spec as to what these attributes actually mean for non-allocated regions vs allocated ones, I don't think we can use them like this. Alternatively, we could update the GCD core so these attributes are not inherited by the EFI memory map. Another potential concern is fragmentation: the GCD memory map has very few entries usually under the current usage model, but keeping track of all memory permission attributes is going to inflate its size substantially. Also, including EFI_MEMORY_RP only makes sense if we implement a way to apply it, which ArmCpuDxe currently does not provide. > PR: https://github.com/tianocore/edk2/pull/4311 > Personal branch: https://github.com/os-d/edk2/tree/osde/sync_aarch64_gcd_capabilities_v1 > > Cc: Leif Lindholm > Cc: Ard Biesheuvel > Cc: Sami Mujawar > Cc: Michael Kubacki > Cc: Sean Brogan > > Signed-off-by: Oliver Smith-Denny > --- > ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c | 55 +++++++++++++++++--- > 1 file changed, 49 insertions(+), 6 deletions(-) > > diff --git a/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c b/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c > index 2e73719dce04..3ef0380e084f 100644 > --- a/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c > +++ b/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c > @@ -90,6 +90,7 @@ SetGcdMemorySpaceAttributes ( > UINTN EndIndex; > EFI_PHYSICAL_ADDRESS RegionStart; > UINT64 RegionLength; > + UINT64 Capabilities; > > DEBUG (( > DEBUG_GCD, > @@ -146,14 +147,56 @@ SetGcdMemorySpaceAttributes ( > RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart; > } > > + // Always add RO, RP, and XP as all memory is capable of supporting these types (they are software > + // constructs, not hardware features) and they are critical to maintaining a security boundary > + Capabilities = MemorySpaceMap[Index].Capabilities | EFI_MEMORY_RO | EFI_MEMORY_RP | EFI_MEMORY_XP; > + > // > - // Set memory attributes according to MTRR attribute and the original attribute of descriptor > + // Update GCD capabilities as these may have changed in the page table since the GCD was created > + // this follows the same pattern as x86 GCD and Page Table syncing > // > - gDS->SetMemorySpaceAttributes ( > - RegionStart, > - RegionLength, > - (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes) > - ); > + Status = gDS->SetMemorySpaceCapabilities ( > + RegionStart, > + RegionLength, > + Capabilities > + ); > + > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "%a - failed to update GCD capabilities: 0x%llx on memory region: 0x%llx length: 0x%llx Status: %r\n", > + __func__, > + Capabilities, > + RegionStart, > + RegionLength, > + Status > + )); > + ASSERT_EFI_ERROR (Status); > + continue; > + } > + > + // > + // Set memory attributes according to the page table attribute and the original attribute of descriptor > + // > + Status = gDS->SetMemorySpaceAttributes ( > + RegionStart, > + RegionLength, > + (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (Attributes & Capabilities) > + ); > + > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_ERROR, > + "%a - failed to update GCD attributes: 0x%llx on memory region: 0x%llx length: 0x%llx Status: %r\n", > + __func__, > + Attributes, > + RegionStart, > + RegionLength, > + Status > + )); > + ASSERT_EFI_ERROR (Status); > + continue; > + } > } > > return EFI_SUCCESS; > -- > 2.40.0 >