From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=66.187.233.73; helo=mx1.redhat.com; envelope-from=lersek@redhat.com; receiver=edk2-devel@lists.01.org Received: from mx1.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id D49B7202E544F for ; Thu, 28 Jun 2018 06:14:02 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1E1004077224; Thu, 28 Jun 2018 13:14:02 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-120-10.rdu2.redhat.com [10.10.120.10]) by smtp.corp.redhat.com (Postfix) with ESMTP id 483E0213ED6A; Thu, 28 Jun 2018 13:14:00 +0000 (UTC) To: "Zeng, Star" , Brijesh Singh , "edk2-devel@lists.01.org" Cc: Tom Lendacky , "Dong, Eric" , "Justen, Jordan L" References: <1530042365-9979-1-git-send-email-brijesh.singh@amd.com> <0C09AFA07DD0434D9E2A0C6AEB0483103BB5E06A@shsmsx102.ccr.corp.intel.com> From: Laszlo Ersek Message-ID: Date: Thu, 28 Jun 2018 15:13:54 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: <0C09AFA07DD0434D9E2A0C6AEB0483103BB5E06A@shsmsx102.ccr.corp.intel.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Thu, 28 Jun 2018 13:14:02 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Thu, 28 Jun 2018 13:14:02 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lersek@redhat.com' RCPT:'' Subject: Re: [RFC PATCH 1/1] OvmfPkg/QemuFlash: Fix Runtime variable access when SEV is enabled X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 28 Jun 2018 13:14:03 -0000 Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit On 06/28/18 08:16, Zeng, Star wrote: > 1) My understanding is Variable Driver is managing the variable region in flash although the flash read/write/erase operations are done in flash driver. Current Variable Driver needs the address (to variable region) be converted to virtual address for runtime, and it does not assume flash driver to set the runtime attribute for variable region, but do it by itself. > > 2) I agree this approach. If the runtime attribute has been set by flash driver, Variable Driver has no need to do that. Great, thank you! Yesterday, after I sent my email(s), I got concerned for a moment, because it wasn't clear to me what *runtime driver* actually owned the flash range. However, the FVB protocol itself must be provided by a runtime driver on UEFI/PI platforms where the variable write service implementation -- indirectly or directly -- depends on FVB, for flash writes. Indeed in edk2, we have at least the following FVB drivers: $ git grep -l -E \ -e 'EfiFirmwareVolumeBlock2?ProtocolGuid' --and -e 'PROD' EmulatorPkg/FvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf Nt32Pkg/FvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbRuntimeDxe.inf Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbSmmDxe.inf All of them are DXE_RUNTIME_DRIVER modules [*] and they all call EfiConvertPointer(). [*] "Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbSmmDxe.inf" is marked as a DXE_DRIVER (not runtime), and indeed it doesn't call EfiConvertPointer(). I don't know what this driver is good for; the INF file is not included in any DSC file in edk2. I guess it can be used for flash access on an SMM platform as long as you never boot an OS / never call ExitBootServices(). In that case however, runtime aspects have no meaning at all. Thanks! Laszlo > > > Thanks, > Star > -----Original Message----- > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Laszlo Ersek > Sent: Wednesday, June 27, 2018 8:54 PM > To: Brijesh Singh ; edk2-devel@lists.01.org > Cc: Tom Lendacky ; Dong, Eric ; Zeng, Star ; Justen, Jordan L > Subject: Re: [edk2] [RFC PATCH 1/1] OvmfPkg/QemuFlash: Fix Runtime variable access when SEV is enabled > > On 06/26/18 21:46, Brijesh Singh wrote: >> Problem statement: >> ------------------ >> Fedora-28 contains 4.16 kernel -- which has all the required support >> to run as an SEV guest. When the installer is launched from SEV guest >> then it fails to install the bootloader. The installer was failing to >> update the 'BootOrder' UEFI runtime variable. >> >> Root Cause Analysis >> -------------------- >> Since QemuFlash storage memory is accessed by both guest and >> hypervisor hence we need to map this memory range as unencrypted. >> AmdSevDxe maps the range as "unencrypted" but later >> FtwNotificationEvent() in >> MdeModule/Universal/Variable/RuntimeDxe/VariableDxe.c resets the mapping and the memory region gets remapped as "encrypted". > > Is this a new issue, or has it always been there, and we just failed to notice it? > > BTW, I don't understand why FtwNotificationEvent() in "MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c" has to mark the flash range as EFI_MEMORY_RUNTIME. I thought that this action belonged in the flash driver itself, and we do that already in MarkMemoryRangeForRuntimeAccess(), in file "OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c". > > The variable driver does not own the pflash chip (the pflash driver owns it), so I believe the variable driver shouldn't mess with the mapping attributes. > > Here's a suggestion -- Star, Eric, can you please comment? In the > FtwNotificationEvent() function, after we get the memory descriptor for the pflash range, first check whether EFI_MEMORY_RUNTIME is already set. > If it is, don't do anything; if it isn't, add the attribute. > > This should cause no observable change on any non-SEV platform, and it should remove the gDS->SetMemorySpaceAttributes() call for OVMF (where it breaks things for SEV). > >> After that, any access >> to the flash will end up going through the encryption engine. I did >> try hacking EDK2 to restore the C-bit > > (I continue to be annoyed that the memory encryption bit is not exposed in the GCD memory space attributes explicitly.) > >> but that was not sufficient because UEFI runtime services are mapped >> as "encrypted" in OS page table > > What do you mean here? Runtime services *code* or runtime services *data*? Code must obviously be remain encrypted (otherwise we cannot execute it in SEV). Runtime Services Data should also be mapped as encrypted (it is normal RAM that is not used for guest<->hypervisor exchange). > >> hence we end up accessing the flash as encrypted when OS requests to update the variables. > > I don't understand the "hence" here; I don't see how the implication follows. runtime services code and data should be encrypted. Runtime MMIO should be un-encrypted. > > Ohh, wait, in MarkMemoryRangeForRuntimeAccess(), we use "EfiGcdMemoryTypeSystemMemory". I don't have a clue why that is a good idea. That should have been EfiGcdMemoryTypeMemoryMappedIo. > > ... Anyway, I think first we should go with the "check EFI_MEMORY_RUNTIME attribute before setting it", in FtwNotificationEvent(). > >> >> A possible solution >> --------------------- >> To solve the issue, after QemuFlash is probed, I allocate an encrypted >> buffer and initialize this buffer with the contents from the flash memory. >> When SEV is enabled, we use newly allocated encrypted buffer in >> FwInstance->FvBase instead of the original flash region. The idea is >> FwInstance->if >> caller grabs the FwInstance->FvBase pointer and tries to access the >> FvVolumeHeader then it should get the data from the encrypted buffer. >> But if caller wants read/writes to/from the flash device then we >> internally use the original "unencrypted" flash region to access the data. > > No, this is neither safe, nor a desirable design. > > Safety: all accesses (via both pointers and FVB protocol members) that higher-level drives *think* go to the pflash chip must *actually* go to the pflash chip. > > Design: it had taken us years to get rid of various memory-emulated fake variable stores. They *all* suck in one way or another, with various obscure UEFI spec incompatibilities and corner cases. A strictly pflash-based varstore is not what we should compromise on. > >> With this >> patch, I have verified that OS is able to update the runtime variable >> and >> FC-28 installer is successfully able to complete the installation process. >> >> If you all agree with approach then I can rework any feedbacks and >> remove the rfc tag from the patch. If you have better suggestions then >> I am open to explore those as well. > > I'd like to understand the following: > > (1) why does FtwNotificationEvent() set the EFI_MEMORY_RUNTIME attribute itself, for the pflash range? -- in my opinion, that belongs in the flash driver. > > (2) Whether Star and Eric agree with setting the EFI_MEMORY_RUNTIME attribute in FtwNotificationEvent() only if the attribute is not already present. > > (3) The implication that you describe, between runtime services/code being mapped encrypted, and restoring the C-bit failing. > > (4) Whether we should modify MarkMemoryRangeForRuntimeAccess() to install the range into GCD as MMIO. (I feel *very* uncomfortable about this, however; the current code has existed as-is for years, and regressions look very risky.) > > My strong preference would be a patch for (2). > > Thanks, > Laszlo > >> Cc: Laszlo Ersek >> Contributed-under: TianoCore Contribution Agreement 1.1 >> Signed-off-by: Brijesh Singh >> --- >> .../FvbServicesRuntimeDxe.inf | 1 + >> .../FwBlockService.c | 37 +++++++++++++++++++--- >> 2 files changed, 34 insertions(+), 4 deletions(-) >> >> diff --git >> a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf >> b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf >> index d7b4ec06c4e6..6bb5c2093790 100644 >> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf >> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf >> @@ -54,6 +54,7 @@ [LibraryClasses] >> DevicePathLib >> DxeServicesTableLib >> MemoryAllocationLib >> + MemEncryptSevLib >> PcdLib >> UefiBootServicesTableLib >> UefiDriverEntryPoint >> diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c >> b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c >> index 558b395dff4a..e82b4ff70961 100644 >> --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c >> +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c >> @@ -36,6 +36,7 @@ >> #include #include >> #include >> >> +#include >> >> #include "FwBlockService.h" >> #include "QemuFlash.h" >> @@ -966,6 +967,7 @@ FvbInitialize ( >> UINTN Length; >> UINTN NumOfBlocks; >> RETURN_STATUS PcdStatus; >> + EFI_PHYSICAL_ADDRESS CryptedAddress; >> >> if (EFI_ERROR (QemuFlashInitialize ())) { >> // >> @@ -986,6 +988,24 @@ FvbInitialize ( >> BaseAddress = (UINTN) PcdGet32 (PcdOvmfFdBaseAddress); >> Length = PcdGet32 (PcdOvmfFirmwareFdSize); >> >> + // >> + // When SEV is enabled, allocate a encrypted buffer which will >> + contain a // encrypted copy of the Flash image. >> + // >> + if (MemEncryptSevIsEnabled ()) { >> + Status = gBS->AllocatePages ( >> + AllocateAnyPages, >> + EfiRuntimeServicesData, >> + EFI_SIZE_TO_PAGES(PcdGet32 (PcdOvmfFirmwareFdSize)), >> + &CryptedAddress >> + ); >> + ASSERT_EFI_ERROR (Status); >> + >> + CopyMem((VOID *)CryptedAddress, (VOID *)BaseAddress, Length); >> + >> + BaseAddress = CryptedAddress; >> + } >> + >> Status = InitializeVariableFvHeader (); >> if (EFI_ERROR (Status)) { >> DEBUG ((EFI_D_INFO, >> @@ -1091,24 +1111,33 @@ FvbInitialize ( >> // >> InstallProtocolInterfaces (FvbDevice); >> >> - MarkMemoryRangeForRuntimeAccess (BaseAddress, Length); >> + MarkMemoryRangeForRuntimeAccess ( >> + (UINTN) PcdGet32 (PcdOvmfFdBaseAddress), >> + Length >> + ); >> >> // >> // Set several PCD values to point to flash >> // >> PcdStatus = PcdSet64S ( >> PcdFlashNvStorageVariableBase64, >> - (UINTN) PcdGet32 (PcdOvmfFlashNvStorageVariableBase) >> + BaseAddress >> ); >> ASSERT_RETURN_ERROR (PcdStatus); >> PcdStatus = PcdSet32S ( >> PcdFlashNvStorageFtwWorkingBase, >> - PcdGet32 (PcdOvmfFlashNvStorageFtwWorkingBase) >> + BaseAddress + >> + PcdGet32(PcdFlashNvStorageVariableSize) + >> + PcdGet32(PcdOvmfFlashNvStorageEventLogSize) >> ); >> + >> ASSERT_RETURN_ERROR (PcdStatus); >> PcdStatus = PcdSet32S ( >> PcdFlashNvStorageFtwSpareBase, >> - PcdGet32 (PcdOvmfFlashNvStorageFtwSpareBase) >> + BaseAddress + >> + PcdGet32(PcdFlashNvStorageVariableSize) + >> + PcdGet32(PcdOvmfFlashNvStorageEventLogSize) + >> + PcdGet32(PcdFlashNvStorageFtwWorkingSize) >> ); >> ASSERT_RETURN_ERROR (PcdStatus); >> >> > > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel >