Linux kernel -stable discussions
 help / color / mirror / Atom feed
From: Catalin Marinas <catalin.marinas@arm.com>
To: Xiangyu Chen <xiangyu.chen@windriver.com>
Cc: will@kernel.org, stable@vger.kernel.org, gregkh@linuxfoundation.org
Subject: Re: [PATCH 6.12 1/1] arm64: io: correct user memory type in ioremap_prot()
Date: Wed, 20 May 2026 18:01:45 +0100	[thread overview]
Message-ID: <ag3o-RbDTQWWazwF@arm.com> (raw)
In-Reply-To: <20260520091337.3799553-2-xiangyu.chen@windriver.com>

On Wed, May 20, 2026 at 05:13:37PM +0800, Xiangyu Chen wrote:
> generic_access_phys() passes a 'pgprot_t' value determined from the
> user mapping of the target 'pfn' being accessed by the kernel.
> On arm64, this 'pgprot_t' contains all non-address bits from the pte,
> including user permission controls (PTE_USER).
> 
> When a process attempts to read the target memory via cross-process
> subsystems (such as reading /proc/<pid>/mem or via ptrace), the kernel
> re-maps this memory using ioremap_prot(). Since the PTE_USER bit is
> incorrectly preserved in the temporary kernel-space mapping, it triggers
> a level 3 permission fault on systems with PAN (Privileged Access Never)
> enabled, resulting in an immediate kernel panic.
> 
> Upstream already fixed this issue in
> commit: 8f098037139b ("arm64: io: Extract user memory type in ioremap_prot()")
> 
> Directly porting the upstream patch's macro changes inside <asm/io.h>
> creates circular build dependencies due to the architecture-specific
> GENERIC_IOREMAP refactoring introduced in the stable kernel lifecycle.
> 
> To bypass header dependency traps safely, this backport confines the fix
> entirely inside the implementation layer of arch/arm64/mm/ioremap.c:
> 1. It uses pgprot_val() to safely unpack page properties into a pteval_t mask.
> 2. It introduces a targeted safety check (if (prot_val & PTE_USER)) to
>    selectively strip away volatile user permission parameters.
> 3. It maps the memory through pure kernel attributes, leaving standard
>    peripheral device drivers completely unaffected.
> 
> Tested-by: QEMU ARM64 (Cortex-A55, CONFIG_ARM64_PAN=y, /proc/<pid>/mem read)
> Fixes: 893dea9ccd08 ("arm64: Add HAVE_IOREMAP_PROT support")
> Signed-off-by: Xiangyu Chen <xiangyu.chen@windriver.com>

Instead of re-implementing this, could we cherry-pick the prior commit
renaming ioremap_prot() to __ioremap_prot() throughout arm64? It's not a
straightforward cherry-pick since we changed the prot arg from unsigned
long to pgprot_t (across multiple architectures), but with some minor
tweaks we can get the patch below. After this, 8f098037139b should apply
(hopefully unmodified). Please give it a try:

--------------------8<------------------------------------
From a38c5529973892914c1c967d43a2abcdcd9c6287 Mon Sep 17 00:00:00 2001
From: Will Deacon <will@kernel.org>
Date: Mon, 23 Feb 2026 22:10:10 +0000
Subject: [PATCH 1/2] arm64: io: Rename ioremap_prot() to __ioremap_prot()

commit f6bf47ab32e0863df50f5501d207dcdddb7fc507 upstream.

Rename our ioremap_prot() implementation to __ioremap_prot() and convert
all arch-internal callers over to the new function.

On this 6.12 branch, ioremap_prot() remains as an exported wrapper around
__ioremap_prot(), since the generic ioremap_prot() prototype still takes an
unsigned long protection value. The wrapper keeps the existing behaviour and
will be subsequently extended to handle user permissions in 'prot'.

Cc: Zeng Heng <zengheng4@huawei.com>
Cc: Jinjiang Tu <tujinjiang@huawei.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm64/include/asm/io.h |  7 ++++---
 arch/arm64/kernel/acpi.c    |  2 +-
 arch/arm64/mm/ioremap.c     | 12 +++++++++---
 3 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 1ada23a6ec19..e6ad41131d80 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -274,15 +274,16 @@ __iowrite64_copy(void __iomem *to, const void *from, size_t count)
 typedef int (*ioremap_prot_hook_t)(phys_addr_t phys_addr, size_t size,
 				   pgprot_t *prot);
 int arm64_ioremap_prot_hook_register(const ioremap_prot_hook_t hook);
+void __iomem *__ioremap_prot(phys_addr_t phys, size_t size, pgprot_t prot);
 
 #define ioremap_prot ioremap_prot
 
 #define _PAGE_IOREMAP PROT_DEVICE_nGnRE
 
 #define ioremap_wc(addr, size)	\
-	ioremap_prot((addr), (size), PROT_NORMAL_NC)
+	__ioremap_prot((addr), (size), __pgprot(PROT_NORMAL_NC))
 #define ioremap_np(addr, size)	\
-	ioremap_prot((addr), (size), PROT_DEVICE_nGnRnE)
+	__ioremap_prot((addr), (size), __pgprot(PROT_DEVICE_nGnRnE))
 
 /*
  * io{read,write}{16,32,64}be() macros
@@ -303,7 +304,7 @@ static inline void __iomem *ioremap_cache(phys_addr_t addr, size_t size)
 	if (pfn_is_map_memory(__phys_to_pfn(addr)))
 		return (void __iomem *)__phys_to_virt(addr);
 
-	return ioremap_prot(addr, size, PROT_NORMAL);
+	return __ioremap_prot(addr, size, __pgprot(PROT_NORMAL));
 }
 
 /*
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index e6f66491fbe9..a99476819e6b 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -379,7 +379,7 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
 				prot = __acpi_get_writethrough_mem_attribute();
 		}
 	}
-	return ioremap_prot(phys, size, pgprot_val(prot));
+	return __ioremap_prot(phys, size, prot);
 }
 
 /*
diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c
index 6cc0b7e7eb03..ca008a4732ae 100644
--- a/arch/arm64/mm/ioremap.c
+++ b/arch/arm64/mm/ioremap.c
@@ -14,11 +14,10 @@ int arm64_ioremap_prot_hook_register(ioremap_prot_hook_t hook)
 	return 0;
 }
 
-void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
-			   unsigned long prot)
+void __iomem *__ioremap_prot(phys_addr_t phys_addr, size_t size,
+			     pgprot_t pgprot)
 {
 	unsigned long last_addr = phys_addr + size - 1;
-	pgprot_t pgprot = __pgprot(prot);
 
 	/* Don't allow outside PHYS_MASK */
 	if (last_addr & ~PHYS_MASK)
@@ -39,6 +38,13 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
 
 	return generic_ioremap_prot(phys_addr, size, pgprot);
 }
+EXPORT_SYMBOL(__ioremap_prot);
+
+void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
+			   unsigned long prot)
+{
+	return __ioremap_prot(phys_addr, size, __pgprot(prot));
+}
 EXPORT_SYMBOL(ioremap_prot);
 
 /*

      parent reply	other threads:[~2026-05-20 17:01 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-20  9:13 proposal to fix CVE-2026-23346 on 6.12 or older kernel Xiangyu Chen
2026-05-20  9:13 ` [PATCH 6.12 1/1] arm64: io: correct user memory type in ioremap_prot() Xiangyu Chen
2026-05-20 11:17   ` Greg KH
2026-05-20 17:01   ` Catalin Marinas [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ag3o-RbDTQWWazwF@arm.com \
    --to=catalin.marinas@arm.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=stable@vger.kernel.org \
    --cc=will@kernel.org \
    --cc=xiangyu.chen@windriver.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox