]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
parisc: Revise __get_user() to probe user read access
authorJohn David Anglin <dave.anglin@bell.net>
Fri, 25 Jul 2025 17:51:32 +0000 (13:51 -0400)
committerHelge Deller <deller@gmx.de>
Fri, 25 Jul 2025 20:45:24 +0000 (22:45 +0200)
Because of the way read access support is implemented, read access
interruptions are only triggered at privilege levels 2 and 3. The
kernel executes at privilege level 0, so __get_user() never triggers
a read access interruption (code 26). Thus, it is currently possible
for user code to access a read protected address via a system call.

Fix this by probing read access rights at privilege level 3 (PRIV_USER)
and setting __gu_err to -EFAULT (-14) if access isn't allowed.

Note the cmpiclr instruction does a 32-bit compare because COND macro
doesn't work inside asm.

Signed-off-by: John David Anglin <dave.anglin@bell.net>
Signed-off-by: Helge Deller <deller@gmx.de>
Cc: stable@vger.kernel.org # v5.12+
arch/parisc/include/asm/uaccess.h

index 88d0ae5769dde54e29176e286da359eb6a54e7bf..6c531d2c847eb11c3ad290e3c2712445d345355c 100644 (file)
        __gu_err;                                       \
 })
 
-#define __get_user(val, ptr)                           \
-({                                                     \
-       __get_user_internal(SR_USER, val, ptr); \
+#define __probe_user_internal(sr, error, ptr)                  \
+({                                                             \
+       __asm__("\tproberi (%%sr%1,%2),%3,%0\n"                 \
+               "\tcmpiclr,= 1,%0,%0\n"                         \
+               "\tldi %4,%0\n"                                 \
+               : "=r"(error)                                   \
+               : "i"(sr), "r"(ptr), "i"(PRIV_USER),            \
+                 "i"(-EFAULT));                                \
+})
+
+#define __get_user(val, ptr)                                   \
+({                                                             \
+       register long __gu_err;                                 \
+                                                               \
+       __gu_err = __get_user_internal(SR_USER, val, ptr);      \
+       if (likely(!__gu_err))                                  \
+               __probe_user_internal(SR_USER, __gu_err, ptr);  \
+       __gu_err;                                               \
 })
 
 #define __get_user_asm(sr, val, ldx, ptr)              \