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);
/*
prev 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