All of lore.kernel.org
 help / color / mirror / Atom feed
* proposal to fix CVE-2026-23346 on 6.12 or older kernel
@ 2026-05-20  9:13 Xiangyu Chen
  2026-05-20  9:13 ` [PATCH 6.12 1/1] arm64: io: correct user memory type in ioremap_prot() Xiangyu Chen
  0 siblings, 1 reply; 6+ messages in thread
From: Xiangyu Chen @ 2026-05-20  9:13 UTC (permalink / raw)
  To: will; +Cc: catalin.marinas, stable, gregkh

Hi Will,

I am looking a CVE issue(CVE-2026-23346) on stable kernel. It was fixed by
commit:8f098037139b ("arm64: io: Extract user memory type in ioremap_prot()").

I have already reproduced it on 6.12 and 6.6 stable kernel[1], but
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.

Since this issue was triggered by 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.

To bypass header dependency traps safely, I have changed the backport code, 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.

(see [PATCH 6.12 1/1] arm64: io: correct user memory type in ioremap_prot() ).
The code I have verified on qemuarm64, after applied the fix, crash won't happen anymore.

So, could you help to review, if we can use this solution to fix this CVE on an older stable
kernel? Thanks.


[1] Test steps:

1.1 Code & script:
C code:
------
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

// Using QEMU RTC HW address
#define PHYSICAL_ADDR 0x09010000 
#define MAP_SIZE 4096

int main() {
    int i = 180;
    int fd = open("/dev/mem", O_RDWR | O_SYNC);
    if (fd < 0) {
        perror("failed to open /dev/mem");
        return 1;
    }   

    // Start map
    void *map_base = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PHYSICAL_ADDR);
    if (map_base == MAP_FAILED) {
        perror("failed to mmap");
        close(fd);
        return 1;
    }

    printf("Put those info to script PID:%d, VADDR:%p\n", getpid(), map_base);

    // Keep running for script trigger the issue.
    while(i > 0) {
        sleep(1);
        i--;
    }

    munmap(map_base, MAP_SIZE);
    close(fd);
    return 0;
}
------ End of C code ------

Python code:
-----------
python3 -c '
pid = 506
vaddr = 0x7f9de3f000
f = open(f"/proc/{pid}/mem", "rb")
f.seek(vaddr)
f.read(4)
'
------End of Python code------

1.2 Usage:
Ensure kernel enabled the CONFIG_ARM64_PAN and CONFIG_DEVMEM

Start Qemuarm64 with -cpu cortex-a55 -M virt, e.g.:
qemu-system-aarch64 \
    -cpu cortex-a55 \
    -M virt \
    -m 2G \
    -smp 2 \
    -kernel ./arch/arm64/boot/Image \
    -append "console=ttyAMA0 root=/dev/vda rw earlycon" \
    -drive if=none,file=rootfs.img,id=hd0,format=raw \
    -device virtio-blk-device,drive=hd0 \
    -nographic


After enter the qemu, using cat /proc/iomem to get a vaild MMIO
address, here is using RTC address (#define PHYSICAL_ADDR 0x09010000).

Build the C code, put the binary to target qemu system and run it, the
C reproducer would output the PID and mapped address, here example pid
is 506 and virtual address is 0x7f9de3f000.

Fill pid and virtual address to python code, without fix, kernel would crash
with "Unable to handle kernel read from unreadable memory".
Based on crash info, pstate: 20400005 (... +PAN ...) and FSC = 0x0f: level 3 permission fault
Call trace:
[ 678.563102] __memcpy_fromio+0x50/0x98
[ 678.563436] __access_remote_vm+0x294/0x3a8
[ 678.563901] access_remote_vm+0x18/0x30
[ 678.564308] mem_rw+0x1e0/0x370
[ 678.564534] mem_read+0x1c/0x30
[ 678.564754] vfs_read+0xcc/0x2d0
[ 678.564975] ksys_read+0x7c/0x120
[ 678.565192] __arm64_sys_read+0x24/0x38
[ 678.565450] invoke_syscall+0x5c/0x138
[ 678.565729] el0_svc_common.constprop.0+0x48/0xf0
[ 678.566038] do_el0_svc+0x24/0x38
[ 678.566264] el0_svc+0x38/0x108
[ 678.566514] el0t_64_sync_handler+0x120/0x130
[ 678.566823] el0t_64_sync+0x190/0x198
....

The behavior is the same as description of
commit:8f098037139b ("arm64: io: Extract user memory type in ioremap_prot()")


Thanks!

Br,
Xiangyu

Xiangyu Chen (1):
  arm64: io: correct user memory type in ioremap_prot()

 arch/arm64/mm/ioremap.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

-- 
2.34.1


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

* [PATCH 6.12 1/1] arm64: io: correct user memory type in ioremap_prot()
  2026-05-20  9:13 proposal to fix CVE-2026-23346 on 6.12 or older kernel Xiangyu Chen
@ 2026-05-20  9:13 ` Xiangyu Chen
  2026-05-20 11:17   ` Greg KH
  2026-05-20 17:01   ` Catalin Marinas
  0 siblings, 2 replies; 6+ messages in thread
From: Xiangyu Chen @ 2026-05-20  9:13 UTC (permalink / raw)
  To: will; +Cc: catalin.marinas, stable, gregkh

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>
---
 arch/arm64/mm/ioremap.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c
index 6cc0b7e7eb03..48a16a360b42 100644
--- a/arch/arm64/mm/ioremap.c
+++ b/arch/arm64/mm/ioremap.c
@@ -19,6 +19,7 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
 {
 	unsigned long last_addr = phys_addr + size - 1;
 	pgprot_t pgprot = __pgprot(prot);
+	pteval_t prot_val = pgprot_val(pgprot);
 
 	/* Don't allow outside PHYS_MASK */
 	if (last_addr & ~PHYS_MASK)
@@ -27,7 +28,6 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
 	/* Don't allow RAM to be mapped. */
 	if (WARN_ON(pfn_is_map_memory(__phys_to_pfn(phys_addr))))
 		return NULL;
-
 	/*
 	 * If a hook is registered (e.g. for confidential computing
 	 * purposes), call that now and barf if it fails.
@@ -37,6 +37,15 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
 		return NULL;
 	}
 
+	/*
+	 * If this is a user mapping (from generic_access_phys), extract
+	 * only the memory type and drop permission bits to avoid PAN faults.
+	 */
+	if (prot_val & PTE_USER) {
+		pgprot = __pgprot_modify(PAGE_KERNEL, PTE_ATTRINDX_MASK,
+					 prot_val & PTE_ATTRINDX_MASK);
+	}
+
 	return generic_ioremap_prot(phys_addr, size, pgprot);
 }
 EXPORT_SYMBOL(ioremap_prot);
-- 
2.34.1


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

* Re: [PATCH 6.12 1/1] arm64: io: correct user memory type in ioremap_prot()
  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
  1 sibling, 0 replies; 6+ messages in thread
From: Greg KH @ 2026-05-20 11:17 UTC (permalink / raw)
  To: Xiangyu Chen; +Cc: will, catalin.marinas, stable

On Wed, May 20, 2026 at 05:13:37PM +0800, Xiangyu Chen wrote:
> @@ -27,7 +28,6 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
>  	/* Don't allow RAM to be mapped. */
>  	if (WARN_ON(pfn_is_map_memory(__phys_to_pfn(phys_addr))))
>  		return NULL;
> -
>  	/*
>  	 * If a hook is registered (e.g. for confidential computing
>  	 * purposes), call that now and barf if it fails.

Why remove this line?


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

* Re: [PATCH 6.12 1/1] arm64: io: correct user memory type in ioremap_prot()
  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
  1 sibling, 1 reply; 6+ messages in thread
From: Catalin Marinas @ 2026-05-20 17:01 UTC (permalink / raw)
  To: Xiangyu Chen; +Cc: will, stable, gregkh

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

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

* Re: [PATCH 6.12 1/1] arm64: io: correct user memory type in ioremap_prot()
  2026-05-20 17:01   ` Catalin Marinas
@ 2026-05-27  3:01     ` Xiangyu Chen
  2026-05-27  8:23       ` Catalin Marinas
  0 siblings, 1 reply; 6+ messages in thread
From: Xiangyu Chen @ 2026-05-27  3:01 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: will, stable, gregkh


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

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

* Re: [PATCH 6.12 1/1] arm64: io: correct user memory type in ioremap_prot()
  2026-05-27  3:01     ` Xiangyu Chen
@ 2026-05-27  8:23       ` Catalin Marinas
  0 siblings, 0 replies; 6+ messages in thread
From: Catalin Marinas @ 2026-05-27  8:23 UTC (permalink / raw)
  To: Xiangyu Chen; +Cc: will, stable, gregkh

On Wed, May 27, 2026 at 11:01:04AM +0800, Xiangyu Chen wrote:
> On 5/21/26 01:01, Catalin Marinas wrote:
> > 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").

My proposed backport of f6bf47ab32e0 took care of using unsigned long
instead of pgprot_t since the dependencies get too complicated. Could
you try my backport of f6bf47ab32e0 together with cherry-picking
8f098037139b. The latter may need some adjustment of pgprot_t as well
but at least the final form will look fairly similar to upstream.

-- 
Catalin

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

end of thread, other threads:[~2026-05-27  8:23 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
2026-05-27  8:23       ` Catalin Marinas

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.