From nobody Fri Dec 27 17:29:43 2024 Delivered-To: importer@patchew.org Received-SPF: none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) client-ip=198.145.21.10; envelope-from=edk2-devel-bounces@lists.01.org; helo=ml01.01.org; Authentication-Results: mx.zohomail.com; spf=none (zoho.com: 198.145.21.10 is neither permitted nor denied by domain of lists.01.org) smtp.mailfrom=edk2-devel-bounces@lists.01.org Return-Path: Received: from ml01.01.org (ml01.01.org [198.145.21.10]) by mx.zohomail.com with SMTPS id 1501709138777520.3651215403903; Wed, 2 Aug 2017 14:25:38 -0700 (PDT) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 5D027209589FA; Wed, 2 Aug 2017 14:23:13 -0700 (PDT) Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (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 DBDB0209589D0 for ; Wed, 2 Aug 2017 14:23:12 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 49E2F37EEC; Wed, 2 Aug 2017 21:25:23 +0000 (UTC) Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-47.phx2.redhat.com [10.3.116.47]) by smtp.corp.redhat.com (Postfix) with ESMTP id EB96117B57; Wed, 2 Aug 2017 21:25:21 +0000 (UTC) X-Original-To: edk2-devel@lists.01.org DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 49E2F37EEC Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=lersek@redhat.com From: Laszlo Ersek To: edk2-devel-01 Date: Wed, 2 Aug 2017 23:24:52 +0200 Message-Id: <20170802212453.19221-12-lersek@redhat.com> In-Reply-To: <20170802212453.19221-1-lersek@redhat.com> References: <20170802212453.19221-1-lersek@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Wed, 02 Aug 2017 21:25:23 +0000 (UTC) Subject: [edk2] [PATCH 11/12] OvmfPkg/IoMmuDxe: abort harder on memory encryption mask failures X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Jordan Justen , Tom Lendacky , Ard Biesheuvel MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" X-ZohoMail: RSF_4 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Upon a MemEncryptSevClearPageEncMask() failure in Map(), it wouldn't be difficult to release the bounce buffer that was implicitly allocated for BusMasterRead[64] and BusMasterWrite[64] operations. However, undoing any partial memory encryption mask changes -- partial page splitting and PTE modifications -- is practically impossible. (For example, restoring the encryption mask on the entire range has no reason to fare any better than the MemEncryptSevClearPageEncMask() call itself.) For this reason, keep ASSERT_EFI_ERROR(), but hang in RELEASE builds too, if MemEncryptSevClearPageEncMask() or MemEncryptSevSetPageEncMask() fails. Cc: Ard Biesheuvel Cc: Brijesh Singh Cc: Jordan Justen Cc: Tom Lendacky Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek --- OvmfPkg/IoMmuDxe/AmdSevIoMmu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c index 5049d19e9cb7..ee94cd4efbe2 100644 --- a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c +++ b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c @@ -89,175 +89,178 @@ EFIAPI IoMmuMap ( IN EDKII_IOMMU_PROTOCOL *This, IN EDKII_IOMMU_OPERATION Operation, IN VOID *HostAddress, IN OUT UINTN *NumberOfBytes, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping ) { EFI_STATUS Status; MAP_INFO *MapInfo; EFI_ALLOCATE_TYPE AllocateType; COMMON_BUFFER_HEADER *CommonBufferHeader; VOID *DecryptionSource; =20 if (HostAddress =3D=3D NULL || NumberOfBytes =3D=3D NULL || DeviceAddres= s =3D=3D NULL || Mapping =3D=3D NULL) { return EFI_INVALID_PARAMETER; } =20 // // Allocate a MAP_INFO structure to remember the mapping when Unmap() is // called later. // MapInfo =3D AllocatePool (sizeof (MAP_INFO)); if (MapInfo =3D=3D NULL) { Status =3D EFI_OUT_OF_RESOURCES; goto Failed; } =20 // // Initialize the MAP_INFO structure, except the PlainTextAddress field // MapInfo->Operation =3D Operation; MapInfo->NumberOfBytes =3D *NumberOfBytes; MapInfo->NumberOfPages =3D EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes= ); MapInfo->CryptedAddress =3D (UINTN)HostAddress; =20 // // In the switch statement below, we point "MapInfo->PlainTextAddress" t= o the // plaintext buffer, according to Operation. We also set "DecryptionSour= ce". // MapInfo->PlainTextAddress =3D MAX_ADDRESS; AllocateType =3D AllocateAnyPages; DecryptionSource =3D (VOID *)(UINTN)MapInfo->CryptedAddress; switch (Operation) { // // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buf= fer // is necessary regardless of whether the original (crypted) buffer cros= ses // the 4GB limit or not -- we have to allocate a separate plaintext buff= er. // The only variable is whether the plaintext buffer should be under 4GB. // case EdkiiIoMmuOperationBusMasterRead: case EdkiiIoMmuOperationBusMasterWrite: MapInfo->PlainTextAddress =3D BASE_4GB - 1; AllocateType =3D AllocateMaxAddress; // // fall through // case EdkiiIoMmuOperationBusMasterRead64: case EdkiiIoMmuOperationBusMasterWrite64: // // Allocate the implicit plaintext bounce buffer. // Status =3D gBS->AllocatePages ( AllocateType, EfiBootServicesData, MapInfo->NumberOfPages, &MapInfo->PlainTextAddress ); if (EFI_ERROR (Status)) { goto FreeMapInfo; } break; =20 // // For BusMasterCommonBuffer[64] operations, a to-be-plaintext buffer an= d a // stash buffer (for in-place decryption) have been allocated already, w= ith // AllocateBuffer(). We only check whether the address of the to-be-plai= ntext // buffer is low enough for the requested operation. // case EdkiiIoMmuOperationBusMasterCommonBuffer: if ((MapInfo->CryptedAddress > BASE_4GB) || (EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) > BASE_4GB - MapInfo->CryptedAddress)) { // // CommonBuffer operations cannot be remapped. If the common buffer = is // above 4GB, then it is not possible to generate a mapping, so retu= rn an // error. // Status =3D EFI_UNSUPPORTED; goto FreeMapInfo; } // // fall through // case EdkiiIoMmuOperationBusMasterCommonBuffer64: // // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer(). // MapInfo->PlainTextAddress =3D MapInfo->CryptedAddress; // // Stash the crypted data. // CommonBufferHeader =3D (COMMON_BUFFER_HEADER *)( (UINTN)MapInfo->CryptedAddress - EFI_PAGE_SIZE ); ASSERT (CommonBufferHeader->Signature =3D=3D COMMON_BUFFER_SIG); CopyMem ( CommonBufferHeader->StashBuffer, (VOID *)(UINTN)MapInfo->CryptedAddress, MapInfo->NumberOfBytes ); // // Point "DecryptionSource" to the stash buffer so that we decrypt // it to the original location, after the switch statement. // DecryptionSource =3D CommonBufferHeader->StashBuffer; break; =20 default: // // Operation is invalid // Status =3D EFI_INVALID_PARAMETER; goto FreeMapInfo; } =20 // // Clear the memory encryption mask on the plaintext buffer. // Status =3D MemEncryptSevClearPageEncMask ( 0, MapInfo->PlainTextAddress, MapInfo->NumberOfPages, TRUE ); - ASSERT_EFI_ERROR(Status); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + CpuDeadLoop (); + } =20 // // If this is a read operation from the Bus Master's point of view, // then copy the contents of the real buffer into the mapped buffer // so the Bus Master can read the contents of the real buffer. // // For BusMasterCommonBuffer[64] operations, the CopyMem() below will de= crypt // the original data (from the stash buffer) back to the original locati= on. // if (Operation =3D=3D EdkiiIoMmuOperationBusMasterRead || Operation =3D=3D EdkiiIoMmuOperationBusMasterRead64 || Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer || Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer64) { CopyMem ( (VOID *) (UINTN) MapInfo->PlainTextAddress, DecryptionSource, MapInfo->NumberOfBytes ); } =20 // // Populate output parameters. // *DeviceAddress =3D MapInfo->PlainTextAddress; *Mapping =3D MapInfo; =20 DEBUG (( DEBUG_VERBOSE, "%a PlainText 0x%Lx Crypted 0x%Lx Pages 0x%Lx Bytes 0x%Lx\n", __FUNCTION__, MapInfo->PlainTextAddress, MapInfo->CryptedAddress, (UINT64)MapInfo->NumberOfPages, (UINT64)MapInfo->NumberOfBytes )); =20 return EFI_SUCCESS; @@ -287,129 +290,132 @@ EFIAPI IoMmuUnmap ( IN EDKII_IOMMU_PROTOCOL *This, IN VOID *Mapping ) { MAP_INFO *MapInfo; EFI_STATUS Status; COMMON_BUFFER_HEADER *CommonBufferHeader; VOID *EncryptionTarget; =20 if (Mapping =3D=3D NULL) { return EFI_INVALID_PARAMETER; } =20 MapInfo =3D (MAP_INFO *)Mapping; =20 // // For BusMasterWrite[64] operations and BusMasterCommonBuffer[64] opera= tions // we have to encrypt the results, ultimately to the original place (i.e= ., // "MapInfo->CryptedAddress"). // // For BusMasterCommonBuffer[64] operations however, this encryption has= to // land in-place, so divert the encryption to the stash buffer first. // EncryptionTarget =3D (VOID *)(UINTN)MapInfo->CryptedAddress; =20 switch (MapInfo->Operation) { case EdkiiIoMmuOperationBusMasterCommonBuffer: case EdkiiIoMmuOperationBusMasterCommonBuffer64: ASSERT (MapInfo->PlainTextAddress =3D=3D MapInfo->CryptedAddress); =20 CommonBufferHeader =3D (COMMON_BUFFER_HEADER *)( (UINTN)MapInfo->PlainTextAddress - EFI_PAGE_SIZE ); ASSERT (CommonBufferHeader->Signature =3D=3D COMMON_BUFFER_SIG); EncryptionTarget =3D CommonBufferHeader->StashBuffer; // // fall through // =20 case EdkiiIoMmuOperationBusMasterWrite: case EdkiiIoMmuOperationBusMasterWrite64: CopyMem ( EncryptionTarget, (VOID *) (UINTN) MapInfo->PlainTextAddress, MapInfo->NumberOfBytes ); break; =20 default: // // nothing to encrypt after BusMasterRead[64] operations // break; } =20 DEBUG (( DEBUG_VERBOSE, "%a PlainText 0x%Lx Crypted 0x%Lx Pages 0x%Lx Bytes 0x%Lx\n", __FUNCTION__, MapInfo->PlainTextAddress, MapInfo->CryptedAddress, (UINT64)MapInfo->NumberOfPages, (UINT64)MapInfo->NumberOfBytes )); =20 // // Restore the memory encryption mask on the area we used to hold the // plaintext. // Status =3D MemEncryptSevSetPageEncMask ( 0, MapInfo->PlainTextAddress, MapInfo->NumberOfPages, TRUE ); - ASSERT_EFI_ERROR(Status); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + CpuDeadLoop (); + } =20 // // For BusMasterCommonBuffer[64] operations, copy the stashed data to the // original (now encrypted) location. // // For all other operations, fill the late bounce buffer (which existed = as // plaintext at some point) with zeros, and then release it. // if (MapInfo->Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer || MapInfo->Operation =3D=3D EdkiiIoMmuOperationBusMasterCommonBuffer64= ) { CopyMem ( (VOID *)(UINTN)MapInfo->CryptedAddress, CommonBufferHeader->StashBuffer, MapInfo->NumberOfBytes ); } else { ZeroMem ( (VOID *)(UINTN)MapInfo->PlainTextAddress, EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) ); gBS->FreePages (MapInfo->PlainTextAddress, MapInfo->NumberOfPages); } =20 // // Free the MAP_INFO structure. // FreePool (Mapping); return EFI_SUCCESS; } =20 /** Allocates pages that are suitable for an OperationBusMasterCommonBuffer = or OperationBusMasterCommonBuffer64 mapping. =20 @param This The protocol instance pointer. @param Type This parameter is not used and must be ign= ored. @param MemoryType The type of memory to allocate, EfiBootServicesData or EfiRuntimeServicesD= ata. @param Pages The number of pages to allocate. @param HostAddress A pointer to store the base system memory address of the allocated range. @param Attributes The requested bit mask of attributes for t= he allocated range. =20 @retval EFI_SUCCESS The requested memory pages were allocated. @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are MEMORY_WRITE_COMBINE and MEMORY_CACHED. @retval EFI_INVALID_PARAMETER One or more parameters are invalid. @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. =20 **/ --=20 2.13.1.3.g8be5a757fa67 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel