First of all, on short copies __copy_{to,from}_user() return the amount
of bytes left uncopied, *not* -EFAULT.  get_user() and put_user() are
expected to return -EFAULT on failure.

Another problem is get_user(v32, (__u64 __user *)p); that should
fetch 64bit value and the assign it to v32, truncating it in process.
Current code, OTOH, reads 8 bytes of data and stores them at the
address of v32, stomping on the 4 bytes that follow v32 itself.

Signed-off-by: Al Viro <v...@zeniv.linux.org.uk>
--
diff --git a/arch/xtensa/include/asm/uaccess.h 
b/arch/xtensa/include/asm/uaccess.h
index 6792928ba84a..155174ddb7ae 100644
--- a/arch/xtensa/include/asm/uaccess.h
+++ b/arch/xtensa/include/asm/uaccess.h
@@ -100,7 +100,7 @@ do {                                                        
                \
        case 4: __put_user_asm(x, ptr, retval, 4, "s32i", __cb); break; \
        case 8: {                                                       \
                     __typeof__(*ptr) __v64 = x;                        \
-                    retval = __copy_to_user(ptr, &__v64, 8);           \
+                    retval = __copy_to_user(ptr, &__v64, 8) ? -EFAULT : 0;     
\
                     break;                                             \
                }                                                       \
        default: __put_user_bad();                                      \
@@ -198,7 +198,12 @@ do {                                                       
                \
        case 1: __get_user_asm(x, ptr, retval, 1, "l8ui", __cb);  break;\
        case 2: __get_user_asm(x, ptr, retval, 2, "l16ui", __cb); break;\
        case 4: __get_user_asm(x, ptr, retval, 4, "l32i", __cb);  break;\
-       case 8: retval = __copy_from_user(&x, ptr, 8);    break;        \
+       case 8: {                                                       \
+               __u64 __x = 0;                                          \
+               retval = __copy_from_user(&__x, ptr, 8) ? -EFAULT : 0;  \
+               (x) = *(__force __typeof__(*(ptr)) *) &__x;             \
+               break;                                                  \
+       }                                                               \
        default: (x) = __get_user_bad();                                \
        }                                                               \
 } while (0)

Reply via email to