Skip to contentSkip to conversation

arm64: compat: Implement misalignment fixups for multiword loads

PATCH Applied Ard Biesheuvel 5 participants 10 messages Jul 1, 2022 – Sep 6, 2022 arm64

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 arm64: compat: Implement misalignment fixups for multiword loads

The 32-bit ARM kernel implements fixups on behalf of user space when using LDM/STM or LDRD/STRD instructions on addresses that are not 32-bit aligned. This is not something that is supported by the architecture, but was done anyway to increase compatibility with user space software, which mostly targeted x86 at the time and did not care about aligned accesses.

This feature is one of the remaining impediments to being able to switch to 64-bit kernels on 64-bit capable hardware running 32-bit user space, so let's implement it for the arm64 compat layer as well.

Note that the intent is to implement the exact same handling of misaligned multi-word loads and stores as the 32-bit kernel does, including what appears to be missing support for user space programs that rely on SETEND to switch to a different byte order and back. Also, like the 32-bit ARM version, we rely on the faulting address reported by the CPU to infer the memory address, instead of decoding the instruction fully to obtain this information.

This implementation is taken from the 32-bit ARM tree, with all pieces removed that deal with instructions other than LDRD/STRD and LDM/STM, or that deal with alignment exceptions taken in kernel mode.

Cc Vagrant Cascadian <[email protected]>
Cc Riku Voipio <[email protected]>
Cc Steve McIntyre <[email protected]>

---
Note to cc'ees: if this is something you would like to see merged, please indicate so. This stuff is unlikely to get in if there are no users.

v2: - drop some obsolete comments
- emit a perf alignment-fault event for every handled instruction
- use arm64_skip_faulting_instruction() to get the correct behavior wrt IT state and single step
- use types with correct endianness annotation (instructions are always little endian on v7/v8+)

 arch/arm64/Kconfig                   |   4 +
 arch/arm64/include/asm/exception.h   |   1 +
 arch/arm64/kernel/Makefile           |   1 +
 arch/arm64/kernel/compat_alignment.c | 389 ++++++++++++++++++++
 arch/arm64/mm/fault.c                |   3 +
 5 files changed, 398 insertions(+)
arch/arm64/Kconfig +4 -0
index 1652a9800ebe..401e4f8fa149 100644
@@ -1508,6 +1508,10 @@ config THUMB2_COMPAT_VDSO
 	  Compile the compat vDSO with '-mthumb -fomit-frame-pointer' if y,
 	  otherwise with '-marm'.
 
+config COMPAT_ALIGNMENT_FIXUPS
+	bool "Fix up misaligned multi-word loads and stores in user space"
+	default y
+
 menuconfig ARMV8_DEPRECATED
 	bool "Emulate deprecated/obsolete ARMv8 instructions"
 	depends on SYSCTL
arch/arm64/include/asm/exception.h +1 -0
index d94aecff9690..e92ca08f754c 100644
@@ -70,6 +70,7 @@ void do_sysinstr(unsigned long esr, struct pt_regs *regs);
 void do_sp_pc_abort(unsigned long addr, unsigned long esr, struct pt_regs *regs);
 void bad_el0_sync(struct pt_regs *regs, int reason, unsigned long esr);
 void do_cp15instr(unsigned long esr, struct pt_regs *regs);
+int do_compat_alignment_fixup(unsigned long addr, struct pt_regs *regs);
 void do_el0_svc(struct pt_regs *regs);
 void do_el0_svc_compat(struct pt_regs *regs);
 void do_ptrauth_fault(struct pt_regs *regs, unsigned long esr);
arch/arm64/kernel/Makefile +1 -0
index fa7981d0d917..58b472fa34fe 100644
@@ -40,6 +40,7 @@ $(obj)/%.stub.o: $(obj)/%.o FORCE
 obj-$(CONFIG_COMPAT)			+= sys32.o signal32.o			\
 					   sys_compat.o
 obj-$(CONFIG_COMPAT)			+= sigreturn32.o
+obj-$(CONFIG_COMPAT_ALIGNMENT_FIXUPS)	+= compat_alignment.o
 obj-$(CONFIG_KUSER_HELPERS)		+= kuser32.o
 obj-$(CONFIG_FUNCTION_TRACER)		+= ftrace.o entry-ftrace.o
 obj-$(CONFIG_MODULES)			+= module.o
arch/arm64/kernel/compat_alignment.c new file +387 -0

387 lines not on this page · raw message

arch/arm64/mm/fault.c +3 -0
index c5e11768e5c1..b25119b4beca 100644
@@ -687,6 +687,9 @@ static int __kprobes do_translation_fault(unsigned long far,
 static int do_alignment_fault(unsigned long far, unsigned long esr,
 			      struct pt_regs *regs)
 {
+	if (IS_ENABLED(CONFIG_COMPAT_ALIGNMENT_FIXUPS) &&
+	    compat_user_mode(regs))
+		return do_compat_alignment_fixup(far, regs);
 	do_bad_area(far, esr, regs);
 	return 0;
 }
Signature · 7 lines
2.35.1


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Reviewed-by on v2 1/1
#1 lore raw
Quoted 7 lines · Ard Biesheuvel

v2: - drop some obsolete comments
- emit a perf alignment-fault event for every handled instruction
- use arm64_skip_faulting_instruction() to get the correct behavior wrt IT state and single step
- use types with correct endianness annotation (instructions are always little endian on v7/v8+)

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#2 lore raw
In reply to Ard Biesheuvel
Quoted 11 lines · Ard Biesheuvel

The 32-bit ARM kernel implements fixups on behalf of user space when using LDM/STM or LDRD/STRD instructions on addresses that are not 32-bit aligned.

This feature is one of the remaining impediments to being able to switch to 64-bit kernels on 64-bit capable hardware running 32-bit user space, so let's implement it for the arm64 compat layer as well.

Note to cc'ees: if this is something you would like to see merged, please indicate so. This stuff is unlikely to get in if there are no users.

Decent 32-bit arm hardware is thin on the ground these days. Debian still has some but it's getting old and flaky. Being able to build reliably on 64-bit hardware is important and useful. Unaligned accesses are much less of a problem than they used to be, but they can still happen, so having these fixups available is definitely a good thing.

Debian runs its 32-bit buildds with alignment fixups turned on. It looks like the boxes still hit about 1 per day.

We also do 32 bit builds on 64-bit kernels (in 32-bit userspaces) and it mostly works. We do have packages that fail on 64-bit kernels and have to be built on real 32-bit hardware, but I don't know how much of that would be fixed by this patch. Some, presumably.

So yes, cheers for this. It is helpful in the real world (or at least it should be).

Wookey

Signature · 2 lines
Principal hats:  Debian, Wookware, ARM
http://wookware.org/

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#3 lore raw

Hi,

Quoted 23 lines · Wookey
Quoted 11 lines · Ard Biesheuvel

The 32-bit ARM kernel implements fixups on behalf of user space when using LDM/STM or LDRD/STRD instructions on addresses that are not 32-bit aligned.

This feature is one of the remaining impediments to being able to switch to 64-bit kernels on 64-bit capable hardware running 32-bit user space, so let's implement it for the arm64 compat layer as well.

Note to cc'ees: if this is something you would like to see merged, please indicate so. This stuff is unlikely to get in if there are no users.

Decent 32-bit arm hardware is thin on the ground these days. Debian still has some but it's getting old and flaky. Being able to build reliably on 64-bit hardware is important and useful. Unaligned accesses are much less of a problem than they used to be, but they can still happen, so having these fixups available is definitely a good thing.

Debian runs its 32-bit buildds with alignment fixups turned on. It looks like the boxes still hit about 1 per day.

Quoted 7 lines

We also do 32 bit builds on 64-bit kernels (in 32-bit userspaces) and it mostly works. We do have packages that fail on 64-bit kernels and have to be built on real 32-bit hardware, but I don't know how much of that would be fixed by this patch. Some, presumably.

So yes, cheers for this. It is helpful in the real world (or at least it should be).

I confirm that this would be very helpful to Debian, so that 32-bit binaries behaves the same with a 32-bit or a 64-bit kernel. Otherwise we need to keep running (old) 32-bit hardware.

What's the status of those patches?

Thanks
Aurelien

Signature · 2 lines
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
[email protected]                 http://www.aurel32.net

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#4 lore raw
Quoted 32 lines · Aurelien Jarno

Hi,

Quoted 28 lines · Wookey
Quoted 11 lines · Ard Biesheuvel

The 32-bit ARM kernel implements fixups on behalf of user space when using LDM/STM or LDRD/STRD instructions on addresses that are not 32-bit aligned.

This feature is one of the remaining impediments to being able to switch to 64-bit kernels on 64-bit capable hardware running 32-bit user space, so let's implement it for the arm64 compat layer as well.

Note to cc'ees: if this is something you would like to see merged, please indicate so. This stuff is unlikely to get in if there are no users.

Decent 32-bit arm hardware is thin on the ground these days. Debian still has some but it's getting old and flaky. Being able to build reliably on 64-bit hardware is important and useful. Unaligned accesses are much less of a problem than they used to be, but they can still happen, so having these fixups available is definitely a good thing.

Debian runs its 32-bit buildds with alignment fixups turned on. It looks like the boxes still hit about 1 per day.

We also do 32 bit builds on 64-bit kernels (in 32-bit userspaces) and it mostly works. We do have packages that fail on 64-bit kernels and have to be built on real 32-bit hardware, but I don't know how much of that would be fixed by this patch. Some, presumably.

Quoted 9 lines
Quoted 2 lines

So yes, cheers for this. It is helpful in the real world (or at least it should be).

I confirm that this would be very helpful to Debian, so that 32-bit binaries behaves the same with a 32-bit or a 64-bit kernel. Otherwise we need to keep running (old) 32-bit hardware.

What's the status of those patches?

Thanks for chiming in.

At this point, it is really up to the maintainers to decide whether the maintenance burden is worth it. The code itself seems pretty uncontroversial afaict.

Might other distros be in a similar situation? Or is this specific to Debian?

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#5 lore raw
Quoted 8 lines · Ard Biesheuvel

Thanks for chiming in.

At this point, it is really up to the maintainers to decide whether the maintenance burden is worth it. The code itself seems pretty uncontroversial afaict.

Might other distros be in a similar situation? Or is this specific to Debian?

My guess is that this is the most prominent on Debian: Many others including have discontinued or reduced support for 32-bit builds across architectures:
Ubuntu only supports "Core" with fewer packages on Raspberry Pi 2 but not desktop or server, Opensuse Leap and Tumbleweed both distributes a lot of board specific images but you have to know where to look as the main page only advertises amd64/i686/arm64/ppc64le/s390x, Fedora stopped entirely.

Android may be an interesting distro here: there are still a lot of phones running a pure 32-bit userland on Cortex-A53/A55 CPUs, and there are a large number of applications built for this. As far as I can tell, they tend to run 32-bit kernels as well, but that is not going to work on newer processors starting with Cortex-A76 big cores or Cortex-A510 little cores.

archlinuxarm supports 32-bit and 64-bit machines equally, but they apparently avoid the build service problem by using distcc with x86-to-arm cross compilers, and they don't seem to support their 32-bit images on 64-bit hardware/kernel.

https://hub.docker.com/search?q=&source=verified&type=image&architecture=arm&image_filter=official
lists 98 "official" arm32 images plus countless ones in other categories. I think these are popular in memory-constrained cloud hosting setups on arm64, so the Alpine based images are probably the most interesting ones because of their size, but they would run under someone else's kernel.

Arnd

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

maintainer
#6 lore raw
In reply to Ard Biesheuvel
Quoted 33 lines · Ard Biesheuvel

The 32-bit ARM kernel implements fixups on behalf of user space when using LDM/STM or LDRD/STRD instructions on addresses that are not 32-bit aligned. This is not something that is supported by the architecture, but was done anyway to increase compatibility with user space software, which mostly targeted x86 at the time and did not care about aligned accesses.

This feature is one of the remaining impediments to being able to switch to 64-bit kernels on 64-bit capable hardware running 32-bit user space, so let's implement it for the arm64 compat layer as well.

Note that the intent is to implement the exact same handling of misaligned multi-word loads and stores as the 32-bit kernel does, including what appears to be missing support for user space programs that rely on SETEND to switch to a different byte order and back. Also, like the 32-bit ARM version, we rely on the faulting address reported by the CPU to infer the memory address, instead of decoding the instruction fully to obtain this information.

This implementation is taken from the 32-bit ARM tree, with all pieces removed that deal with instructions other than LDRD/STRD and LDM/STM, or that deal with alignment exceptions taken in kernel mode.

Cc Vagrant Cascadian <[email protected]>
Cc Riku Voipio <[email protected]>
Cc Steve McIntyre <[email protected]>

---
Note to cc'ees: if this is something you would like to see merged, please indicate so. This stuff is unlikely to get in if there are no users.

Quoted 6 lines

v2: - drop some obsolete comments
- emit a perf alignment-fault event for every handled instruction
- use arm64_skip_faulting_instruction() to get the correct behavior wrt IT state and single step
- use types with correct endianness annotation (instructions are always little endian on v7/v8+)

It looks like that's a fairly popular request from people running 32-bit user on AArch64 kernels, so happy to queue it for 6.1 (if it still applies cleanly). I'm not too keen on code duplication but it's a lot more hassle to create a common decoding/emulation library to share with arch/arm, especially as such code is not going to change in the future.

arch/arm64/Kconfig config THUMB2_COMPAT_VDSO · line 1513

Quoted 3 lines
arch/arm64/Kconfig +3 -0
+config COMPAT_ALIGNMENT_FIXUPS
+	bool "Fix up misaligned multi-word loads and stores in user space"
+	default y

For consistency with ARMV8_DEPRECATED, I think we should keep this as default n.

Thanks.

Signature · 6 lines
Catalin

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#7 lore raw
Quoted 48 lines · Catalin Marinas
Quoted 33 lines · Ard Biesheuvel

The 32-bit ARM kernel implements fixups on behalf of user space when using LDM/STM or LDRD/STRD instructions on addresses that are not 32-bit aligned. This is not something that is supported by the architecture, but was done anyway to increase compatibility with user space software, which mostly targeted x86 at the time and did not care about aligned accesses.

This feature is one of the remaining impediments to being able to switch to 64-bit kernels on 64-bit capable hardware running 32-bit user space, soDocumentation/x86/boot.rst let's implement it for the arm64 compat layer as well.

Note that the intent is to implement the exact same handling of misaligned multi-word loads and stores as the 32-bit kernel does, including what appears to be missing support for user space programs that rely on SETEND to switch to a different byte order and back. Also, like the 32-bit ARM version, we rely on the faulting address reported by the CPU to infer the memory address, instead of decoding the instruction fully to obtain this information.

This implementation is taken from the 32-bit ARM tree, with all pieces removed that deal with instructions other than LDRD/STRD and LDM/STM, or that deal with alignment exceptions taken in kernel mode.

Cc Vagrant Cascadian <[email protected]>
Cc Riku Voipio <[email protected]>
Cc Steve McIntyre <[email protected]>

---
Note to cc'ees: if this is something you would like to see merged, please indicate so. This stuff is unlikely to get in if there are no users.

Quoted 6 lines

v2: - drop some obsolete comments
- emit a perf alignment-fault event for every handled instruction
- use arm64_skip_faulting_instruction() to get the correct behavior wrt IT state and single step
- use types with correct endianness annotation (instructions are always little endian on v7/v8+)

It looks like that's a fairly popular request from people running 32-bit user on AArch64 kernels, so happy to queue it for 6.1 (if it still applies cleanly). I'm not too keen on code duplication but it's a lot more hassle to create a common decoding/emulation library to share with arch/arm, especially as such code is not going to change in the future.

Quoted 7 lines

arch/arm64/Kconfig config THUMB2_COMPAT_VDSO · line 1513

Quoted 3 lines
arch/arm64/Kconfig +3 -0
+config COMPAT_ALIGNMENT_FIXUPS
+     bool "Fix up misaligned multi-word loads and stores in user space"
+     default y

For consistency with ARMV8_DEPRECATED, I think we should keep this as default n.

Fair enough. I take it you can fix this up while applying?

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

maintainer
#8 lore raw
Quoted 10 lines · Ard Biesheuvel
Quoted 7 lines · Catalin Marinas

arch/arm64/Kconfig config THUMB2_COMPAT_VDSO · line 1513

Quoted 3 lines · Ard Biesheuvel
arch/arm64/Kconfig +3 -0
+config COMPAT_ALIGNMENT_FIXUPS
+     bool "Fix up misaligned multi-word loads and stores in user space"
+     default y

For consistency with ARMV8_DEPRECATED, I think we should keep this as default n.

Fair enough. I take it you can fix this up while applying?

Yes.

Signature · 6 lines
Catalin

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
maintainer Applied
#9 lore raw
In reply to Ard Biesheuvel
Quoted 8 lines · Ard Biesheuvel

The 32-bit ARM kernel implements fixups on behalf of user space when using LDM/STM or LDRD/STRD instructions on addresses that are not 32-bit aligned. This is not something that is supported by the architecture, but was done anyway to increase compatibility with user space software, which mostly targeted x86 at the time and did not care about aligned accesses.

[...]

Applied to arm64 (for-next/misc), thanks!

[1/1] arm64: compat: Implement misalignment fixups for multiword loads

      https://git.kernel.org/arm64/c/3fc24ef32d3b
Signature · 7 lines
Catalin


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel