Re: [PATCH] arm64: compat: Keep alignment address arithmetic 32-bit
From: Arnd Bergmann
Date: Mon Aug 17 2026 - 05:16:29 EST
On Mon, Aug 17, 2026, at 02:02, Karl Mehltretter wrote:
> The compat alignment emulator inherited unsigned long data addresses
> from the 32-bit ARM implementation. On arm64, negating the unsigned int
> transfer size wraps it at 32 bits before it is added to a 64-bit
> address. A decrementing LDM or STM therefore adds nearly 4 GiB instead
> of subtracting its transfer size. The resulting address lies outside
> the compat task's address space, so the access fails and the process
> gets a spurious SIGBUS instead of the fixup.
>
> Using 64-bit addresses also prevents transfer and writeback arithmetic
> from wrapping at the AArch32 address-space boundary.
Hi Karl,
Nice find! How did you come across this?
Your patch looks correct to me, but it took me a bit to understand
it, as I found the use of compat_ptr() and changing the addressing
to 32-bit a little confusing at first.
> unsigned int rd, rn, nr_regs, regbits;
> - unsigned long eaddr, newaddr;
> + u32 eaddr, newaddr;
> unsigned int val;
As I understand it, the underlying problem here is the
32-bit overflow of nr_regs. Wouldn't it be sufficient
to just turn nr_regs into an 'unsigned long' or 'size_t'
in both instances?
> - if (get_user(val, (u32 __user *)eaddr))
> + if (get_user(val,
> + (u32 __user *)compat_ptr(eaddr)))
The individual compat_ptr() in each access looks like it would
have been sufficient as well, by avoiding the effect of the
overflow, and it also makes the address wrap back to zero
at the end of the address space. What's a bit confusing here
is that accessing an unaligned set of words at the end of the
address space will still read a couple of bytes beyond the
end of the 32-bit space.
Again, none of this is wrong, just wondering whether a simpler
change would make this easier to understand and keep the code
closer to the original arm32 version.
Arnd