[PATCH v3 4/4] ARM: Implement PAN for LPAE by TTBR0 page table walks disablement
Ard Biesheuvel
ardb at kernel.org
Wed May 15 09:36:41 PDT 2024
On Wed, 15 May 2024 at 18:18, Russell King (Oracle)
<linux at armlinux.org.uk> wrote:
>
> On Wed, May 15, 2024 at 05:41:45PM +0200, Ard Biesheuvel wrote:
> > This definitely looks like some pathological compiler behavior:
> >
> > The faulting instruction in question is in busybox
> >
> > 15f450: eef11a10 vmrs r1, fpscr
> >
> > which [as expected] triggers an UNDEF exception as FP is disabled
> > after a context switch.
> >
> > The get_user() call in do_undefinstr() [arch/arm/kernel/traps.c:482]
> >
> > if (get_user(instr, (u32 __user *)pc))
> >
> > gets compiled to the below, where the thing to note is that the
> > out-of-line version of uaccess_save_and_enable() returns the old ttbcr
> > value in R0. This value gets recorded in R3, but it also gets happily
> > passed on to __get_user_4(), which expects the user address in R0, not
> > the old value of TTBCR.
> >
> > │ 0xc040a5e4 <do_undefinstr+228> bl 0xc0409fe4
> > <uaccess_save_and_enable>
> > │ 0xc040a5e8 <do_undefinstr+232> mov r3, r0
> > │ > 0xc040a5ec <do_undefinstr+236> bl 0xc10443a8 <__get_user_4>
> > │ 0xc040a5f0 <do_undefinstr+240> mcr 15, 0, r3, cr2, cr0, {2}
> > │ 0xc040a5f4 <do_undefinstr+244> isb sy
> >
> > With __always_inline, this part is emitted as
> >
> > 5fc: ee124f50 mrc 15, 0, r4, cr2, cr0, {2}
> > 600: e0033004 and r3, r3, r4
> > 604: ee023f50 mcr 15, 0, r3, cr2, cr0, {2}
> > 608: f57ff06f isb sy
> > 60c: ebfffffe bl 0 <__get_user_4>
> > 60c: R_ARM_CALL __get_user_4
> > 610: ee024f50 mcr 15, 0, r4, cr2, cr0, {2}
> > 614: f57ff06f isb sy
> >
> > and so R0 is preserved, and the issue does not happen.
> >
> > Not sure how to reduce this to a reproducer that can be used to report
> > the issue to the GCC folks, but it is most definitely a compiler
> > problem, as far as I can tell.
>
> Well this has come up before...
>
> commit 851140ab0d083c78e5723a8b1cbd258f567a7aff
> Author: Masahiro Yamada <yamada.masahiro at socionext.com>
> Date: Wed Oct 2 11:28:02 2019 +0100
>
> ARM: 8908/1: add __always_inline to functions called from __get_user_check()
>
> I assume it's a wontfix on the GCC side.
>
Yes, that is the exact same issue.
Not sure whether it has been reported - the GCC side might not even be aware.
I managed to reproduce this in godbolt - it happens even with -O2 not
just with -Os
https://godbolt.org/z/do56voKsa
As far as I can tell, functions that use asm("r#") cannot safely call
other functions at all unless those are __always_inline. The fact that
it triggers with -Os first is just because it inlines much less
aggressively than other optimization levels.
More information about the linux-arm-kernel
mailing list