ARM: nwfpe: use task_pt_regs() to find user registers
Subsystems (2)
PATCH 1/1 ARM: nwfpe: use task_pt_regs() to find user registers
NWFPE locates the trapping process's saved registers relative to current_thread_info(), assuming thread_info sits at the bottom of the kernel stack. Since ARM moved thread_info into task_struct, that expression points past the end of the task_struct instead.
This breaks FPA instruction emulation, as the user registers are never read or written and causes out-of-bounds reads and writes of kernel memory beyond the task_struct. Any unprivileged process can trigger this.
Fix by using task_pt_regs(current), which finds the registers on the stack.
The bug was found with assistance from Claude Code (Anthropic), model Claude Opus 5.5 (claude-opus-5-5).
---
Build tested on Russell King's linux-arm tree with footbridge_defconfig (CPU_SA110, FPE_NWFPE,THREAD_INFO_IN_TASK), W=1, no new warnings.
Runtime-tested on 6.12.116, where this patch applies unchanged (arch/arm/nwfpe/fpa11.h is identical to mainline):
- QEMU versatilepb (ARM926) with OABI_COMPAT, FPE_NWFPE and KASAN:
a test that executes FLT and FIX gets the wrong result back and KASAN reports "slab-out-of-bounds in PerformFLT" without this patch; with it the result is correct and KASAN reports nothing.
- Nokia 770 (OMAP1710, ARM926, OABI userspace): fixes the maemo battery daemon's FPA arithmetic which would incorrectly calculate the remaining charge of the battery and power off the device.
Not runtime tested on mainline: since 25900bd99d4d ("ARM: limit OABI support to StrongARM CPUs") NWFPE is StrongARM-only, and QEMU's only StrongARM machine (collie) currently fails to boot mainline.
A reproducer is available on request.
arch/arm/nwfpe/fpa11.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
arch/arm/nwfpe/fpa11.h +3 -4
@@ -13,13 +13,12 @@#define GET_FPA11 () ((FPA11 *)(¤t_thread_info()->fpstate))/* -* The processes registers are always at the very top of the 8K -* stack+task struct. Use the same method as 'current' uses to -* reach them. +* The process's registers are saved at the top of its kernel stack. */ -#define GET_USERREG () ((struct pt_regs *)(THREAD_START_SP + (unsigned long)current_thread_info()) - 1) +#define GET_USERREG () task_pt_regs(current)#include <linux/thread_info.h> +#include <linux/sched/task_stack.h> /* includes */ #include "fpsr.h" /* FP control and status register definitions */
Signature · 1 line
2.47.3
Quoted 37 lines · Patrick Lister
NWFPE locates the trapping process's saved registers relative to
current_thread_info(), assumingthread_infosits at the bottom of the kernel stack. Since ARM movedthread_infointotask_struct, that expression points past the end of thetask_structinstead.This breaks FPA instruction emulation, as the user registers are never read or written and causes out-of-bounds reads and writes of kernel memory beyond the
task_struct. Any unprivileged process can trigger this.Fix by using
task_pt_regs(current), which finds the registers on the stack.The bug was found with assistance from Claude Code (Anthropic), model Claude Opus 5.5 (claude-opus-5-5).
Fixes 18ed1c01a7dd ("ARM: smp: Enable THREAD_INFO_IN_TASK")Fixes 9c46929e7989 ("ARM: implement THREAD_INFO_IN_TASK foruniprocessor systems")
Cc [email protected] # 5.16+Signed-off-by Patrick Lister <[email protected]>---
Build tested on Russell King's linux-arm tree withfootbridge_defconfig(CPU_SA110, FPE_NWFPE,THREAD_INFO_IN_TASK), W=1, no new warnings.Runtime-tested on 6.12.116, where this patch applies unchanged (
arch/arm/nwfpe/fpa11.his identical to mainline):- QEMU versatilepb (ARM926) with
OABI_COMPAT,FPE_NWFPEand KASAN:
a test that executes FLT and FIX gets the wrong result back and KASAN reports "slab-out-of-bounds in PerformFLT" without this patch; with it the result is correct and KASAN reports nothing.- Nokia 770 (OMAP1710, ARM926, OABI userspace): fixes the maemo battery daemon's FPA arithmetic which would incorrectly calculate the remaining charge of the battery and power off the device.
Quoted 6 lines
Not runtime tested on mainline: since
25900bd99d4d("ARM: limit OABI support to StrongARM CPUs") NWFPE is StrongARM-only, and QEMU's only StrongARM machine (collie) currently fails to boot mainline.A reproducer is available on request.
So NWFPE has been broken for 5 years and nobody noticed until now?
Quoted 9 lines · Patrick Lister
NWFPE locates the trapping process's saved registers relative to
current_thread_info(), assumingthread_infosits at the bottom of the kernel stack. Since ARM movedthread_infointotask_struct, that expression points past the end of thetask_structinstead.This breaks FPA instruction emulation, as the user registers are never read or written and causes out-of-bounds reads and writes of kernel memory beyond the
task_struct. Any unprivileged process can trigger this.
Thanks a lot for chasing this down!
As I understand it, this means that nobody has seriously used or tested OABI since 5.16. I last tested it myself in 5.14 when working on 4e57a4ddf6b0 ("ARM: 9107/1: syscall: always store thread_info->abi_syscall"), but it was quite hard to properly test it at the time, even getting an old Debian rootfs to work with a modern kernel and qemu was nontrivial.
Quoted 11 lines
Fix by using
task_pt_regs(current), which finds the registers on the stack.The bug was found with assistance from Claude Code (Anthropic), model Claude Opus 5.5 (claude-opus-5-5).
Fixes 18ed1c01a7dd ("ARM: smp: Enable THREAD_INFO_IN_TASK")Fixes 9c46929e7989 ("ARM: implement THREAD_INFO_IN_TASK foruniprocessor systems")
Cc [email protected] # 5.16+Signed-off-by Patrick Lister <[email protected]>
The patch looks fine, and it's clearly harmless to merge as there are no users, so please add it to the patch tracker according to the instructions at https://www.arm.linux.org.uk/developer/patches/info.php
Hopefully this way we can have OABI/NWFPE in a working state for the LTS backports when we remove it in the near future, in case anyone ever wants to play with it later.
I've added the maintainers for the Arm ports in gcc, qemu and binutils to Cc here, I believe all of these still have some level of OABI support that they kept just because Linux still handles it, but that can then also be removed.
Arnd
Quoted 21 lines · Arnd Bergmann
Quoted 9 lines · Patrick Lister
NWFPE locates the trapping process's saved registers relative to
current_thread_info(), assumingthread_infosits at the bottom of the kernel stack. Since ARM movedthread_infointotask_struct, that expression points past the end of thetask_structinstead.This breaks FPA instruction emulation, as the user registers are never read or written and causes out-of-bounds reads and writes of kernel memory beyond the
task_struct. Any unprivileged process can trigger this.Thanks a lot for chasing this down!
As I understand it, this means that nobody has seriously used or tested OABI since 5.16. I last tested it myself in 5.14 when working on
4e57a4ddf6b0("ARM: 9107/1: syscall: always storethread_info->abi_syscall"), but it was quite hard to properly test it at the time, even getting an old Debian rootfs to work with a modern kernel and qemu was nontrivial.
Quoted 4 lines
I've added the maintainers for the Arm ports in gcc, qemu and binutils to Cc here, I believe all of these still have some level of OABI support that they kept just because Linux still handles it, but that can then also be removed.
QEMU has already deprecated its OABI and NWFPE emulation as of our 11.0 release in April this year. We'll probably remove it in 12.0 in April next year. (Our deprecation policy only requires two releases of notice before removal, so we could have removed it for 11.2 if we'd remembered, but as we're already in freeze it's a bit late to do so now.)
thanks
-- PMM
Quoted 3 lines · Arnd Bergmann
The patch looks fine, and it's clearly harmless to merge as there are no users, so please add it to the patch tracker according to the instructions at https://www.arm.linux.org.uk/developer/patches/info.php
I have submitted patch 9527/1 as requested, thanks!