summaryrefslogtreecommitdiff
path: root/arch/arm64
diff options
context:
space:
mode:
authorWill Deacon <will@kernel.org>2026-02-23 22:10:11 +0000
committerSasha Levin <sashal@kernel.org>2026-03-12 07:09:20 -0400
commitd1ad8fe7f72d73e1617bac79f2ec7a3bedf47e2a (patch)
tree9fdd28a44d0a530ece2ab72df4191979eaf1ff52 /arch/arm64
parentf1a13183a4cd1a0c607af8cc76ca9f2f57c0b561 (diff)
arm64: io: Extract user memory type in ioremap_prot()
[ Upstream commit 8f098037139b294050053123ab2bc0f819d08932 ] The only caller of ioremap_prot() outside of the generic ioremap() implementation is generic_access_phys(), which passes a 'pgprot_t' value determined from the user mapping of the target 'pfn' being accessed by the kernel. On arm64, the 'pgprot_t' contains all of the non-address bits from the pte, including the permission controls, and so we end up returning a new user mapping from ioremap_prot() which faults when accessed from the kernel on systems with PAN: | Unable to handle kernel read from unreadable memory at virtual address ffff80008ea89000 | ... | Call trace: | __memcpy_fromio+0x80/0xf8 | generic_access_phys+0x20c/0x2b8 | __access_remote_vm+0x46c/0x5b8 | access_remote_vm+0x18/0x30 | environ_read+0x238/0x3e8 | vfs_read+0xe4/0x2b0 | ksys_read+0xcc/0x178 | __arm64_sys_read+0x4c/0x68 Extract only the memory type from the user 'pgprot_t' in ioremap_prot() and assert that we're being passed a user mapping, to protect us against any changes in future that may require additional handling. To avoid falsely flagging users of ioremap(), provide our own ioremap() macro which simply wraps __ioremap_prot(). Cc: Zeng Heng <zengheng4@huawei.com> Cc: Jinjiang Tu <tujinjiang@huawei.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Fixes: 893dea9ccd08 ("arm64: Add HAVE_IOREMAP_PROT support") Reported-by: Jinjiang Tu <tujinjiang@huawei.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Will Deacon <will@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'arch/arm64')
-rw-r--r--arch/arm64/include/asm/io.h17
1 files changed, 15 insertions, 2 deletions
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index cd2fddfe814a..8cbd1e96fd50 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -266,10 +266,23 @@ typedef int (*ioremap_prot_hook_t)(phys_addr_t phys_addr, size_t size,
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
+static inline void __iomem *ioremap_prot(phys_addr_t phys, size_t size,
+ pgprot_t user_prot)
+{
+ pgprot_t prot;
+ ptdesc_t user_prot_val = pgprot_val(user_prot);
+
+ if (WARN_ON_ONCE(!(user_prot_val & PTE_USER)))
+ return NULL;
-#define _PAGE_IOREMAP PROT_DEVICE_nGnRE
+ prot = __pgprot_modify(PAGE_KERNEL, PTE_ATTRINDX_MASK,
+ user_prot_val & PTE_ATTRINDX_MASK);
+ return __ioremap_prot(phys, size, prot);
+}
+#define ioremap_prot ioremap_prot
+#define ioremap(addr, size) \
+ __ioremap_prot((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
#define ioremap_wc(addr, size) \
__ioremap_prot((addr), (size), __pgprot(PROT_NORMAL_NC))
#define ioremap_np(addr, size) \