From 998d4d789d2d625e1d8c77c1b6c3951e30e81bb0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 11 Jun 2026 15:21:44 +0200 Subject: [PATCH 1/3] arm64: static_call: include asm/insns.h I came a cross a missing declaration in a randconfig build: arch/arm64/kernel/static_call.c:16:5: error: call to undeclared function 'aarch64_insn_adrp_get_offset'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 16 | aarch64_insn_adrp_get_offset(le32_to_cpup(tramp + 4)) + | ^ Include the header that contains this definition explicitly, rather than relying on it to come indirectly through another header. Fixes: 54ac9ff8f119 ("arm64: Use static call trampolines when kCFI is enabled") Signed-off-by: Arnd Bergmann Signed-off-by: Will Deacon --- arch/arm64/kernel/static_call.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kernel/static_call.c b/arch/arm64/kernel/static_call.c index 8b3a19e10871..c126edced022 100644 --- a/arch/arm64/kernel/static_call.c +++ b/arch/arm64/kernel/static_call.c @@ -2,6 +2,7 @@ #include #include #include +#include void arch_static_call_transform(void *site, void *tramp, void *func, bool tail) { From 4cc70f75853bebac022334b6a86b953348072f74 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 9 Jun 2026 06:15:53 -0700 Subject: [PATCH 2/3] arm64/hw_breakpoint: reject unaligned watchpoints that would truncate BAS hw_breakpoint_arch_parse() positions the BAS bit pattern in hw->ctrl.len with offset = hw->address & alignment_mask; /* 0..7 */ hw->ctrl.len <<= offset; ctrl.len is an 8-bit bitfield (struct arch_hw_breakpoint_ctrl::len is u32 :8), so the shift silently drops any bits past bit 7. For non-compat AArch64 watchpoints the offset is unbounded relative to ctrl.len: a perf_event_open(PERF_TYPE_BREAKPOINT) caller asking for HW_BREAKPOINT_W with bp_addr=page+1 and bp_len=HW_BREAKPOINT_LEN_8 ends up with 0xff << 1 = 0x1fe, stored as 0xfe. The kernel programs WCR.BAS=0xfe and the hardware watches bytes [1..7] instead of the requested [1..8] -- the eighth byte is silently dropped. The syscall still returns success, leaving userspace to discover the gap by empirical probing. The same class affects HW_BREAKPOINT_LEN_{2,4} when offset pushes the high BAS bit past bit 7 (e.g. LEN_4 with offset=5 yields 0xe0 instead of 0x1e0). No memory-safety impact -- the value is masked into 8 bits before encoding -- but debuggers and perf users observe missed events on bytes they thought they were watching. The AArch32 branch immediately above already rejects unrepresentable (offset, len) combinations via an explicit switch. Mirror that for the non-compat branch by checking that the shifted pattern fits in the BAS field, returning -EINVAL when it does not. GDB and similar debuggers are unaffected by the stricter check. aarch64_linux_set_debug_regs() already treats EINVAL on NT_ARM_HW_WATCH as a downgrade signal: it clears kernel_supports_any_contiguous_range, calls aarch64_downgrade_regs() to round the BAS up to a legacy 0x01/03/0f/ff mask with an aligned base, and retries -- the same fallback path that PR-20207 introduced. The new -EINVAL is therefore reachable only from a raw perf_event_open() that pairs an unaligned base with an oversized bp_len, which is precisely the bug. Reproducer: struct perf_event_attr a = { .type = PERF_TYPE_BREAKPOINT, .size = sizeof(a), .bp_type = HW_BREAKPOINT_W, .bp_addr = (uintptr_t)(buf + 1), .bp_len = HW_BREAKPOINT_LEN_8, .exclude_kernel = 1, .exclude_hv = 1, }; int fd = perf_event_open(&a, 0, -1, -1, 0); /* before this fix: succeeds, watches 7 bytes (buf+1..buf+7) */ /* after this fix: fails with EINVAL */ Fixes: b08fb180bb88 ("arm64: Allow hw watchpoint at varied offset from base address") Signed-off-by: Breno Leitao Signed-off-by: Will Deacon --- arch/arm64/kernel/hw_breakpoint.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index ab76b36dce82..73cce8ac8368 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -559,6 +559,15 @@ int hw_breakpoint_arch_parse(struct perf_event *bp, else alignment_mask = 0x7; offset = hw->address & alignment_mask; + + /* + * BAS is an 8-bit field in WCR/BCR; the shift below would + * silently drop the high bits of ctrl.len when offset + len + * exceeds 8, programming hardware to watch fewer bytes than + * the user requested. + */ + if (((u32)hw->ctrl.len << offset) > ARM_BREAKPOINT_LEN_8) + return -EINVAL; } hw->address &= ~alignment_mask; From 36fa5ffa60344bcc59fb3f50b33af8187e6b8753 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 23 Jun 2026 22:28:18 +0200 Subject: [PATCH 3/3] arm64: mm: Defer read-only remap of data/bss linear alias Since commit f2ba877402e5 ("arm64: mm: Map the kernel data/bss read-only in the linear map") the linear alias of the .data and .bss regions is remapped read-only early during the boot. (Note that a subsequent patch to unmap this region entirely was reverted just before the v7.2 merge window, and will be brought back in an improved form for the v7.3 cycle) Fuad reports that in some cases, the KVM init code may apply relocations to variables that reside in .data, and does so via the linear map. This means that remapping .data read-only beforehand is a bad idea, and results in an early boot crash. These variables in .data are only present when CONFIG_NVHE_EL2_DEBUG or CONFIG_NVHE_EL2_TRACING are enabled, which is why it was not spotted in testing. So move the remap to mark_rodata_ro(), which is a reasonable place to put this, and ensures that it happens much later during the boot. It also means that rodata=off is now taken into account, and so the linear alias will remain writable in that case. Fixes: f2ba877402e5 ("arm64: mm: Map the kernel data/bss read-only in the linear map") Reviewed-by: Fuad Tabba Tested-by: Fuad Tabba Signed-off-by: Ard Biesheuvel Reviewed-by: Kevin Brodsky Signed-off-by: Will Deacon --- arch/arm64/mm/mmu.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 354bedf0e638..60c2778f413c 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -1198,11 +1198,6 @@ static void __init map_mem(void) __map_memblock(start, end, pgprot_tagged(PAGE_KERNEL), flags); } - - /* Map the kernel data/bss read-only in the linear map */ - __map_memblock(init_end, kernel_end, PAGE_KERNEL_RO, flags); - flush_tlb_kernel_range((unsigned long)lm_alias(__init_end), - (unsigned long)lm_alias(__bss_stop)); } void mark_rodata_ro(void) @@ -1221,6 +1216,12 @@ void mark_rodata_ro(void) update_mapping_prot(__pa_symbol(_text), (unsigned long)_text, (unsigned long)_stext - (unsigned long)_text, PAGE_KERNEL_RO); + + /* Map the kernel data/bss read-only in the linear map */ + update_mapping_prot(__pa_symbol(__init_end), + (unsigned long)lm_alias(__init_end), + (unsigned long)__bss_stop - (unsigned long)__init_end, + PAGE_KERNEL_RO); } static void __init declare_vma(struct vm_struct *vma,