From: Xiangyu Chen <xiangyu.chen@windriver.com>
To: Catalin Marinas <catalin.marinas@arm.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, 27 May 2026 11:01:04 +0800 [thread overview]
Message-ID: <3f1485f0-905b-4c5a-bd66-fb03aa9ea0cb@windriver.com> (raw)
In-Reply-To: <ag3o-RbDTQWWazwF@arm.com>
On 5/21/26 01:01, Catalin Marinas wrote:
> CAUTION: This email comes from a non Wind River email account!
> Do not click links or open attachments unless you recognize the sender and know the content is safe.
>
> 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:
Thanks for your suggestion.
After reviewing the code, it appears we cannot directly backport commit
f6bf47ab32e0 ("arm64: io: Rename ioremap_prot() to __ioremap_prot()") to
older stable kernels. This is because commit f6bf47ab32e0 depends on
commit 86758b504864 ("mm/ioremap: pass pgprot_t to ioremap_prot()
instead of unsigned long").
Therefore, a clean backport would require the following sequence:
Cherry-pick commit 86758b504864 ("mm/ioremap: pass pgprot_t to
ioremap_prot() instead of unsigned long")
Cherry-pick commit f6bf47ab32e0 ("arm64: io: Rename ioremap_prot() to
__ioremap_prot()")
Cherry-pick commit 8f098037139b ("arm64: io: Extract user memory type in
ioremap_prot()")
However, the main roadblock is that commit 86758b504864 introduces
significant architectural conflicts on older kernels like 6.12 and 6.6
due to context changes. While I could manually resolve these conflicts
to pass compilation, the patch touches numerous boards and CPU
architectures within the arch/ directory. Since I do not have access to
these boards for verification, forcing this cherry-pick carries a high
risk of introducing unforeseen regressions into a stable branch.
Reimplementing or hacking the fix for older branches might similarly
jeopardize kernel stability. Given these risks, I suggest we keep this
discussion archived in the mailing list rather than merging the patches.
This way, if other users encounter this CVE on older kernels, they can
refer to this thread for a potential workaround or solution for their
specific systems.
Thanks,
Br,
Xiangyu
>
> --------------------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);
>
> /*
next prev parent reply other threads:[~2026-05-27 3:01 UTC|newest]
Thread overview: 6+ 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
2026-05-27 3:01 ` Xiangyu Chen [this message]
2026-05-27 8:23 ` Catalin Marinas
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=3f1485f0-905b-4c5a-bd66-fb03aa9ea0cb@windriver.com \
--to=xiangyu.chen@windriver.com \
--cc=catalin.marinas@arm.com \
--cc=gregkh@linuxfoundation.org \
--cc=stable@vger.kernel.org \
--cc=will@kernel.org \
/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