X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=include%2Fasm-arm%2Fuaccess.h;h=5f420a0149f1d5dd133e17890d4a81ac2a8f0c74;hb=refs%2Fheads%2Fvserver;hp=d01310569c470385efc227fb4d3a275898856601;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h index d01310569..5f420a014 100644 --- a/include/asm-arm/uaccess.h +++ b/include/asm-arm/uaccess.h @@ -40,16 +40,25 @@ struct exception_table_entry extern int fixup_exception(struct pt_regs *regs); +/* + * These two are intentionally not defined anywhere - if the kernel + * code generates any references to them, that's a bug. + */ +extern int __get_user_bad(void); +extern int __put_user_bad(void); + /* * Note that this is actually 0x1,0000,0000 */ #define KERNEL_DS 0x00000000 -#define USER_DS TASK_SIZE - #define get_ds() (KERNEL_DS) + +#ifdef CONFIG_MMU + +#define USER_DS TASK_SIZE #define get_fs() (current_thread_info()->addr_limit) -static inline void set_fs (mm_segment_t fs) +static inline void set_fs(mm_segment_t fs) { current_thread_info()->addr_limit = fs; modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER); @@ -68,19 +77,13 @@ static inline void set_fs (mm_segment_t fs) /* We use 33-bit arithmetic here... */ #define __range_ok(addr,size) ({ \ unsigned long flag, sum; \ + __chk_user_ptr(addr); \ __asm__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \ : "=&r" (flag), "=&r" (sum) \ : "r" (addr), "Ir" (size), "0" (current_thread_info()->addr_limit) \ : "cc"); \ flag; }) -#define access_ok(type,addr,size) (__range_ok(addr,size) == 0) - -static inline int verify_area(int type, const void __user *addr, unsigned long size) -{ - return access_ok(type, addr, size) ? 0 : -EFAULT; -} - /* * Single-value transfer routines. They automatically use the right * size if we just have the right pointer type. Note that the functions @@ -91,54 +94,108 @@ static inline int verify_area(int type, const void __user *addr, unsigned long s * fixup code, but there are a few places where it intrudes on the * main code path. When we only write to user space, there is no * problem. - * - * The "__xxx" versions of the user access functions do not verify the - * address space - it must have been done previously with a separate - * "access_ok()" call. - * - * The "xxx_error" versions set the third argument to EFAULT if an - * error occurs, and leave it unchanged on success. Note that these - * versions are void (ie, don't return a value as such). */ - extern int __get_user_1(void *); extern int __get_user_2(void *); extern int __get_user_4(void *); -extern int __get_user_8(void *); -extern int __get_user_bad(void); -#define __get_user_x(__r1,__p,__e,__s,__i...) \ +#define __get_user_x(__r2,__p,__e,__s,__i...) \ __asm__ __volatile__ ( \ - __asmeq("%0", "r0") __asmeq("%1", "r1") \ + __asmeq("%0", "r0") __asmeq("%1", "r2") \ "bl __get_user_" #__s \ - : "=&r" (__e), "=r" (__r1) \ + : "=&r" (__e), "=r" (__r2) \ : "0" (__p) \ : __i, "cc") #define get_user(x,p) \ ({ \ - const register typeof(*(p)) *__p asm("r0") = (p); \ - register typeof(*(p)) __r1 asm("r1"); \ + const register typeof(*(p)) __user *__p asm("r0") = (p);\ + register unsigned long __r2 asm("r2"); \ register int __e asm("r0"); \ switch (sizeof(*(__p))) { \ case 1: \ - __get_user_x(__r1, __p, __e, 1, "lr"); \ + __get_user_x(__r2, __p, __e, 1, "lr"); \ break; \ case 2: \ - __get_user_x(__r1, __p, __e, 2, "r2", "lr"); \ + __get_user_x(__r2, __p, __e, 2, "r3", "lr"); \ break; \ case 4: \ - __get_user_x(__r1, __p, __e, 4, "lr"); \ + __get_user_x(__r2, __p, __e, 4, "lr"); \ break; \ - case 8: \ - __get_user_x(__r1, __p, __e, 8, "lr"); \ - break; \ default: __e = __get_user_bad(); break; \ } \ - x = __r1; \ + x = (typeof(*(p))) __r2; \ __e; \ }) +extern int __put_user_1(void *, unsigned int); +extern int __put_user_2(void *, unsigned int); +extern int __put_user_4(void *, unsigned int); +extern int __put_user_8(void *, unsigned long long); + +#define __put_user_x(__r2,__p,__e,__s) \ + __asm__ __volatile__ ( \ + __asmeq("%0", "r0") __asmeq("%2", "r2") \ + "bl __put_user_" #__s \ + : "=&r" (__e) \ + : "0" (__p), "r" (__r2) \ + : "ip", "lr", "cc") + +#define put_user(x,p) \ + ({ \ + const register typeof(*(p)) __r2 asm("r2") = (x); \ + const register typeof(*(p)) __user *__p asm("r0") = (p);\ + register int __e asm("r0"); \ + switch (sizeof(*(__p))) { \ + case 1: \ + __put_user_x(__r2, __p, __e, 1); \ + break; \ + case 2: \ + __put_user_x(__r2, __p, __e, 2); \ + break; \ + case 4: \ + __put_user_x(__r2, __p, __e, 4); \ + break; \ + case 8: \ + __put_user_x(__r2, __p, __e, 8); \ + break; \ + default: __e = __put_user_bad(); break; \ + } \ + __e; \ + }) + +#else /* CONFIG_MMU */ + +/* + * uClinux has only one addr space, so has simplified address limits. + */ +#define USER_DS KERNEL_DS + +#define segment_eq(a,b) (1) +#define __addr_ok(addr) (1) +#define __range_ok(addr,size) (0) +#define get_fs() (KERNEL_DS) + +static inline void set_fs(mm_segment_t fs) +{ +} + +#define get_user(x,p) __get_user(x,p) +#define put_user(x,p) __put_user(x,p) + +#endif /* CONFIG_MMU */ + +#define access_ok(type,addr,size) (__range_ok(addr,size) == 0) + +/* + * The "__xxx" versions of the user access functions do not verify the + * address space - it must have been done previously with a separate + * "access_ok()" call. + * + * The "xxx_error" versions set the third argument to EFAULT if an + * error occurs, and leave it unchanged on success. Note that these + * versions are void (ie, don't return a value as such). + */ #define __get_user(x,ptr) \ ({ \ long __gu_err = 0; \ @@ -156,6 +213,7 @@ extern int __get_user_bad(void); do { \ unsigned long __gu_addr = (unsigned long)(ptr); \ unsigned long __gu_val; \ + __chk_user_ptr(ptr); \ switch (sizeof(*(ptr))) { \ case 1: __get_user_asm_byte(__gu_val,__gu_addr,err); break; \ case 2: __get_user_asm_half(__gu_val,__gu_addr,err); break; \ @@ -219,43 +277,6 @@ do { \ : "r" (addr), "i" (-EFAULT) \ : "cc") -extern int __put_user_1(void *, unsigned int); -extern int __put_user_2(void *, unsigned int); -extern int __put_user_4(void *, unsigned int); -extern int __put_user_8(void *, unsigned long long); -extern int __put_user_bad(void); - -#define __put_user_x(__r1,__p,__e,__s) \ - __asm__ __volatile__ ( \ - __asmeq("%0", "r0") __asmeq("%2", "r1") \ - "bl __put_user_" #__s \ - : "=&r" (__e) \ - : "0" (__p), "r" (__r1) \ - : "ip", "lr", "cc") - -#define put_user(x,p) \ - ({ \ - const register typeof(*(p)) __r1 asm("r1") = (x); \ - const register typeof(*(p)) *__p asm("r0") = (p); \ - register int __e asm("r0"); \ - switch (sizeof(*(__p))) { \ - case 1: \ - __put_user_x(__r1, __p, __e, 1); \ - break; \ - case 2: \ - __put_user_x(__r1, __p, __e, 2); \ - break; \ - case 4: \ - __put_user_x(__r1, __p, __e, 4); \ - break; \ - case 8: \ - __put_user_x(__r1, __p, __e, 8); \ - break; \ - default: __e = __put_user_bad(); break; \ - } \ - __e; \ - }) - #define __put_user(x,ptr) \ ({ \ long __pu_err = 0; \ @@ -273,6 +294,7 @@ extern int __put_user_bad(void); do { \ unsigned long __pu_addr = (unsigned long)(ptr); \ __typeof__(*(ptr)) __pu_val = (x); \ + __chk_user_ptr(ptr); \ switch (sizeof(*(ptr))) { \ case 1: __put_user_asm_byte(__pu_val,__pu_addr,err); break; \ case 2: __put_user_asm_half(__pu_val,__pu_addr,err); break; \ @@ -359,71 +381,62 @@ do { \ : "r" (x), "i" (-EFAULT) \ : "cc") -extern unsigned long __arch_copy_from_user(void *to, const void __user *from, unsigned long n); -extern unsigned long __arch_copy_to_user(void __user *to, const void *from, unsigned long n); -extern unsigned long __arch_clear_user(void __user *addr, unsigned long n); -extern unsigned long __arch_strncpy_from_user(char *to, const char __user *from, unsigned long count); -extern unsigned long __arch_strnlen_user(const char __user *s, long n); -static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) +#ifdef CONFIG_MMU +extern unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n); +extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n); +extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n); +#else +#define __copy_from_user(to,from,n) (memcpy(to, (void __force *)from, n), 0) +#define __copy_to_user(to,from,n) (memcpy((void __force *)to, from, n), 0) +#define __clear_user(addr,n) (memset((void __force *)addr, 0, n), 0) +#endif + +extern unsigned long __must_check __strncpy_from_user(char *to, const char __user *from, unsigned long count); +extern unsigned long __must_check __strnlen_user(const char __user *s, long n); + +static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { if (access_ok(VERIFY_READ, from, n)) - n = __arch_copy_from_user(to, from, n); + n = __copy_from_user(to, from, n); else /* security hole - plug it */ memzero(to, n); return n; } -static inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n) -{ - return __arch_copy_from_user(to, from, n); -} - -static inline unsigned long copy_to_user(void __user *to, const void *from, unsigned long n) +static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) - n = __arch_copy_to_user(to, from, n); + n = __copy_to_user(to, from, n); return n; } -static inline unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n) -{ - return __arch_copy_to_user(to, from, n); -} +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user -static inline unsigned long clear_user (void __user *to, unsigned long n) +static inline unsigned long __must_check clear_user(void __user *to, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) - n = __arch_clear_user(to, n); + n = __clear_user(to, n); return n; } -static inline unsigned long __clear_user (void __user *to, unsigned long n) -{ - return __arch_clear_user(to, n); -} - -static inline long strncpy_from_user (char *dst, const char __user *src, long count) +static inline long __must_check strncpy_from_user(char *dst, const char __user *src, long count) { long res = -EFAULT; if (access_ok(VERIFY_READ, src, 1)) - res = __arch_strncpy_from_user(dst, src, count); + res = __strncpy_from_user(dst, src, count); return res; } -static inline long __strncpy_from_user (char *dst, const char __user *src, long count) -{ - return __arch_strncpy_from_user(dst, src, count); -} - #define strlen_user(s) strnlen_user(s, ~0UL >> 1) -static inline long strnlen_user(const char __user *s, long n) +static inline long __must_check strnlen_user(const char __user *s, long n) { unsigned long res = 0; if (__addr_ok(s)) - res = __arch_strnlen_user(s, n); + res = __strnlen_user(s, n); return res; }