<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p><br>
    </p>
    <div class="moz-cite-prefix">On 27/02/26 14:52, Christophe Leroy (CS
      GROUP) wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:a8f8fd17-7746-46da-8ae7-439d1e8f1f23@kernel.org">Hi,
      <br>
      <br>
      Le 17/02/2026 à 13:44, Sayali Patil a écrit :
      <br>
      <blockquote type="cite">[Vous ne recevez pas souvent de courriers
        de <a class="moz-txt-link-abbreviated" href="mailto:sayalip@linux.ibm.com">sayalip@linux.ibm.com</a>. Découvrez pourquoi ceci est important
        à <a class="moz-txt-link-freetext" href="https://aka.ms/LearnAboutSenderIdentification">https://aka.ms/LearnAboutSenderIdentification</a> ]
        <br>
        <br>
        On powerpc with PREEMPT_FULL or PREEMPT_LAZY and function
        tracing enabled,
        <br>
        KUAP warnings can be triggered from the VMX usercopy path under
        memory
        <br>
        stress workloads.
        <br>
        <br>
        KUAP requires that no subfunctions are called once userspace
        access has
        <br>
        been enabled. The existing VMX copy implementation violates this
        <br>
        requirement by invoking enter_vmx_usercopy() from the assembly
        path after
        <br>
        userspace access has already been enabled. If preemption occurs
        <br>
        in this window, the AMR state may not be preserved correctly,
        <br>
        leading to unexpected userspace access state and resulting in
        <br>
        KUAP warnings.
        <br>
        <br>
        Fix this by moving VMX selection and enter_vmx_usercopy()/
        <br>
        exit_vmx_usercopy() handling into the
        raw_copy_{to,from,in}_user()
        <br>
        wrappers in uaccess.h. The new flow is:
        <br>
        <br>
           - Decide whether to use the VMX path based on size and CPU
        capability
        <br>
           - Call enter_vmx_usercopy() before enabling userspace access
        <br>
           - Enable userspace access and perform the VMX copy
        <br>
           - Disable userspace access
        <br>
           - Call exit_vmx_usercopy()
        <br>
           - Fall back to the base copy routine if the VMX copy faults
        <br>
        <br>
        With this change, the VMX assembly routines no longer perform
        VMX state
        <br>
        management or call helper functions; they only implement the
        <br>
        copy operations.
        <br>
        The previous feature-section based VMX selection inside
        <br>
        __copy_tofrom_user_power7() is removed, and a dedicated
        <br>
        __copy_tofrom_user_power7_vmx() entry point is introduced.
        <br>
        <br>
        This ensures correct KUAP ordering, avoids subfunction calls
        <br>
        while KUAP is unlocked, and eliminates the warnings while
        preserving
        <br>
        the VMX fast path.
        <br>
      </blockquote>
      <br>
      You patch conflicts with the changes for adding masked user
      access.
      <br>
      <br>
      Can you rebase on top of v7.0-rc1 ?
      <br>
      <br>
      Comments below
      <br>
      <br>
      <blockquote type="cite">
        <br>
        Fixes: de78a9c42a79 ("powerpc: Add a framework for Kernel
        Userspace Access Protection")
        <br>
        Reported-by: Shrikanth Hegde <a class="moz-txt-link-rfc2396E" href="mailto:sshegde@linux.ibm.com"><sshegde@linux.ibm.com></a>
        <br>
        Closes:
<a class="moz-txt-link-freetext" href="https://lore.kernel.org/all/20260109064917.777587-2-sshegde@linux.ibm.com/">https://lore.kernel.org/all/20260109064917.777587-2-sshegde@linux.ibm.com/</a><br>
        Suggested-by: Christophe Leroy (CS GROUP)
        <a class="moz-txt-link-rfc2396E" href="mailto:chleroy@kernel.org"><chleroy@kernel.org></a>
        <br>
        Co-developed-by: Aboorva Devarajan
        <a class="moz-txt-link-rfc2396E" href="mailto:aboorvad@linux.ibm.com"><aboorvad@linux.ibm.com></a>
        <br>
        Signed-off-by: Aboorva Devarajan <a class="moz-txt-link-rfc2396E" href="mailto:aboorvad@linux.ibm.com"><aboorvad@linux.ibm.com></a>
        <br>
        Signed-off-by: Sayali Patil <a class="moz-txt-link-rfc2396E" href="mailto:sayalip@linux.ibm.com"><sayalip@linux.ibm.com></a>
        <br>
        ---
        <br>
          arch/powerpc/include/asm/uaccess.h | 67
        ++++++++++++++++++++++++++++++
        <br>
          arch/powerpc/lib/copyuser_64.S     |  1 +
        <br>
          arch/powerpc/lib/copyuser_power7.S | 45 +++++++-------------
        <br>
          arch/powerpc/lib/vmx-helper.c      |  2 +
        <br>
          4 files changed, 85 insertions(+), 30 deletions(-)
        <br>
        <br>
        diff --git a/arch/powerpc/include/asm/uaccess.h
        b/arch/powerpc/include/asm/uaccess.h
        <br>
        index 784a00e681fa..52e4a784d148 100644
        <br>
        --- a/arch/powerpc/include/asm/uaccess.h
        <br>
        +++ b/arch/powerpc/include/asm/uaccess.h
        <br>
        @@ -13,6 +13,11 @@
        <br>
          #define TASK_SIZE_MAX          TASK_SIZE_USER64
        <br>
          #endif
        <br>
        <br>
        +#ifdef CONFIG_ALTIVEC
        <br>
      </blockquote>
      <br>
      remove the ifdef to avoid matching ifdef later
      <br>
      <br>
      <blockquote type="cite">+/* Threshold above which VMX copy path is
        used */
        <br>
        +#define VMX_COPY_THRESHOLD 3328
        <br>
        +#endif
        <br>
        +
        <br>
          #include <asm-generic/access_ok.h>
        <br>
        <br>
          /*
        <br>
        @@ -323,12 +328,42 @@ do
        {                                                              \
        <br>
          extern unsigned long __copy_tofrom_user(void __user *to,
        <br>
                         const void __user *from, unsigned long size);
        <br>
        <br>
        +extern unsigned long __copy_tofrom_user_base(void __user *to,
        <br>
        +               const void __user *from, unsigned long size);
        <br>
        +
        <br>
      </blockquote>
      <br>
      extern keywork is pointless for function prototypes, don't add new
      ones.
      <br>
      <br>
      <blockquote type="cite">+#ifdef CONFIG_ALTIVEC
        <br>
      </blockquote>
      <br>
      Remove the ifdef
      <br>
      <br>
      <blockquote type="cite">+extern unsigned long
        __copy_tofrom_user_power7_vmx(void __user *to,
        <br>
        +               const void __user *from, unsigned long size);
        <br>
        +
        <br>
        +static inline bool will_use_vmx(unsigned long n)
        <br>
        +{
        <br>
        +       return cpu_has_feature(CPU_FTR_VMX_COPY) &&
        <br>
        +               n > VMX_COPY_THRESHOLD;
        <br>
      </blockquote>
      <br>
      Change to
      <br>
      <br>
          return IS_ENABLED(CONFIG_ALTIVEC) &&
      cpu_has_feature(CPU_FTR_VMX_COPY) &&  n >
      VMX_COPY_THRESHOLD;
      <br>
      <br>
      Then will_use_vmx() will return false when CONFIG_ALTIVEC is not
      set
      <br>
      <br>
      <blockquote type="cite">+}
        <br>
        +#endif
        <br>
        +
        <br>
          #ifdef __powerpc64__
        <br>
          static inline unsigned long
        <br>
          raw_copy_in_user(void __user *to, const void __user *from,
        unsigned long n)
        <br>
          {
        <br>
                 unsigned long ret;
        <br>
        <br>
        +#ifdef CONFIG_ALTIVEC
        <br>
      </blockquote>
      <br>
      Remove the ifdef, will_use_vmx() will return false with the above
      change when CONFIG_ALTIVEC is not set
      <br>
      <br>
      <blockquote type="cite">+       if (will_use_vmx(n) &&
        enter_vmx_usercopy()) {
        <br>
        +               allow_read_write_user(to, from, n);
        <br>
        +               ret = __copy_tofrom_user_power7_vmx(to, from,
        n);
        <br>
        +               prevent_read_write_user(to, from, n);
        <br>
        +               exit_vmx_usercopy();
        <br>
        +               if (unlikely(ret)) {
        <br>
        +                       allow_read_write_user(to, from, n);
        <br>
        +                       ret = __copy_tofrom_user_base(to, from,
        n);
        <br>
        +                       prevent_read_write_user(to, from, n);
        <br>
        +               }
        <br>
        +
        <br>
        +               return ret;
        <br>
        +       }
        <br>
      </blockquote>
      <br>
      This block is starting to be a bit big for an inline function.
      <br>
      I think we should just have:
      <br>
      <br>
          if (will_use_vmx(n))
      <br>
              return __copy_tofrom_user_vmx()
      <br>
      <br>
      and then define a __copy_tofrom_user_vmx() in for instance
      arch/powerpc/lib/vmx-helper.c
      <br>
      <br>
      This would also avoid having to export enter_vmx_usercopy() and
      exit_vmx_usercopy()
      <br>
      <br>
      Christophe <br>
      <br>
    </blockquote>
    <font face="monospace" size="4">Thanks Christophe for the review and
      suggestions. We have incorporated<br aria-hidden="true">
       these changes in v2.<br>
      <br aria-hidden="true">
      v2:
<a class="moz-txt-link-freetext" href="https://lore.kernel.org/all/20260228135319.238985-1-sayalip@linux.ibm.com/">https://lore.kernel.org/all/20260228135319.238985-1-sayalip@linux.ibm.com/</a><br>
      <br>
      Regards,<br>
      Sayali</font>
    <blockquote type="cite"
      cite="mid:a8f8fd17-7746-46da-8ae7-439d1e8f1f23@kernel.org">
      <blockquote type="cite">+#endif
        <br>
        +
        <br>
                 allow_read_write_user(to, from, n);
        <br>
                 ret = __copy_tofrom_user(to, from, n);
        <br>
                 prevent_read_write_user(to, from, n);
        <br>
        @@ -341,6 +376,22 @@ static inline unsigned long
        raw_copy_from_user(void *to,
        <br>
          {
        <br>
                 unsigned long ret;
        <br>
        <br>
        +#ifdef CONFIG_ALTIVEC
        <br>
        +       if (will_use_vmx(n) && enter_vmx_usercopy()) {
        <br>
        +               allow_read_from_user(from, n);
        <br>
        +               ret = __copy_tofrom_user_power7_vmx((__force
        void __user *)to, from, n);
        <br>
        +               prevent_read_from_user(from, n);
        <br>
        +               exit_vmx_usercopy();
        <br>
        +               if (unlikely(ret)) {
        <br>
        +                       allow_read_from_user(from, n);
        <br>
        +                       ret = __copy_tofrom_user_base((__force
        void __user *)to, from, n);
        <br>
        +                       prevent_read_from_user(from, n);
        <br>
        +               }
        <br>
        +
        <br>
        +               return ret;
        <br>
        +       }
        <br>
        +#endif
        <br>
        +
        <br>
                 allow_read_from_user(from, n);
        <br>
                 ret = __copy_tofrom_user((__force void __user *)to,
        from, n);
        <br>
                 prevent_read_from_user(from, n);
        <br>
        @@ -352,6 +403,22 @@ raw_copy_to_user(void __user *to, const
        void *from, unsigned long n)
        <br>
          {
        <br>
                 unsigned long ret;
        <br>
        <br>
        +#ifdef CONFIG_ALTIVEC
        <br>
        +       if (will_use_vmx(n) && enter_vmx_usercopy()) {
        <br>
        +               allow_write_to_user(to, n);
        <br>
        +               ret = __copy_tofrom_user_power7_vmx(to, (__force
        const void __user *)from, n);
        <br>
        +               prevent_write_to_user(to, n);
        <br>
        +               exit_vmx_usercopy();
        <br>
        +               if (unlikely(ret)) {
        <br>
        +                       allow_write_to_user(to, n);
        <br>
        +                       ret = __copy_tofrom_user_base(to,
        (__force const void __user *)from, n);
        <br>
        +                       prevent_write_to_user(to, n);
        <br>
        +               }
        <br>
        +
        <br>
        +               return ret;
        <br>
        +       }
        <br>
        +#endif
        <br>
        +
        <br>
                 allow_write_to_user(to, n);
        <br>
                 ret = __copy_tofrom_user(to, (__force const void __user
        *)from, n);
        <br>
                 prevent_write_to_user(to, n);
        <br>
        diff --git a/arch/powerpc/lib/copyuser_64.S
        b/arch/powerpc/lib/copyuser_64.S
        <br>
        index 9af969d2cc0c..25a99108caff 100644
        <br>
        --- a/arch/powerpc/lib/copyuser_64.S
        <br>
        +++ b/arch/powerpc/lib/copyuser_64.S
        <br>
        @@ -562,3 +562,4 @@ exc;        std     r10,32(3)
        <br>
                 li      r5,4096
        <br>
                 b       .Ldst_aligned
        <br>
          EXPORT_SYMBOL(__copy_tofrom_user)
        <br>
        +EXPORT_SYMBOL(__copy_tofrom_user_base)
        <br>
        diff --git a/arch/powerpc/lib/copyuser_power7.S
        b/arch/powerpc/lib/copyuser_power7.S
        <br>
        index 8474c682a178..17dbcfbae25f 100644
        <br>
        --- a/arch/powerpc/lib/copyuser_power7.S
        <br>
        +++ b/arch/powerpc/lib/copyuser_power7.S
        <br>
        @@ -5,13 +5,9 @@
        <br>
           *
        <br>
           * Author: Anton Blanchard <a class="moz-txt-link-rfc2396E" href="mailto:anton@au.ibm.com"><anton@au.ibm.com></a>
        <br>
           */
        <br>
        +#include <linux/export.h>
        <br>
          #include <asm/ppc_asm.h>
        <br>
        <br>
        -#ifndef SELFTEST_CASE
        <br>
        -/* 0 == don't use VMX, 1 == use VMX */
        <br>
        -#define SELFTEST_CASE  0
        <br>
        -#endif
        <br>
        -
        <br>
          #ifdef __BIG_ENDIAN__
        <br>
          #define LVS(VRT,RA,RB)         lvsl    VRT,RA,RB
        <br>
          #define VPERM(VRT,VRA,VRB,VRC) vperm   VRT,VRA,VRB,VRC
        <br>
        @@ -47,10 +43,14 @@
        <br>
                 ld      r15,STK_REG(R15)(r1)
        <br>
                 ld      r14,STK_REG(R14)(r1)
        <br>
          .Ldo_err3:
        <br>
        -       bl      CFUNC(exit_vmx_usercopy)
        <br>
        +       ld      r6,STK_REG(R31)(r1)     /* original destination
        pointer */
        <br>
        +       ld      r5,STK_REG(R29)(r1)     /* original number of
        bytes */
        <br>
        +       subf    r7,r6,r3                /* #bytes copied */
        <br>
        +       subf    r3,r7,r5                /* #bytes not copied in
        r3 */
        <br>
                 ld      r0,STACKFRAMESIZE+16(r1)
        <br>
                 mtlr    r0
        <br>
        -       b       .Lexit
        <br>
        +       addi    r1,r1,STACKFRAMESIZE
        <br>
        +       blr
        <br>
          #endif /* CONFIG_ALTIVEC */
        <br>
        <br>
          .Ldo_err2:
        <br>
        @@ -74,7 +74,6 @@
        <br>
        <br>
          _GLOBAL(__copy_tofrom_user_power7)
        <br>
                 cmpldi  r5,16
        <br>
        -       cmpldi  cr1,r5,3328
        <br>
        <br>
                 std     r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
        <br>
                 std     r4,-STACKFRAMESIZE+STK_REG(R30)(r1)
        <br>
        @@ -82,12 +81,6 @@ _GLOBAL(__copy_tofrom_user_power7)
        <br>
        <br>
                 blt     .Lshort_copy
        <br>
        <br>
        -#ifdef CONFIG_ALTIVEC
        <br>
        -test_feature = SELFTEST_CASE
        <br>
        -BEGIN_FTR_SECTION
        <br>
        -       bgt     cr1,.Lvmx_copy
        <br>
        -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        <br>
        -#endif
        <br>
        <br>
          .Lnonvmx_copy:
        <br>
                 /* Get the source 8B aligned */
        <br>
        @@ -263,23 +256,14 @@ err1;     stb     r0,0(r3)
        <br>
          15:    li      r3,0
        <br>
                 blr
        <br>
        <br>
        -.Lunwind_stack_nonvmx_copy:
        <br>
        -       addi    r1,r1,STACKFRAMESIZE
        <br>
        -       b       .Lnonvmx_copy
        <br>
        -
        <br>
        -.Lvmx_copy:
        <br>
          #ifdef CONFIG_ALTIVEC
        <br>
        +_GLOBAL(__copy_tofrom_user_power7_vmx)
        <br>
                 mflr    r0
        <br>
                 std     r0,16(r1)
        <br>
                 stdu    r1,-STACKFRAMESIZE(r1)
        <br>
        -       bl      CFUNC(enter_vmx_usercopy)
        <br>
        -       cmpwi   cr1,r3,0
        <br>
        -       ld      r0,STACKFRAMESIZE+16(r1)
        <br>
        -       ld      r3,STK_REG(R31)(r1)
        <br>
        -       ld      r4,STK_REG(R30)(r1)
        <br>
        -       ld      r5,STK_REG(R29)(r1)
        <br>
        -       mtlr    r0
        <br>
        <br>
        +       std     r3,STK_REG(R31)(r1)
        <br>
        +       std     r5,STK_REG(R29)(r1)
        <br>
                 /*
        <br>
                  * We prefetch both the source and destination using
        enhanced touch
        <br>
                  * instructions. We use a stream ID of 0 for the load
        side and
        <br>
        @@ -300,8 +284,6 @@ err1;       stb     r0,0(r3)
        <br>
        <br>
                 DCBT_SETUP_STREAMS(r6, r7, r9, r10, r8)
        <br>
        <br>
        -       beq     cr1,.Lunwind_stack_nonvmx_copy
        <br>
        -
        <br>
                 /*
        <br>
                  * If source and destination are not relatively aligned
        we use a
        <br>
                  * slower permute loop.
        <br>
        @@ -478,7 +460,8 @@ err3;       lbz     r0,0(r4)
        <br>
          err3;  stb     r0,0(r3)
        <br>
        <br>
          15:    addi    r1,r1,STACKFRAMESIZE
        <br>
        -       b       CFUNC(exit_vmx_usercopy)        /* tail call
        optimise */
        <br>
        +       li r3,0
        <br>
        +       blr
        <br>
        <br>
          .Lvmx_unaligned_copy:
        <br>
                 /* Get the destination 16B aligned */
        <br>
        @@ -681,5 +664,7 @@ err3;       lbz     r0,0(r4)
        <br>
          err3;  stb     r0,0(r3)
        <br>
        <br>
          15:    addi    r1,r1,STACKFRAMESIZE
        <br>
        -       b       CFUNC(exit_vmx_usercopy)        /* tail call
        optimise */
        <br>
        +       li r3,0
        <br>
        +       blr
        <br>
        +EXPORT_SYMBOL(__copy_tofrom_user_power7_vmx)
        <br>
          #endif /* CONFIG_ALTIVEC */
        <br>
        diff --git a/arch/powerpc/lib/vmx-helper.c
        b/arch/powerpc/lib/vmx-helper.c
        <br>
        index 54340912398f..554b248002b4 100644
        <br>
        --- a/arch/powerpc/lib/vmx-helper.c
        <br>
        +++ b/arch/powerpc/lib/vmx-helper.c
        <br>
        @@ -27,6 +27,7 @@ int enter_vmx_usercopy(void)
        <br>
        <br>
                 return 1;
        <br>
          }
        <br>
        +EXPORT_SYMBOL(enter_vmx_usercopy);
        <br>
        <br>
          /*
        <br>
           * This function must return 0 because we tail call optimise
        when calling
        <br>
        @@ -49,6 +50,7 @@ int exit_vmx_usercopy(void)
        <br>
                         set_dec(1);
        <br>
                 return 0;
        <br>
          }
        <br>
        +EXPORT_SYMBOL(exit_vmx_usercopy);
        <br>
        <br>
          int enter_vmx_ops(void)
        <br>
          {
        <br>
        --
        <br>
        2.52.0
        <br>
        <br>
      </blockquote>
      <br>
      <br>
    </blockquote>
  </body>
</html>