From patchwork Tue May 3 12:45:53 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 67064 Delivered-To: patch@linaro.org Received: by 10.140.92.199 with SMTP id b65csp572029qge; Tue, 3 May 2016 05:46:06 -0700 (PDT) X-Received: by 10.98.2.79 with SMTP id 76mr1456906pfc.147.1462279566096; Tue, 03 May 2016 05:46:06 -0700 (PDT) Return-Path: Received: from ml01.01.org (ml01.01.org. [2001:19d0:306:5::1]) by mx.google.com with ESMTPS id lc4si4388493pab.144.2016.05.03.05.46.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 03 May 2016 05:46:06 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) client-ip=2001:19d0:306:5::1; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id A8BA11A1F2F; Tue, 3 May 2016 05:46:05 -0700 (PDT) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received: from mail-wm0-x233.google.com (mail-wm0-x233.google.com [IPv6:2a00:1450:400c:c09::233]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 104421A1F2B for ; Tue, 3 May 2016 05:46:04 -0700 (PDT) Received: by mail-wm0-x233.google.com with SMTP id g17so28390733wme.0 for ; Tue, 03 May 2016 05:46:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=pxTUV/T5+S76YF8ATY6ste/kBkUShRPPKkeYyFcGKIA=; b=SH/TbXSqiP5CunkP0G7S6NdYzEMQkCyFsHIF/JNkI+rp19LhDwbRO/fJns52no9SUA ox64sOhLns2i6JHk7F+uoDv6lDvtr2gwwOjtDpWGHPLnaOaxPjcDYANyjhXHi+5EFS3h FTmDp95wBHAYP047ZtYvsU3qTWDUWifEtY9Wc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=pxTUV/T5+S76YF8ATY6ste/kBkUShRPPKkeYyFcGKIA=; b=ksg9vjsieAXHqwKfo5udaEe0lfUKuGpZWwr6f34NGsU2tb+Rnd4Vm8cLpYab8I7kOJ cGOd+l8NYD1GDaRr/iO/TwwoyVWAlE8BYJbqZEuZOI7W13AFp/Rt4TifzDSZU/3jVP3Q 8Ecixw45oR3VcoO5M6f76iF4g2rQ7AP9hRGSdg748ufnO/c5sFbq8JgS+mosNh87qQKS iBLKATOx0RXuaSCZGXXQNOsqM8a8FA5zThYa2eOAyIVyAIM0rw+8aGtz07cYLgtUBgzK /akefPNHKKck0BJ4134mrggEqPHJYnLYHHZjtw3uOpS9zoXXop4xxD/RdkcUax8heMLU AEFQ== X-Gm-Message-State: AOPr4FX5jxKbypKm0lGBYVxX+bghNhICkiuN8Bd4vSwtVyCJdqZOFfkrn9IvO+2BZV4biPO1 X-Received: by 10.194.134.73 with SMTP id pi9mr2682307wjb.156.1462279562312; Tue, 03 May 2016 05:46:02 -0700 (PDT) Received: from localhost.localdomain ([195.55.142.58]) by smtp.gmail.com with ESMTPSA id ib1sm3668096wjb.48.2016.05.03.05.45.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 03 May 2016 05:46:01 -0700 (PDT) From: Ard Biesheuvel To: edk2-devel@lists.01.org, leif.lindholm@linaro.org, lersek@redhat.com, ryan.harkin@linaro.org Date: Tue, 3 May 2016 14:45:53 +0200 Message-Id: <1462279554-24821-2-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1462279554-24821-1-git-send-email-ard.biesheuvel@linaro.org> References: <1462279554-24821-1-git-send-email-ard.biesheuvel@linaro.org> Subject: [edk2] [RFC PATCH 1/2] ArmPkg/PermissionsPeCoffExtraActionLib: introduce new library X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Ard Biesheuvel , Charles.Garcia-Tobin@arm.com MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" This introduces a new implementation of PeCoffExtraActionLib that remaps PE/COFF executable sections as read-only if the section attributes allow it (and if the module is not a runtime driver) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel --- ArmPkg/Library/PermissionsPeCoffExtraActionLib/PermissionsPeCoffExtraActionLib.c | 202 ++++++++++++++++++++ ArmPkg/Library/PermissionsPeCoffExtraActionLib/PermissionsPeCoffExtraActionLib.inf | 45 +++++ 2 files changed, 247 insertions(+) -- 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/ArmPkg/Library/PermissionsPeCoffExtraActionLib/PermissionsPeCoffExtraActionLib.c b/ArmPkg/Library/PermissionsPeCoffExtraActionLib/PermissionsPeCoffExtraActionLib.c new file mode 100644 index 000000000000..565cbe4db57f --- /dev/null +++ b/ArmPkg/Library/PermissionsPeCoffExtraActionLib/PermissionsPeCoffExtraActionLib.c @@ -0,0 +1,202 @@ +/**@file + +PeCoff extra action library for PEI and DXE phase to set strict permissions on +PE/COFF executables using ArmLib + +Copyright (c) 2016, Linaro Ltd. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +typedef RETURN_STATUS (*REGION_PERMISSION_UPDATE_FUNC) ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +STATIC +RETURN_STATUS +UpdatePeCoffPermissions ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN REGION_PERMISSION_UPDATE_FUNC NoExecUpdater, + IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; + UINTN Size; + UINTN ReadSize; + UINT32 SectionHeaderOffset; + UINTN NumberOfSections; + UINTN Index; + EFI_IMAGE_SECTION_HEADER SectionHeader; + PE_COFF_LOADER_IMAGE_CONTEXT TmpContext; + EFI_PHYSICAL_ADDRESS Base; + + // + // We need to copy ImageContext since PeCoffLoaderGetImageInfo () + // will mangle the ImageAddress field + // + CopyMem (&TmpContext, ImageContext, sizeof (TmpContext)); + + if (TmpContext.PeCoffHeaderOffset == 0) { + Status = PeCoffLoaderGetImageInfo (&TmpContext); + if (RETURN_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, + "%a: PeCoffLoaderGetImageInfo () failed (Status = %r)\n", + __FUNCTION__, Status)); + return Status; + } + } + + if (TmpContext.IsTeImage && + TmpContext.ImageAddress == ImageContext->ImageAddress) { + DEBUG ((EFI_D_INFO, "%a: ignoring XIP TE image at 0x%lx\n", __FUNCTION__, + ImageContext->ImageAddress)); + return RETURN_SUCCESS; + } + + if (TmpContext.SectionAlignment < EFI_PAGE_SIZE) { + // + // The sections need to be at least 4 KB aligned, since that is the + // granularity at which we can tighten permissions. So just clear the + // noexec permissions on the entire region. + // + if (!TmpContext.IsTeImage) { + DEBUG ((EFI_D_WARN, + "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n", + __FUNCTION__, ImageContext->ImageAddress, TmpContext.SectionAlignment)); + } + Base = ImageContext->ImageAddress & ~(EFI_PAGE_SIZE - 1); + Size = ImageContext->ImageAddress - Base + ImageContext->ImageSize; + return NoExecUpdater (Base, ALIGN_VALUE (Size, EFI_PAGE_SIZE)); + } + + // + // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much + // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic + // determines if this is a PE32 or PE32+ image. The magic is in the same + // location in both images. + // + Hdr.Union = &HdrData; + Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION); + ReadSize = Size; + Status = TmpContext.ImageRead (TmpContext.Handle, + TmpContext.PeCoffHeaderOffset, &Size, Hdr.Pe32); + if (RETURN_ERROR (Status) || (Size != ReadSize)) { + DEBUG ((EFI_D_ERROR, + "%a: TmpContext.ImageRead () failed (Status = %r)\n", + __FUNCTION__, Status)); + return Status; + } + + ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE); + + SectionHeaderOffset = TmpContext.PeCoffHeaderOffset + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER); + NumberOfSections = (UINTN)(Hdr.Pe32->FileHeader.NumberOfSections); + + switch (Hdr.Pe32->OptionalHeader.Magic) { + case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC: + SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader; + break; + case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC: + SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader; + break; + default: + ASSERT (FALSE); + } + + // + // Iterate over the sections + // + for (Index = 0; Index < NumberOfSections; Index++) { + // + // Read section header from file + // + Size = sizeof (EFI_IMAGE_SECTION_HEADER); + ReadSize = Size; + Status = TmpContext.ImageRead (TmpContext.Handle, SectionHeaderOffset, + &Size, &SectionHeader); + if (RETURN_ERROR (Status) || (Size != ReadSize)) { + DEBUG ((EFI_D_ERROR, + "%a: TmpContext.ImageRead () failed (Status = %r)\n", + __FUNCTION__, Status)); + return Status; + } + + if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) != 0) { + Base = TmpContext.ImageAddress + SectionHeader.VirtualAddress; + NoExecUpdater (Base, SectionHeader.Misc.VirtualSize); + + if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) == 0 && + TmpContext.ImageType != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { + ReadOnlyUpdater (Base, SectionHeader.Misc.VirtualSize); + + DEBUG ((EFI_D_INFO, + "%a: Mapping section %d of image at 0x%lx with R-X permissions\n", + __FUNCTION__, Index, ImageContext->ImageAddress)); + } else { + DEBUG ((EFI_D_WARN, + "%a: Mapping section %d of image at 0x%lx with RWX permissions\n", + __FUNCTION__, Index, ImageContext->ImageAddress)); + } + } + SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + } + return RETURN_SUCCESS; +} + +/** + Performs additional actions after a PE/COFF image has been loaded and relocated. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that has already been loaded and relocated. + +**/ +VOID +EFIAPI +PeCoffLoaderRelocateImageExtraAction ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UpdatePeCoffPermissions (ImageContext, ArmClearMemoryRegionNoExec, + ArmSetMemoryRegionReadOnly); +} + + +/** + Performs additional actions just before a PE/COFF image is unloaded. Any resources + that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that is being unloaded. + +**/ +VOID +EFIAPI +PeCoffLoaderUnloadImageExtraAction ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UpdatePeCoffPermissions (ImageContext, ArmSetMemoryRegionNoExec, + ArmClearMemoryRegionReadOnly); +} diff --git a/ArmPkg/Library/PermissionsPeCoffExtraActionLib/PermissionsPeCoffExtraActionLib.inf b/ArmPkg/Library/PermissionsPeCoffExtraActionLib/PermissionsPeCoffExtraActionLib.inf new file mode 100644 index 000000000000..1a0641276376 --- /dev/null +++ b/ArmPkg/Library/PermissionsPeCoffExtraActionLib/PermissionsPeCoffExtraActionLib.inf @@ -0,0 +1,45 @@ +#/** @file +# +# PeCoff extra action library for PEI and DXE phase to set strict permissions on +# PE/COFF executables using ArmLib +# +# Copyright (c) 2016, Linaro Ltd. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PermissionsPeCoffExtraActionLib + FILE_GUID = CC4E5D9E-7096-4908-A1A9-E0F6E5606C86 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PeCoffExtraActionLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = ARM AARCH63 +# + +[Sources] + PermissionsPeCoffExtraActionLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + ArmLib + BaseLib + BaseMemoryLib + DebugLib + PeCoffLib