raid6: riscv: Fix NULL pointer dereference caused by a missing clobber
authorChunyan Zhang <zhangchunyan@iscas.ac.cn>
Tue, 10 Jun 2025 10:12:32 +0000 (18:12 +0800)
committerPalmer Dabbelt <palmer@dabbelt.com>
Thu, 12 Jun 2025 19:21:48 +0000 (12:21 -0700)
When running the raid6 user-space test program on RISC-V QEMU, there's a
segmentation fault which seems caused by accessing a NULL pointer,
which is the pointer variable p/q in raid6_rvv*_gen/xor_syndrome_real(),
p/q should have been equal to dptr[x], but when I use GDB command to
see its value, which was 0x10 like below:

"
Program received signal SIGSEGV, Segmentation fault.
0x0000000000011062 in raid6_rvv2_xor_syndrome_real (disks=<optimized out>, start=0, stop=<optimized out>, bytes=4096, ptrs=<optimized out>) at rvv.c:386
(gdb) p p
$1 = (u8 *) 0x10 <error: Cannot access memory at address 0x10>
"

The issue was found to be related with:
1) Compile optimization
   There's no segmentation fault if compiling the raid6test program with
   the optimization flag -O0.
2) The RISC-V vector command vsetvli
   If not used t0 as the first parameter in vsetvli, there's no
   segmentation fault either.

This patch selects the 2nd solution to fix the issue.

[Palmer: The actual issue here is a missing clobber in the vsetvli code.
It's a little tricky: we've already probed for VLENB so we don't need to
look at the output register, we just need to have an X register in the
instruction as that's the form required to actually set VL.  Thus we
clobber a register, and without describing that we end up breaking
compilers.]

Fixes: 6093faaf9593 ("raid6: Add RISC-V SIMD syndrome and recovery calculations")
Signed-off-by: Chunyan Zhang <zhangchunyan@iscas.ac.cn>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20250610101234.1100660-3-zhangchunyan@iscas.ac.cn
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
lib/raid6/rvv.c

index f0887344b274cb11cc6fd10a20f2c40549b43b43..7d82efa5b14f9e2ceb37a88e509883856870db43 100644 (file)
@@ -26,9 +26,9 @@ static int rvv_has_vector(void)
 static void raid6_rvv1_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs)
 {
        u8 **dptr = (u8 **)ptrs;
-       unsigned long d;
-       int z, z0;
        u8 *p, *q;
+       unsigned long vl, d;
+       int z, z0;
 
        z0 = disks - 3;         /* Highest data disk */
        p = dptr[z0 + 1];               /* XOR parity */
@@ -36,8 +36,9 @@ static void raid6_rvv1_gen_syndrome_real(int disks, unsigned long bytes, void **
 
        asm volatile (".option  push\n"
                      ".option  arch,+v\n"
-                     "vsetvli  t0, x0, e8, m1, ta, ma\n"
+                     "vsetvli  %0, x0, e8, m1, ta, ma\n"
                      ".option  pop\n"
+                     : "=&r" (vl)
        );
 
         /* v0:wp0, v1:wq0, v2:wd0/w20, v3:w10 */
@@ -99,7 +100,7 @@ static void raid6_rvv1_xor_syndrome_real(int disks, int start, int stop,
 {
        u8 **dptr = (u8 **)ptrs;
        u8 *p, *q;
-       unsigned long d;
+       unsigned long vl, d;
        int z, z0;
 
        z0 = stop;              /* P/Q right side optimization */
@@ -108,8 +109,9 @@ static void raid6_rvv1_xor_syndrome_real(int disks, int start, int stop,
 
        asm volatile (".option  push\n"
                      ".option  arch,+v\n"
-                     "vsetvli  t0, x0, e8, m1, ta, ma\n"
+                     "vsetvli  %0, x0, e8, m1, ta, ma\n"
                      ".option  pop\n"
+                     : "=&r" (vl)
        );
 
        /* v0:wp0, v1:wq0, v2:wd0/w20, v3:w10 */
@@ -195,9 +197,9 @@ static void raid6_rvv1_xor_syndrome_real(int disks, int start, int stop,
 static void raid6_rvv2_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs)
 {
        u8 **dptr = (u8 **)ptrs;
-       unsigned long d;
-       int z, z0;
        u8 *p, *q;
+       unsigned long vl, d;
+       int z, z0;
 
        z0 = disks - 3;         /* Highest data disk */
        p = dptr[z0 + 1];               /* XOR parity */
@@ -205,8 +207,9 @@ static void raid6_rvv2_gen_syndrome_real(int disks, unsigned long bytes, void **
 
        asm volatile (".option  push\n"
                      ".option  arch,+v\n"
-                     "vsetvli  t0, x0, e8, m1, ta, ma\n"
+                     "vsetvli  %0, x0, e8, m1, ta, ma\n"
                      ".option  pop\n"
+                     : "=&r" (vl)
        );
 
        /*
@@ -287,7 +290,7 @@ static void raid6_rvv2_xor_syndrome_real(int disks, int start, int stop,
 {
        u8 **dptr = (u8 **)ptrs;
        u8 *p, *q;
-       unsigned long d;
+       unsigned long vl, d;
        int z, z0;
 
        z0 = stop;              /* P/Q right side optimization */
@@ -296,8 +299,9 @@ static void raid6_rvv2_xor_syndrome_real(int disks, int start, int stop,
 
        asm volatile (".option  push\n"
                      ".option  arch,+v\n"
-                     "vsetvli  t0, x0, e8, m1, ta, ma\n"
+                     "vsetvli  %0, x0, e8, m1, ta, ma\n"
                      ".option  pop\n"
+                     : "=&r" (vl)
        );
 
        /*
@@ -413,9 +417,9 @@ static void raid6_rvv2_xor_syndrome_real(int disks, int start, int stop,
 static void raid6_rvv4_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs)
 {
        u8 **dptr = (u8 **)ptrs;
-       unsigned long d;
-       int z, z0;
        u8 *p, *q;
+       unsigned long vl, d;
+       int z, z0;
 
        z0 = disks - 3; /* Highest data disk */
        p = dptr[z0 + 1];       /* XOR parity */
@@ -423,8 +427,9 @@ static void raid6_rvv4_gen_syndrome_real(int disks, unsigned long bytes, void **
 
        asm volatile (".option  push\n"
                      ".option  arch,+v\n"
-                     "vsetvli  t0, x0, e8, m1, ta, ma\n"
+                     "vsetvli  %0, x0, e8, m1, ta, ma\n"
                      ".option  pop\n"
+                     : "=&r" (vl)
        );
 
        /*
@@ -539,7 +544,7 @@ static void raid6_rvv4_xor_syndrome_real(int disks, int start, int stop,
 {
        u8 **dptr = (u8 **)ptrs;
        u8 *p, *q;
-       unsigned long d;
+       unsigned long vl, d;
        int z, z0;
 
        z0 = stop;              /* P/Q right side optimization */
@@ -548,8 +553,9 @@ static void raid6_rvv4_xor_syndrome_real(int disks, int start, int stop,
 
        asm volatile (".option  push\n"
                      ".option  arch,+v\n"
-                     "vsetvli  t0, x0, e8, m1, ta, ma\n"
+                     "vsetvli  %0, x0, e8, m1, ta, ma\n"
                      ".option  pop\n"
+                     : "=&r" (vl)
        );
 
        /*
@@ -721,9 +727,9 @@ static void raid6_rvv4_xor_syndrome_real(int disks, int start, int stop,
 static void raid6_rvv8_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs)
 {
        u8 **dptr = (u8 **)ptrs;
-       unsigned long d;
-       int z, z0;
        u8 *p, *q;
+       unsigned long vl, d;
+       int z, z0;
 
        z0 = disks - 3; /* Highest data disk */
        p = dptr[z0 + 1];       /* XOR parity */
@@ -731,8 +737,9 @@ static void raid6_rvv8_gen_syndrome_real(int disks, unsigned long bytes, void **
 
        asm volatile (".option  push\n"
                      ".option  arch,+v\n"
-                     "vsetvli  t0, x0, e8, m1, ta, ma\n"
+                     "vsetvli  %0, x0, e8, m1, ta, ma\n"
                      ".option  pop\n"
+                     : "=&r" (vl)
        );
 
        /*
@@ -915,7 +922,7 @@ static void raid6_rvv8_xor_syndrome_real(int disks, int start, int stop,
 {
        u8 **dptr = (u8 **)ptrs;
        u8 *p, *q;
-       unsigned long d;
+       unsigned long vl, d;
        int z, z0;
 
        z0 = stop;              /* P/Q right side optimization */
@@ -924,8 +931,9 @@ static void raid6_rvv8_xor_syndrome_real(int disks, int start, int stop,
 
        asm volatile (".option  push\n"
                      ".option  arch,+v\n"
-                     "vsetvli  t0, x0, e8, m1, ta, ma\n"
+                     "vsetvli  %0, x0, e8, m1, ta, ma\n"
                      ".option  pop\n"
+                     : "=&r" (vl)
        );
 
        /*