parisc: Fix some apparent put_user() failures
authorHelge Deller <deller@gmx.de>
Sun, 13 Feb 2022 21:52:11 +0000 (22:52 +0100)
committerHelge Deller <deller@gmx.de>
Mon, 14 Feb 2022 11:36:42 +0000 (12:36 +0100)
After commit 4b9d2a731c3d ("parisc: Switch user access functions
to signal errors in r29 instead of r8") bash suddenly started
to report those warnings after login:

-bash: cannot set terminal process group (-1): Bad file descriptor
-bash: no job control in this shell

It turned out, that a function call inside a put_user(), e.g.:
put_user(vt_do_kdgkbmode(console), (int __user *)arg);
clobbered the error register (r29) and thus the put_user() call itself
seem to have failed.

Rearrange the C-code to pre-calculate the intermediate value
and then do the put_user().
Additionally prefer the "+" constraint on pu_err and gu_err registers
to tell the compiler that those operands are both read and written by
the assembly instruction.

Reported-by: John David Anglin <dave.anglin@bell.net>
Signed-off-by: Helge Deller <deller@gmx.de>
Fixes: 4b9d2a731c3d ("parisc: Switch user access functions to signal errors in r29 instead of r8")
Signed-off-by: Helge Deller <deller@gmx.de>
arch/parisc/include/asm/uaccess.h

index ebf8a845b01742f1fe75c8cace45b6e2ef4373ce..123d5f16cd9db2381c95247e20dc5dc18a78d33a 100644 (file)
@@ -89,8 +89,8 @@ struct exception_table_entry {
        __asm__("1: " ldx " 0(" sr "%2),%0\n"           \
                "9:\n"                                  \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
-               : "=r"(__gu_val), "=r"(__gu_err)        \
-               : "r"(ptr), "1"(__gu_err));             \
+               : "=r"(__gu_val), "+r"(__gu_err)        \
+               : "r"(ptr));                            \
                                                        \
        (val) = (__force __typeof__(*(ptr))) __gu_val;  \
 }
@@ -123,8 +123,8 @@ struct exception_table_entry {
                "9:\n"                                  \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \
-               : "=&r"(__gu_tmp.l), "=r"(__gu_err)     \
-               : "r"(ptr), "1"(__gu_err));             \
+               : "=&r"(__gu_tmp.l), "+r"(__gu_err)     \
+               : "r"(ptr));                            \
                                                        \
        (val) = __gu_tmp.t;                             \
 }
@@ -135,13 +135,12 @@ struct exception_table_entry {
 #define __put_user_internal(sr, x, ptr)                                \
 ({                                                             \
        ASM_EXCEPTIONTABLE_VAR(__pu_err);                       \
-        __typeof__(*(ptr)) __x = (__typeof__(*(ptr)))(x);      \
                                                                \
        switch (sizeof(*(ptr))) {                               \
-       case 1: __put_user_asm(sr, "stb", __x, ptr); break;     \
-       case 2: __put_user_asm(sr, "sth", __x, ptr); break;     \
-       case 4: __put_user_asm(sr, "stw", __x, ptr); break;     \
-       case 8: STD_USER(sr, __x, ptr); break;                  \
+       case 1: __put_user_asm(sr, "stb", x, ptr); break;       \
+       case 2: __put_user_asm(sr, "sth", x, ptr); break;       \
+       case 4: __put_user_asm(sr, "stw", x, ptr); break;       \
+       case 8: STD_USER(sr, x, ptr); break;                    \
        default: BUILD_BUG();                                   \
        }                                                       \
                                                                \
@@ -150,7 +149,9 @@ struct exception_table_entry {
 
 #define __put_user(x, ptr)                                     \
 ({                                                             \
-       __put_user_internal("%%sr3,", x, ptr);                  \
+       __typeof__(&*(ptr)) __ptr = ptr;                        \
+       __typeof__(*(__ptr)) __x = (__typeof__(*(__ptr)))(x);   \
+       __put_user_internal("%%sr3,", __x, __ptr);              \
 })
 
 #define __put_kernel_nofault(dst, src, type, err_label)                \
@@ -180,8 +181,8 @@ struct exception_table_entry {
                "1: " stx " %2,0(" sr "%1)\n"                   \
                "9:\n"                                          \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)         \
-               : "=r"(__pu_err)                                \
-               : "r"(ptr), "r"(x), "0"(__pu_err))
+               : "+r"(__pu_err)                                \
+               : "r"(ptr), "r"(x))
 
 
 #if !defined(CONFIG_64BIT)
@@ -193,8 +194,8 @@ struct exception_table_entry {
                "9:\n"                                          \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)         \
                ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b)         \
-               : "=r"(__pu_err)                                \
-               : "r"(ptr), "r"(__val), "0"(__pu_err));         \
+               : "+r"(__pu_err)                                \
+               : "r"(ptr), "r"(__val));                        \
 } while (0)
 
 #endif /* !defined(CONFIG_64BIT) */