Commit 67e8b28b authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] sparse: amd64 annotation - beginning

	Annotated basic primitives (copy_.._user, get_user, ...).
Functions got __user in prototypes, macros (in uaccess.h) got a
conditional check - see CHECK_UPTR() below.  If you have more elegant
way to deal with the macros - please, tell.
parent ecf88904
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* src and dst are best aligned to 64bits. * src and dst are best aligned to 64bits.
*/ */
unsigned int unsigned int
csum_partial_copy_from_user(const char *src, char *dst, csum_partial_copy_from_user(const char __user *src, char *dst,
int len, unsigned int isum, int *errp) int len, unsigned int isum, int *errp)
{ {
*errp = 0; *errp = 0;
...@@ -33,7 +33,7 @@ csum_partial_copy_from_user(const char *src, char *dst, ...@@ -33,7 +33,7 @@ csum_partial_copy_from_user(const char *src, char *dst,
if (unlikely((unsigned long)src & 6)) { if (unlikely((unsigned long)src & 6)) {
while (((unsigned long)src & 6) && len >= 2) { while (((unsigned long)src & 6) && len >= 2) {
__u16 val16; __u16 val16;
*errp = __get_user(val16, (__u16 *)src); *errp = __get_user(val16, (__u16 __user *)src);
if (*errp) if (*errp)
return isum; return isum;
*(__u16 *)dst = val16; *(__u16 *)dst = val16;
...@@ -43,7 +43,7 @@ csum_partial_copy_from_user(const char *src, char *dst, ...@@ -43,7 +43,7 @@ csum_partial_copy_from_user(const char *src, char *dst,
len -= 2; len -= 2;
} }
} }
isum = csum_partial_copy_generic(src,dst,len,isum,errp,NULL); isum = csum_partial_copy_generic((void *)src,dst,len,isum,errp,NULL);
if (likely(*errp == 0)) if (likely(*errp == 0))
return isum; return isum;
} }
...@@ -66,7 +66,7 @@ EXPORT_SYMBOL(csum_partial_copy_from_user); ...@@ -66,7 +66,7 @@ EXPORT_SYMBOL(csum_partial_copy_from_user);
* src and dst are best aligned to 64bits. * src and dst are best aligned to 64bits.
*/ */
unsigned int unsigned int
csum_partial_copy_to_user(const char *src, char *dst, csum_partial_copy_to_user(const char *src, char __user *dst,
int len, unsigned int isum, int *errp) int len, unsigned int isum, int *errp)
{ {
if (unlikely(!access_ok(VERIFY_WRITE, dst, len))) { if (unlikely(!access_ok(VERIFY_WRITE, dst, len))) {
...@@ -78,7 +78,7 @@ csum_partial_copy_to_user(const char *src, char *dst, ...@@ -78,7 +78,7 @@ csum_partial_copy_to_user(const char *src, char *dst,
while (((unsigned long)dst & 6) && len >= 2) { while (((unsigned long)dst & 6) && len >= 2) {
__u16 val16 = *(__u16 *)src; __u16 val16 = *(__u16 *)src;
isum = add32_with_carry(isum, val16); isum = add32_with_carry(isum, val16);
*errp = __put_user(val16, (__u16 *)dst); *errp = __put_user(val16, (__u16 __user *)dst);
if (*errp) if (*errp)
return isum; return isum;
src += 2; src += 2;
...@@ -88,7 +88,7 @@ csum_partial_copy_to_user(const char *src, char *dst, ...@@ -88,7 +88,7 @@ csum_partial_copy_to_user(const char *src, char *dst,
} }
*errp = 0; *errp = 0;
return csum_partial_copy_generic(src,dst,len,isum,NULL,errp); return csum_partial_copy_generic(src, (void *)dst,len,isum,NULL,errp);
} }
EXPORT_SYMBOL(csum_partial_copy_to_user); EXPORT_SYMBOL(csum_partial_copy_to_user);
......
...@@ -40,7 +40,7 @@ do { \ ...@@ -40,7 +40,7 @@ do { \
} while (0) } while (0)
long long
__strncpy_from_user(char *dst, const char *src, long count) __strncpy_from_user(char *dst, const char __user *src, long count)
{ {
long res; long res;
__do_strncpy_from_user(dst, src, count, res); __do_strncpy_from_user(dst, src, count, res);
...@@ -48,7 +48,7 @@ __strncpy_from_user(char *dst, const char *src, long count) ...@@ -48,7 +48,7 @@ __strncpy_from_user(char *dst, const char *src, long count)
} }
long long
strncpy_from_user(char *dst, const char *src, long count) strncpy_from_user(char *dst, const char __user *src, long count)
{ {
long res = -EFAULT; long res = -EFAULT;
if (access_ok(VERIFY_READ, src, 1)) if (access_ok(VERIFY_READ, src, 1))
...@@ -60,7 +60,7 @@ strncpy_from_user(char *dst, const char *src, long count) ...@@ -60,7 +60,7 @@ strncpy_from_user(char *dst, const char *src, long count)
* Zero Userspace * Zero Userspace
*/ */
unsigned long __clear_user(void *addr, unsigned long size) unsigned long __clear_user(void __user *addr, unsigned long size)
{ {
long __d0; long __d0;
/* no memory constraint because it doesn't change any memory gcc knows /* no memory constraint because it doesn't change any memory gcc knows
...@@ -94,7 +94,7 @@ unsigned long __clear_user(void *addr, unsigned long size) ...@@ -94,7 +94,7 @@ unsigned long __clear_user(void *addr, unsigned long size)
} }
unsigned long clear_user(void *to, unsigned long n) unsigned long clear_user(void __user *to, unsigned long n)
{ {
if (access_ok(VERIFY_WRITE, to, n)) if (access_ok(VERIFY_WRITE, to, n))
return __clear_user(to, n); return __clear_user(to, n);
...@@ -107,7 +107,7 @@ unsigned long clear_user(void *to, unsigned long n) ...@@ -107,7 +107,7 @@ unsigned long clear_user(void *to, unsigned long n)
* Return 0 on exception, a value greater than N if too long * Return 0 on exception, a value greater than N if too long
*/ */
long strnlen_user(const char *s, long n) long strnlen_user(const char __user *s, long n)
{ {
long res = 0; long res = 0;
char c; char c;
...@@ -127,7 +127,7 @@ long strnlen_user(const char *s, long n) ...@@ -127,7 +127,7 @@ long strnlen_user(const char *s, long n)
} }
} }
long strlen_user(const char *s) long strlen_user(const char __user *s)
{ {
long res = 0; long res = 0;
char c; char c;
...@@ -142,10 +142,10 @@ long strlen_user(const char *s) ...@@ -142,10 +142,10 @@ long strlen_user(const char *s)
} }
} }
unsigned long copy_in_user(void *to, const void *from, unsigned len) unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len)
{ {
if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) {
return copy_user_generic(to, from, len); return copy_user_generic((void *)to, (void *)from, len);
} }
return len; return len;
} }
...@@ -186,15 +186,15 @@ struct compat_shmid64_ds { ...@@ -186,15 +186,15 @@ struct compat_shmid64_ds {
*/ */
typedef u32 compat_uptr_t; typedef u32 compat_uptr_t;
static inline void *compat_ptr(compat_uptr_t uptr) static inline void __user *compat_ptr(compat_uptr_t uptr)
{ {
return (void *)(unsigned long)uptr; return (void __user *)(unsigned long)uptr;
} }
static __inline__ void *compat_alloc_user_space(long len) static __inline__ void __user *compat_alloc_user_space(long len)
{ {
struct pt_regs *regs = (void *)current->thread.rsp0 - sizeof(struct pt_regs); struct pt_regs *regs = (void *)current->thread.rsp0 - sizeof(struct pt_regs);
return (void *)regs->rsp - len; return (void __user *)regs->rsp - len;
} }
#endif /* _ASM_X86_64_COMPAT_H */ #endif /* _ASM_X86_64_COMPAT_H */
...@@ -33,6 +33,16 @@ ...@@ -33,6 +33,16 @@
#define segment_eq(a,b) ((a).seg == (b).seg) #define segment_eq(a,b) ((a).seg == (b).seg)
#ifdef __CHECKER__
#define CHECK_UPTR(ptr) do { \
__typeof__(*(ptr)) *__dummy_check_uptr = \
(void __user *)&__dummy_check_uptr; \
} while(0)
#else
#define CHECK_UPTR(ptr)
#endif
#define __addr_ok(addr) (!((unsigned long)(addr) & (current_thread_info()->addr_limit.seg))) #define __addr_ok(addr) (!((unsigned long)(addr) & (current_thread_info()->addr_limit.seg)))
/* /*
...@@ -40,15 +50,16 @@ ...@@ -40,15 +50,16 @@
*/ */
#define __range_not_ok(addr,size) ({ \ #define __range_not_ok(addr,size) ({ \
unsigned long flag,sum; \ unsigned long flag,sum; \
CHECK_UPTR(addr); \
asm("# range_ok\n\r" \ asm("# range_ok\n\r" \
"addq %3,%1 ; sbbq %0,%0 ; cmpq %1,%4 ; sbbq $0,%0" \ "addq %3,%1 ; sbbq %0,%0 ; cmpq %1,%4 ; sbbq $0,%0" \
:"=&r" (flag), "=r" (sum) \ :"=&r" (flag), "=r" (sum) \
:"1" (addr),"g" ((long)(size)),"g" (current_thread_info()->addr_limit.seg)); \ :"1" (addr),"g" ((long)(size)),"g" (current_thread_info()->addr_limit.seg)); \
flag; }) flag; })
#define access_ok(type,addr,size) (__range_not_ok(addr,size) == 0) #define access_ok(type, addr, size) (__range_not_ok(addr,size) == 0)
extern inline int verify_area(int type, const void * addr, unsigned long size) extern inline int verify_area(int type, const void __user * addr, unsigned long size)
{ {
return access_ok(type,addr,size) ? 0 : -EFAULT; return access_ok(type,addr,size) ? 0 : -EFAULT;
} }
...@@ -103,6 +114,7 @@ extern void __get_user_8(void); ...@@ -103,6 +114,7 @@ extern void __get_user_8(void);
#define get_user(x,ptr) \ #define get_user(x,ptr) \
({ long __val_gu; \ ({ long __val_gu; \
int __ret_gu; \ int __ret_gu; \
CHECK_UPTR(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; \
...@@ -138,6 +150,7 @@ extern void __put_user_bad(void); ...@@ -138,6 +150,7 @@ extern void __put_user_bad(void);
#define __put_user_nocheck(x,ptr,size) \ #define __put_user_nocheck(x,ptr,size) \
({ \ ({ \
int __pu_err; \ int __pu_err; \
CHECK_UPTR(ptr); \
__put_user_size((x),(ptr),(size),__pu_err); \ __put_user_size((x),(ptr),(size),__pu_err); \
__pu_err; \ __pu_err; \
}) })
...@@ -193,6 +206,7 @@ struct __large_struct { unsigned long buf[100]; }; ...@@ -193,6 +206,7 @@ struct __large_struct { unsigned long buf[100]; };
({ \ ({ \
int __gu_err; \ int __gu_err; \
long __gu_val; \ long __gu_val; \
CHECK_UPTR(ptr); \
__get_user_size(__gu_val,(ptr),(size),__gu_err); \ __get_user_size(__gu_val,(ptr),(size),__gu_err); \
(x) = (__typeof__(*(ptr)))__gu_val; \ (x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \ __gu_err; \
...@@ -235,15 +249,15 @@ do { \ ...@@ -235,15 +249,15 @@ do { \
/* Handles exceptions in both to and from, but doesn't do access_ok */ /* Handles exceptions in both to and from, but doesn't do access_ok */
extern unsigned long copy_user_generic(void *to, const void *from, unsigned len); extern unsigned long copy_user_generic(void *to, const void *from, unsigned len);
extern unsigned long copy_to_user(void *to, const void *from, unsigned len); extern unsigned long copy_to_user(void __user *to, const void *from, unsigned len);
extern unsigned long copy_from_user(void *to, const void *from, unsigned len); extern unsigned long copy_from_user(void *to, const void __user *from, unsigned len);
extern unsigned long copy_in_user(void *to, const void *from, unsigned len); extern unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len);
static inline int __copy_from_user(void *dst, const void *src, unsigned size) static inline int __copy_from_user(void *dst, const void __user *src, unsigned size)
{ {
int ret = 0; int ret = 0;
if (!__builtin_constant_p(size)) if (!__builtin_constant_p(size))
return copy_user_generic(dst,src,size); return copy_user_generic(dst,(void *)src,size);
switch (size) { switch (size) {
case 1:__get_user_asm(*(u8*)dst,(u8 *)src,ret,"b","b","=q",1); case 1:__get_user_asm(*(u8*)dst,(u8 *)src,ret,"b","b","=q",1);
return ret; return ret;
...@@ -264,15 +278,15 @@ static inline int __copy_from_user(void *dst, const void *src, unsigned size) ...@@ -264,15 +278,15 @@ static inline int __copy_from_user(void *dst, const void *src, unsigned size)
__get_user_asm(*(u64*)(8+(char*)dst),(u64*)(8+(char*)src),ret,"q","","=r",8); __get_user_asm(*(u64*)(8+(char*)dst),(u64*)(8+(char*)src),ret,"q","","=r",8);
return ret; return ret;
default: default:
return copy_user_generic(dst,src,size); return copy_user_generic(dst,(void *)src,size);
} }
} }
static inline int __copy_to_user(void *dst, const void *src, unsigned size) static inline int __copy_to_user(void __user *dst, const void *src, unsigned size)
{ {
int ret = 0; int ret = 0;
if (!__builtin_constant_p(size)) if (!__builtin_constant_p(size))
return copy_user_generic(dst,src,size); return copy_user_generic((void *)dst,src,size);
switch (size) { switch (size) {
case 1:__put_user_asm(*(u8*)src,(u8 *)dst,ret,"b","b","iq",1); case 1:__put_user_asm(*(u8*)src,(u8 *)dst,ret,"b","b","iq",1);
return ret; return ret;
...@@ -295,16 +309,16 @@ static inline int __copy_to_user(void *dst, const void *src, unsigned size) ...@@ -295,16 +309,16 @@ static inline int __copy_to_user(void *dst, const void *src, unsigned size)
__put_user_asm(1[(u64*)src],1+(u64*)dst,ret,"q","","ir",8); __put_user_asm(1[(u64*)src],1+(u64*)dst,ret,"q","","ir",8);
return ret; return ret;
default: default:
return copy_user_generic(dst,src,size); return copy_user_generic((void *)dst,src,size);
} }
} }
static inline int __copy_in_user(void *dst, const void *src, unsigned size) static inline int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
{ {
int ret = 0; int ret = 0;
if (!__builtin_constant_p(size)) if (!__builtin_constant_p(size))
return copy_user_generic(dst,src,size); return copy_user_generic((void *)dst,(void *)src,size);
switch (size) { switch (size) {
case 1: { case 1: {
u8 tmp; u8 tmp;
...@@ -336,15 +350,15 @@ static inline int __copy_in_user(void *dst, const void *src, unsigned size) ...@@ -336,15 +350,15 @@ static inline int __copy_in_user(void *dst, const void *src, unsigned size)
return ret; return ret;
} }
default: default:
return copy_user_generic(dst,src,size); return copy_user_generic((void *)dst,(void *)src,size);
} }
} }
long strncpy_from_user(char *dst, const char *src, long count); long strncpy_from_user(char *dst, const char __user *src, long count);
long __strncpy_from_user(char *dst, const char *src, long count); long __strncpy_from_user(char *dst, const char __user *src, long count);
long strnlen_user(const char *str, long n); long strnlen_user(const char __user *str, long n);
long strlen_user(const char *str); long strlen_user(const char __user *str);
unsigned long clear_user(void *mem, unsigned long len); unsigned long clear_user(void __user *mem, unsigned long len);
unsigned long __clear_user(void *mem, unsigned long len); unsigned long __clear_user(void __user *mem, unsigned long len);
#endif /* __X86_64_UACCESS_H */ #endif /* __X86_64_UACCESS_H */
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