Commit d17ae813 authored by Linus Torvalds's avatar Linus Torvalds

sparse: make x86 user pointer checks stricter.

Also use "__force" when forcing the user address to "unsigned long"
for the address limit check.
parent 0c41bbc8
...@@ -34,6 +34,10 @@ ...@@ -34,6 +34,10 @@
#define segment_eq(a,b) ((a).seg == (b).seg) #define segment_eq(a,b) ((a).seg == (b).seg)
extern long not_a_user_address;
#define check_user_ptr(x) \
(void) ({ void __user * __userptr = (__typeof__(*(x)) *)&not_a_user_address; __userptr; })
/* /*
* movsl can be slow when source and dest are not both 8-byte aligned * movsl can be slow when source and dest are not both 8-byte aligned
*/ */
...@@ -43,7 +47,7 @@ extern struct movsl_mask { ...@@ -43,7 +47,7 @@ extern struct movsl_mask {
} ____cacheline_aligned_in_smp movsl_mask; } ____cacheline_aligned_in_smp movsl_mask;
#endif #endif
#define __addr_ok(addr) ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg)) #define __addr_ok(addr) ((unsigned long __force)(addr) < (current_thread_info()->addr_limit.seg))
/* /*
* Test whether a block of memory is a valid user space address. * Test whether a block of memory is a valid user space address.
...@@ -56,6 +60,7 @@ extern struct movsl_mask { ...@@ -56,6 +60,7 @@ extern struct movsl_mask {
*/ */
#define __range_ok(addr,size) ({ \ #define __range_ok(addr,size) ({ \
unsigned long flag,sum; \ unsigned long flag,sum; \
check_user_ptr(addr); \
asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \ asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \
:"=&r" (flag), "=r" (sum) \ :"=&r" (flag), "=r" (sum) \
:"1" (addr),"g" ((int)(size)),"g" (current_thread_info()->addr_limit.seg)); \ :"1" (addr),"g" ((int)(size)),"g" (current_thread_info()->addr_limit.seg)); \
...@@ -170,6 +175,7 @@ extern void __get_user_4(void); ...@@ -170,6 +175,7 @@ extern void __get_user_4(void);
*/ */
#define get_user(x,ptr) \ #define get_user(x,ptr) \
({ int __ret_gu,__val_gu; \ ({ int __ret_gu,__val_gu; \
check_user_ptr(ptr); \
switch(sizeof (*(ptr))) { \ switch(sizeof (*(ptr))) { \
case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \ case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \
case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break; \ case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break; \
...@@ -288,6 +294,7 @@ extern void __put_user_bad(void); ...@@ -288,6 +294,7 @@ extern void __put_user_bad(void);
#define __put_user_size(x,ptr,size,retval,errret) \ #define __put_user_size(x,ptr,size,retval,errret) \
do { \ do { \
retval = 0; \ retval = 0; \
check_user_ptr(ptr); \
switch (size) { \ switch (size) { \
case 1: __put_user_asm(x,ptr,retval,"b","b","iq",errret);break; \ case 1: __put_user_asm(x,ptr,retval,"b","b","iq",errret);break; \
case 2: __put_user_asm(x,ptr,retval,"w","w","ir",errret);break; \ case 2: __put_user_asm(x,ptr,retval,"w","w","ir",errret);break; \
...@@ -346,6 +353,7 @@ extern long __get_user_bad(void); ...@@ -346,6 +353,7 @@ extern long __get_user_bad(void);
#define __get_user_size(x,ptr,size,retval,errret) \ #define __get_user_size(x,ptr,size,retval,errret) \
do { \ do { \
retval = 0; \ retval = 0; \
check_user_ptr(ptr); \
switch (size) { \ switch (size) { \
case 1: __get_user_asm(x,ptr,retval,"b","b","=q",errret);break; \ case 1: __get_user_asm(x,ptr,retval,"b","b","=q",errret);break; \
case 2: __get_user_asm(x,ptr,retval,"w","w","=r",errret);break; \ case 2: __get_user_asm(x,ptr,retval,"w","w","=r",errret);break; \
...@@ -403,13 +411,13 @@ __copy_to_user(void __user *to, const void *from, unsigned long n) ...@@ -403,13 +411,13 @@ __copy_to_user(void __user *to, const void *from, unsigned long n)
switch (n) { switch (n) {
case 1: case 1:
__put_user_size(*(u8 *)from, (u8 *)to, 1, ret, 1); __put_user_size(*(u8 *)from, (u8 __user *)to, 1, ret, 1);
return ret; return ret;
case 2: case 2:
__put_user_size(*(u16 *)from, (u16 *)to, 2, ret, 2); __put_user_size(*(u16 *)from, (u16 __user *)to, 2, ret, 2);
return ret; return ret;
case 4: case 4:
__put_user_size(*(u32 *)from, (u32 *)to, 4, ret, 4); __put_user_size(*(u32 *)from, (u32 __user *)to, 4, ret, 4);
return ret; return ret;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment