From: Lorenzo Pieralisi <hidden> Date: 2020-06-23 16:28:49
On Tue, Jun 23, 2020 at 11:37:55AM +0200, Ard Biesheuvel wrote:
quoted hunk
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>
---
v2: do a more elaborate check on the region, against the EFI memory map
arch/arm64/include/asm/acpi.h | 15 +---
arch/arm64/kernel/acpi.c | 72 ++++++++++++++++++++
2 files changed, 73 insertions(+), 14 deletions(-)
@@ -47,20 +47,7 @@pgprot_t__acpi_get_mem_attribute(phys_addr_taddr);/* ACPI table mapping after acpi_permanent_mmap is set */-staticinlinevoid__iomem*acpi_os_ioremap(acpi_physical_addressphys,-acpi_sizesize)-{-/* For normal memory we already have a cacheable mapping. */-if(memblock_is_map_memory(phys))-return(void__iomem*)__phys_to_virt(phys);--/*-*Weshouldstillhonorthememory'sattributeherebecause-*crashdumpkernelpossiblyexcludessomeACPI(reclaim)-*regionsfrommemblocklist.-*/-return__ioremap(phys,size,__acpi_get_mem_attribute(phys));-}+void__iomem*acpi_os_ioremap(acpi_physical_addressphys,acpi_sizesize);#define acpi_os_ioremap acpi_os_ioremaptypedefu64phys_cpuid_t;
@@ -261,6 +261,78 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)return__pgprot(PROT_DEVICE_nGnRnE);}+void__iomem*acpi_os_ioremap(acpi_physical_addressphys,acpi_sizesize)+{+efi_memory_desc_t*md,*region=NULL;+pgprot_tprot;++if(WARN_ON_ONCE(!efi_enabled(EFI_MEMMAP)))+returnNULL;++for_each_efi_memory_desc(md){+u64end=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");+returnNULL;+}+region=md;+break;+}++/*+*ItisfineforAMLtoremapregionsthatarenotrepresentedinthe+*EFImemorymapatall,asitonlydescribesnormalmemory,andMMIO+*regionsthatrequireavirtualmappingtomakethemaccessibleto+*theEFIruntimeservices.+*/+prot=__pgprot(PROT_DEVICE_nGnRnE);+if(region){+switch(region->type){+caseEFI_LOADER_CODE:+caseEFI_LOADER_DATA:+caseEFI_BOOT_SERVICES_CODE:+caseEFI_BOOT_SERVICES_DATA:+caseEFI_CONVENTIONAL_MEMORY:+caseEFI_PERSISTENT_MEMORY:+pr_warn(FW_BUG"requested region covers kernel memory @ %pa\n",&phys);+returnNULL;++caseEFI_ACPI_RECLAIM_MEMORY:+/*+*ACPIreclaimmemoryisusedtopassfirmwaretables+*andotherdatathatisintendedforconsumptionby+*theOSonly,whichmaydecideitwantstoreclaim+*thatmemoryanduseitforsomethingelse.Wenever+*dothat,butweaddittothelinearmapanyway,and+*sowemustusetheexistingmapping.+*/+return(void__iomem*)__phys_to_virt(phys);
For my own understanding - we have to keep this mapping (given the
current kernel code and tables handling) which means that this patch
mitigates (correctly) the issue but can't solve it in its entirety.
+ 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;
Nit: IIUC this tweaks the current behaviour (so it is probably better
to move this change to another patch).
Other than that the patch is sound and probably the best we could
do to harden the code, goes without saying - it requires testing.
Thanks for putting it together.
Lorenzo
+ break;
+
+ 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
On Tue, 23 Jun 2020 at 18:27, Lorenzo Pieralisi
[off-list ref] wrote:
On Tue, Jun 23, 2020 at 11:37:55AM +0200, Ard Biesheuvel wrote:
quoted
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>
---
v2: do a more elaborate check on the region, against the EFI memory map
arch/arm64/include/asm/acpi.h | 15 +---
arch/arm64/kernel/acpi.c | 72 ++++++++++++++++++++
2 files changed, 73 insertions(+), 14 deletions(-)
@@ -47,20 +47,7 @@pgprot_t__acpi_get_mem_attribute(phys_addr_taddr);/* ACPI table mapping after acpi_permanent_mmap is set */-staticinlinevoid__iomem*acpi_os_ioremap(acpi_physical_addressphys,-acpi_sizesize)-{-/* For normal memory we already have a cacheable mapping. */-if(memblock_is_map_memory(phys))-return(void__iomem*)__phys_to_virt(phys);--/*-*Weshouldstillhonorthememory'sattributeherebecause-*crashdumpkernelpossiblyexcludessomeACPI(reclaim)-*regionsfrommemblocklist.-*/-return__ioremap(phys,size,__acpi_get_mem_attribute(phys));-}+void__iomem*acpi_os_ioremap(acpi_physical_addressphys,acpi_sizesize);#define acpi_os_ioremap acpi_os_ioremaptypedefu64phys_cpuid_t;
@@ -261,6 +261,78 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)return__pgprot(PROT_DEVICE_nGnRnE);}+void__iomem*acpi_os_ioremap(acpi_physical_addressphys,acpi_sizesize)+{+efi_memory_desc_t*md,*region=NULL;+pgprot_tprot;++if(WARN_ON_ONCE(!efi_enabled(EFI_MEMMAP)))+returnNULL;++for_each_efi_memory_desc(md){+u64end=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");+returnNULL;+}+region=md;+break;+}++/*+*ItisfineforAMLtoremapregionsthatarenotrepresentedinthe+*EFImemorymapatall,asitonlydescribesnormalmemory,andMMIO+*regionsthatrequireavirtualmappingtomakethemaccessibleto+*theEFIruntimeservices.+*/+prot=__pgprot(PROT_DEVICE_nGnRnE);+if(region){+switch(region->type){+caseEFI_LOADER_CODE:+caseEFI_LOADER_DATA:+caseEFI_BOOT_SERVICES_CODE:+caseEFI_BOOT_SERVICES_DATA:+caseEFI_CONVENTIONAL_MEMORY:+caseEFI_PERSISTENT_MEMORY:+pr_warn(FW_BUG"requested region covers kernel memory @ %pa\n",&phys);+returnNULL;++caseEFI_ACPI_RECLAIM_MEMORY:+/*+*ACPIreclaimmemoryisusedtopassfirmwaretables+*andotherdatathatisintendedforconsumptionby+*theOSonly,whichmaydecideitwantstoreclaim+*thatmemoryanduseitforsomethingelse.Wenever+*dothat,butweaddittothelinearmapanyway,and+*sowemustusetheexistingmapping.+*/+return(void__iomem*)__phys_to_virt(phys);
For my own understanding - we have to keep this mapping (given the
current kernel code and tables handling) which means that this patch
mitigates (correctly) the issue but can't solve it in its entirety.
Yes. The ACPI core uses acpi_os_ioremap() to map all the ACPI tables
at boot, which are passed in ACPI reclaim memory, which is already
mapped in the linear region at this point.
Actually, come to think of it, this is probably incorrect for kexec,
as the kernel may not have mapped such regions in its linear map, so
we still need the memblock_is_map_memory() test here.
quoted
+ 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;
Nit: IIUC this tweaks the current behaviour (so it is probably better
to move this change to another patch).
OK
Other than that the patch is sound and probably the best we could
do to harden the code, goes without saying - it requires testing.
Indeed. I will do some testing on the systems I have access to, and
hopefully, other will as well.
Thanks for putting it together.
Lorenzo
quoted
+ break;
+
+ 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
From: Will Deacon <will@kernel.org> Date: 2020-07-03 16:16:07
On Tue, Jun 23, 2020 at 06:32:25PM +0200, Ard Biesheuvel wrote:
On Tue, 23 Jun 2020 at 18:27, Lorenzo Pieralisi
[off-list ref] wrote:
quoted
On Tue, Jun 23, 2020 at 11:37:55AM +0200, Ard Biesheuvel wrote:
quoted
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>
---
v2: do a more elaborate check on the region, against the EFI memory map
arch/arm64/include/asm/acpi.h | 15 +---
arch/arm64/kernel/acpi.c | 72 ++++++++++++++++++++
2 files changed, 73 insertions(+), 14 deletions(-)
[...]
quoted
quoted
+ 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;
Nit: IIUC this tweaks the current behaviour (so it is probably better
to move this change to another patch).
OK
quoted
Other than that the patch is sound and probably the best we could
do to harden the code, goes without saying - it requires testing.
Indeed. I will do some testing on the systems I have access to, and
hopefully, other will as well.
From: Will Deacon <will@kernel.org> Date: 2020-07-03 16:17:53
On Fri, Jul 03, 2020 at 05:14:29PM +0100, Will Deacon wrote:
Is this 5.9 material, or do you want it to go in as a fix?
Sorry, just spotted the v3, but the same question applies there!
Will
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Fri, 3 Jul 2020 at 18:16, Will Deacon [off-list ref] wrote:
On Fri, Jul 03, 2020 at 05:14:29PM +0100, Will Deacon wrote:
quoted
Is this 5.9 material, or do you want it to go in as a fix?
Sorry, just spotted the v3, but the same question applies there!
This needs a bit more test coverage than we have been able to provide
so far, especially regarding kexec/kdump etc. So even though I think
this ultimately belongs in -stable, that does not necessarily mean it
should go into the next -rc right away.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel