Le 27/11/2021 à 19:10, Christophe Leroy a écrit :
copy_inst_from_kernel_nofault() uses copy_from_kernel_nofault() to
copy one or two 32bits words. This means calling an out-of-line
function which itself calls back copy_from_kernel_nofault_allowed()
then performs a generic copy with loops.

Rewrite copy_inst_from_kernel_nofault() to do everything at a
single place and use __get_kernel_nofault() directly to perform
single accesses without loops.

Before the patch:

        00000018 <copy_inst_from_kernel_nofault>:
          18:   94 21 ff e0     stwu    r1,-32(r1)
          1c:   7c 08 02 a6     mflr    r0
          20:   38 a0 00 04     li      r5,4
          24:   93 e1 00 1c     stw     r31,28(r1)
          28:   7c 7f 1b 78     mr      r31,r3
          2c:   38 61 00 08     addi    r3,r1,8
          30:   90 01 00 24     stw     r0,36(r1)
          34:   48 00 00 01     bl      34 <copy_inst_from_kernel_nofault+0x1c>
                                34: R_PPC_REL24 copy_from_kernel_nofault
          38:   2c 03 00 00     cmpwi   r3,0
          3c:   40 82 00 0c     bne     48 <copy_inst_from_kernel_nofault+0x30>
          40:   81 21 00 08     lwz     r9,8(r1)
          44:   91 3f 00 00     stw     r9,0(r31)
          48:   80 01 00 24     lwz     r0,36(r1)
          4c:   83 e1 00 1c     lwz     r31,28(r1)
          50:   38 21 00 20     addi    r1,r1,32
          54:   7c 08 03 a6     mtlr    r0
          58:   4e 80 00 20     blr

After the patch:

        00000018 <copy_inst_from_kernel_nofault>:
          18:   3d 20 b0 00     lis     r9,-20480
          1c:   7c 04 48 40     cmplw   r4,r9
          20:   7c 69 1b 78     mr      r9,r3
          24:   41 80 00 2c     blt     50 <copy_inst_from_kernel_nofault+0x38>
          28:   81 42 04 d0     lwz     r10,1232(r2)
          2c:   39 4a 00 01     addi    r10,r10,1
          30:   91 42 04 d0     stw     r10,1232(r2)
          34:   80 e4 00 00     lwz     r7,0(r4)
          38:   81 42 04 d0     lwz     r10,1232(r2)
          3c:   38 60 00 00     li      r3,0
          40:   39 4a ff ff     addi    r10,r10,-1
          44:   91 42 04 d0     stw     r10,1232(r2)
          48:   90 e9 00 00     stw     r7,0(r9)
          4c:   4e 80 00 20     blr

          50:   38 60 ff de     li      r3,-34
          54:   4e 80 00 20     blr
          58:   81 22 04 d0     lwz     r9,1232(r2)
          5c:   38 60 ff f2     li      r3,-14
          60:   39 29 ff ff     addi    r9,r9,-1
          64:   91 22 04 d0     stw     r9,1232(r2)
          68:   4e 80 00 20     blr

Signed-off-by: Christophe Leroy <christophe.le...@csgroup.eu>
---
v3: New
---
  arch/powerpc/mm/maccess.c | 18 ++++++++++++------
  1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/mm/maccess.c b/arch/powerpc/mm/maccess.c
index 5abae96b2b46..90309806f5eb 100644
--- a/arch/powerpc/mm/maccess.c
+++ b/arch/powerpc/mm/maccess.c
@@ -15,16 +15,22 @@ bool copy_from_kernel_nofault_allowed(const void 
*unsafe_src, size_t size)
  int copy_inst_from_kernel_nofault(ppc_inst_t *inst, u32 *src)
  {
        unsigned int val, suffix;
-       int err;
- err = copy_from_kernel_nofault(&val, src, sizeof(val));
-       if (err)
-               return err;
+       if (unlikely(!is_kernel_addr((unsigned long)src)))
+               return -ERANGE;
+
+       pagefault_disable();

Allthough generic version of copy_from_kernel_nofault() does it, disabling pagefault is pointless here because we are accessing kernel addresses only, so a page fault will always fail via bad_kernel_fault(), it will never reach the faulthandler_disabled() test.

+       __get_kernel_nofault(&val, src, u32, Efault);
        if (IS_ENABLED(CONFIG_PPC64) && get_op(val) == OP_PREFIX) {
-               err = copy_from_kernel_nofault(&suffix, src + 1, 
sizeof(suffix));
+               __get_kernel_nofault(&suffix, src + 1, u32, Efault);
+               pagefault_enable();
                *inst = ppc_inst_prefix(val, suffix);
        } else {
+               pagefault_enable();
                *inst = ppc_inst(val);
        }
-       return err;
+       return 0;
+Efault:
+       pagefault_enable();
+       return -EFAULT;
  }

Reply via email to