Kernel-hardening archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access
@ 2020-06-26 15:58 Ard Biesheuvel
  2020-06-26 15:58 ` [PATCH v3 1/2] arm64/acpi: disallow AML memory opregions to access kernel memory Ard Biesheuvel
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Ard Biesheuvel @ 2020-06-26 15:58 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-acpi, will, catalin.marinas, lorenzo.pieralisi,
	sudeep.holla, kernel-hardening, Ard Biesheuvel

v2:
- do a more elaborate check on the region, against the EFI memory map

v3:
- split into two patches
- fallback to __ioremap() for ACPI reclaim memory, in case it is not covered
  by the linear mapping (e.g., when booting a kdump kernel)

Ard Biesheuvel (2):
  arm64/acpi: disallow AML memory opregions to access kernel memory
  arm64/acpi: disallow writeable AML opregion mapping for EFI code
    regions

 arch/arm64/include/asm/acpi.h | 15 +---
 arch/arm64/kernel/acpi.c      | 75 ++++++++++++++++++++
 2 files changed, 76 insertions(+), 14 deletions(-)

-- 
2.27.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v3 1/2] arm64/acpi: disallow AML memory opregions to access kernel memory
  2020-06-26 15:58 [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access Ard Biesheuvel
@ 2020-06-26 15:58 ` Ard Biesheuvel
  2020-06-26 15:58 ` [PATCH v3 2/2] arm64/acpi: disallow writeable AML opregion mapping for EFI code regions Ard Biesheuvel
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Ard Biesheuvel @ 2020-06-26 15:58 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-acpi, will, catalin.marinas, lorenzo.pieralisi,
	sudeep.holla, kernel-hardening, Ard Biesheuvel,
	Jason A . Donenfeld

AML uses SystemMemory opregions to allow AML handlers to access MMIO
registers of, e.g., GPIO controllers, or access reserved regions of
memory that are owned by the firmware.

Currently, we also allow AML access to memory that is owned by the
kernel and mapped via the linear region, which does not seem to be
supported by a valid use case, and exposes the kernel's internal
state to AML methods that may be buggy and exploitable.

On arm64, ACPI support requires booting in EFI mode, and so we can cross
reference the requested region against the EFI memory map, rather than
just do a minimal check on the first page. So let's only permit regions
to be remapped by the ACPI core if
- they don't appear in the EFI memory map at all (which is the case for
  most MMIO), or
- they are covered by a single region in the EFI memory map, which is not
  of a type that describes memory that is given to the kernel at boot.

Reported-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/arm64/include/asm/acpi.h | 15 +----
 arch/arm64/kernel/acpi.c      | 66 ++++++++++++++++++++
 2 files changed, 67 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index a45366c3909b..bd68e1b7f29f 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -47,20 +47,7 @@
 pgprot_t __acpi_get_mem_attribute(phys_addr_t addr);
 
 /* ACPI table mapping after acpi_permanent_mmap is set */
-static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
-					    acpi_size size)
-{
-	/* For normal memory we already have a cacheable mapping. */
-	if (memblock_is_map_memory(phys))
-		return (void __iomem *)__phys_to_virt(phys);
-
-	/*
-	 * We should still honor the memory's attribute here because
-	 * crash dump kernel possibly excludes some ACPI (reclaim)
-	 * regions from memblock list.
-	 */
-	return __ioremap(phys, size, __acpi_get_mem_attribute(phys));
-}
+void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size);
 #define acpi_os_ioremap acpi_os_ioremap
 
 typedef u64 phys_cpuid_t;
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index a7586a4db142..01b861e225b0 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -261,6 +261,72 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
 	return __pgprot(PROT_DEVICE_nGnRnE);
 }
 
+void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
+{
+	efi_memory_desc_t *md, *region = NULL;
+	pgprot_t prot;
+
+	if (WARN_ON_ONCE(!efi_enabled(EFI_MEMMAP)))
+		return NULL;
+
+	for_each_efi_memory_desc(md) {
+		u64 end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+
+		if (phys < md->phys_addr || phys >= end)
+			continue;
+
+		if (phys + size > end) {
+			pr_warn(FW_BUG "requested region covers multiple EFI memory regions\n");
+			return NULL;
+		}
+		region = md;
+		break;
+	}
+
+	/*
+	 * It is fine for AML to remap regions that are not represented in the
+	 * EFI memory map at all, as it only describes normal memory, and MMIO
+	 * regions that require a virtual mapping to make them accessible to
+	 * the EFI runtime services.
+	 */
+	prot = __pgprot(PROT_DEVICE_nGnRnE);
+	if (region) {
+		switch (region->type) {
+		case EFI_LOADER_CODE:
+		case EFI_LOADER_DATA:
+		case EFI_BOOT_SERVICES_CODE:
+		case EFI_BOOT_SERVICES_DATA:
+		case EFI_CONVENTIONAL_MEMORY:
+		case EFI_PERSISTENT_MEMORY:
+			pr_warn(FW_BUG "requested region covers kernel memory @ %pa\n", &phys);
+			return NULL;
+
+		case EFI_ACPI_RECLAIM_MEMORY:
+			/*
+			 * ACPI reclaim memory is used to pass firmware tables
+			 * and other data that is intended for consumption by
+			 * the OS only, which may decide it wants to reclaim
+			 * that memory and use it for something else. We never
+			 * do that, but we usually add it to the linear map
+			 * anyway, in which case we should use the existing
+			 * mapping.
+			 */
+			if (memblock_is_map_memory(phys))
+				return (void __iomem *)__phys_to_virt(phys);
+			/* fall through */
+
+		default:
+			if (region->attribute & EFI_MEMORY_WB)
+				prot = PAGE_KERNEL;
+			else if (region->attribute & EFI_MEMORY_WT)
+				prot = __pgprot(PROT_NORMAL_WT);
+			else if (region->attribute & EFI_MEMORY_WC)
+				prot = __pgprot(PROT_NORMAL_NC);
+		}
+	}
+	return __ioremap(phys, size, prot);
+}
+
 /*
  * Claim Synchronous External Aborts as a firmware first notification.
  *
-- 
2.27.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v3 2/2] arm64/acpi: disallow writeable AML opregion mapping for EFI code regions
  2020-06-26 15:58 [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access Ard Biesheuvel
  2020-06-26 15:58 ` [PATCH v3 1/2] arm64/acpi: disallow AML memory opregions to access kernel memory Ard Biesheuvel
@ 2020-06-26 15:58 ` Ard Biesheuvel
  2020-07-08 16:17 ` [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access Ard Biesheuvel
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Ard Biesheuvel @ 2020-06-26 15:58 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: linux-acpi, will, catalin.marinas, lorenzo.pieralisi,
	sudeep.holla, kernel-hardening, Ard Biesheuvel

Given that the contents of EFI runtime code and data regions are
provided by the firmware, as well as the DSDT, it is not unimaginable
that AML code exists today that accesses EFI runtime code regions using
a SystemMemory OpRegion. There is nothing fundamentally wrong with that,
but since we take great care to ensure that executable code is never
mapped writeable and executable at the same time, we should not permit
AML to create writable mapping.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/arm64/kernel/acpi.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 01b861e225b0..455966401102 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -301,6 +301,15 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
 			pr_warn(FW_BUG "requested region covers kernel memory @ %pa\n", &phys);
 			return NULL;
 
+		case EFI_RUNTIME_SERVICES_CODE:
+			/*
+			 * This would be unusual, but not problematic per se,
+			 * as long as we take care not to create a writable
+			 * mapping for executable code.
+			 */
+			prot = PAGE_KERNEL_RO;
+			break;
+
 		case EFI_ACPI_RECLAIM_MEMORY:
 			/*
 			 * ACPI reclaim memory is used to pass firmware tables
-- 
2.27.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access
  2020-06-26 15:58 [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access Ard Biesheuvel
  2020-06-26 15:58 ` [PATCH v3 1/2] arm64/acpi: disallow AML memory opregions to access kernel memory Ard Biesheuvel
  2020-06-26 15:58 ` [PATCH v3 2/2] arm64/acpi: disallow writeable AML opregion mapping for EFI code regions Ard Biesheuvel
@ 2020-07-08 16:17 ` Ard Biesheuvel
  2020-07-09  8:42 ` Lorenzo Pieralisi
  2020-07-14 19:52 ` Catalin Marinas
  4 siblings, 0 replies; 6+ messages in thread
From: Ard Biesheuvel @ 2020-07-08 16:17 UTC (permalink / raw)
  To: Linux ARM, James Morse
  Cc: ACPI Devel Maling List, Will Deacon, Catalin Marinas,
	Lorenzo Pieralisi, Sudeep Holla, Kernel Hardening

(+ James)

On Fri, 26 Jun 2020 at 18:58, Ard Biesheuvel <ardb@kernel.org> wrote:
>
> v2:
> - do a more elaborate check on the region, against the EFI memory map
>
> v3:
> - split into two patches
> - fallback to __ioremap() for ACPI reclaim memory, in case it is not covered
>   by the linear mapping (e.g., when booting a kdump kernel)
>
> Ard Biesheuvel (2):
>   arm64/acpi: disallow AML memory opregions to access kernel memory
>   arm64/acpi: disallow writeable AML opregion mapping for EFI code
>     regions
>

With some adult supervision from James (thanks!), I have given this a
spin myself with kexec under QEMU/kvm, to boot a crashkernel, and
everything works as expected.


>  arch/arm64/include/asm/acpi.h | 15 +---
>  arch/arm64/kernel/acpi.c      | 75 ++++++++++++++++++++
>  2 files changed, 76 insertions(+), 14 deletions(-)
>
> --
> 2.27.0
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access
  2020-06-26 15:58 [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access Ard Biesheuvel
                   ` (2 preceding siblings ...)
  2020-07-08 16:17 ` [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access Ard Biesheuvel
@ 2020-07-09  8:42 ` Lorenzo Pieralisi
  2020-07-14 19:52 ` Catalin Marinas
  4 siblings, 0 replies; 6+ messages in thread
From: Lorenzo Pieralisi @ 2020-07-09  8:42 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: linux-arm-kernel, linux-acpi, will, catalin.marinas,
	sudeep.holla, kernel-hardening

On Fri, Jun 26, 2020 at 05:58:30PM +0200, Ard Biesheuvel wrote:
> v2:
> - do a more elaborate check on the region, against the EFI memory map
> 
> v3:
> - split into two patches
> - fallback to __ioremap() for ACPI reclaim memory, in case it is not covered
>   by the linear mapping (e.g., when booting a kdump kernel)
> 
> Ard Biesheuvel (2):
>   arm64/acpi: disallow AML memory opregions to access kernel memory
>   arm64/acpi: disallow writeable AML opregion mapping for EFI code
>     regions
> 
>  arch/arm64/include/asm/acpi.h | 15 +---
>  arch/arm64/kernel/acpi.c      | 75 ++++++++++++++++++++
>  2 files changed, 76 insertions(+), 14 deletions(-)

Thanks Ard for fixing this, for the series:

Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access
  2020-06-26 15:58 [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access Ard Biesheuvel
                   ` (3 preceding siblings ...)
  2020-07-09  8:42 ` Lorenzo Pieralisi
@ 2020-07-14 19:52 ` Catalin Marinas
  4 siblings, 0 replies; 6+ messages in thread
From: Catalin Marinas @ 2020-07-14 19:52 UTC (permalink / raw)
  To: Ard Biesheuvel, linux-arm-kernel
  Cc: Will Deacon, sudeep.holla, kernel-hardening, linux-acpi,
	lorenzo.pieralisi

On Fri, 26 Jun 2020 17:58:30 +0200, Ard Biesheuvel wrote:
> v2:
> - do a more elaborate check on the region, against the EFI memory map
> 
> v3:
> - split into two patches
> - fallback to __ioremap() for ACPI reclaim memory, in case it is not covered
>   by the linear mapping (e.g., when booting a kdump kernel)
> 
> [...]

Applied to arm64 (for-next/acpi), thanks!

[1/2] arm64/acpi: disallow AML memory opregions to access kernel memory
      https://git.kernel.org/arm64/c/1583052d111f
[2/2] arm64/acpi: disallow writeable AML opregion mapping for EFI code regions
      https://git.kernel.org/arm64/c/325f5585ec36

-- 
Catalin


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, back to index

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-26 15:58 [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access Ard Biesheuvel
2020-06-26 15:58 ` [PATCH v3 1/2] arm64/acpi: disallow AML memory opregions to access kernel memory Ard Biesheuvel
2020-06-26 15:58 ` [PATCH v3 2/2] arm64/acpi: disallow writeable AML opregion mapping for EFI code regions Ard Biesheuvel
2020-07-08 16:17 ` [PATCH v3 0/2] arm64/acpi: restrict AML opregion memory access Ard Biesheuvel
2020-07-09  8:42 ` Lorenzo Pieralisi
2020-07-14 19:52 ` Catalin Marinas

Kernel-hardening archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/kernel-hardening/0 kernel-hardening/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 kernel-hardening kernel-hardening/ https://lore.kernel.org/kernel-hardening \
		kernel-hardening@lists.openwall.com
	public-inbox-index kernel-hardening

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/com.openwall.lists.kernel-hardening


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git