diff options
Diffstat (limited to 'include/asm-generic/uaccess.h')
-rw-r--r-- | include/asm-generic/uaccess.h | 192 |
1 files changed, 72 insertions, 120 deletions
diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h index ba68ee4dabfa..b276f783494c 100644 --- a/include/asm-generic/uaccess.h +++ b/include/asm-generic/uaccess.h @@ -8,100 +8,92 @@ * address space, e.g. all NOMMU machines. */ #include <linux/string.h> +#include <asm-generic/access_ok.h> #ifdef CONFIG_UACCESS_MEMCPY -static inline __must_check unsigned long -raw_copy_from_user(void *to, const void __user * from, unsigned long n) +#include <linux/unaligned.h> + +static __always_inline int +__get_user_fn(size_t size, const void __user *from, void *to) { - if (__builtin_constant_p(n)) { - switch(n) { - case 1: - *(u8 *)to = *(u8 __force *)from; - return 0; - case 2: - *(u16 *)to = *(u16 __force *)from; - return 0; - case 4: - *(u32 *)to = *(u32 __force *)from; - return 0; -#ifdef CONFIG_64BIT - case 8: - *(u64 *)to = *(u64 __force *)from; - return 0; -#endif - } + BUILD_BUG_ON(!__builtin_constant_p(size)); + + switch (size) { + case 1: + *(u8 *)to = *((u8 __force *)from); + return 0; + case 2: + *(u16 *)to = get_unaligned((u16 __force *)from); + return 0; + case 4: + *(u32 *)to = get_unaligned((u32 __force *)from); + return 0; + case 8: + *(u64 *)to = get_unaligned((u64 __force *)from); + return 0; + default: + BUILD_BUG(); + return 0; } - memcpy(to, (const void __force *)from, n); - return 0; } +#define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) -static inline __must_check unsigned long -raw_copy_to_user(void __user *to, const void *from, unsigned long n) +static __always_inline int +__put_user_fn(size_t size, void __user *to, void *from) { - if (__builtin_constant_p(n)) { - switch(n) { - case 1: - *(u8 __force *)to = *(u8 *)from; - return 0; - case 2: - *(u16 __force *)to = *(u16 *)from; - return 0; - case 4: - *(u32 __force *)to = *(u32 *)from; - return 0; -#ifdef CONFIG_64BIT - case 8: - *(u64 __force *)to = *(u64 *)from; - return 0; -#endif - default: - break; - } - } + BUILD_BUG_ON(!__builtin_constant_p(size)); - memcpy((void __force *)to, from, n); - return 0; + switch (size) { + case 1: + *(u8 __force *)to = *(u8 *)from; + return 0; + case 2: + put_unaligned(*(u16 *)from, (u16 __force *)to); + return 0; + case 4: + put_unaligned(*(u32 *)from, (u32 __force *)to); + return 0; + case 8: + put_unaligned(*(u64 *)from, (u64 __force *)to); + return 0; + default: + BUILD_BUG(); + return 0; + } } -#define INLINE_COPY_FROM_USER -#define INLINE_COPY_TO_USER -#endif /* CONFIG_UACCESS_MEMCPY */ +#define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) -#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) +#define __get_kernel_nofault(dst, src, type, err_label) \ +do { \ + *((type *)dst) = get_unaligned((type *)(src)); \ + if (0) /* make sure the label looks used to the compiler */ \ + goto err_label; \ +} while (0) -#ifndef KERNEL_DS -#define KERNEL_DS MAKE_MM_SEG(~0UL) -#endif - -#ifndef USER_DS -#define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) -#endif +#define __put_kernel_nofault(dst, src, type, err_label) \ +do { \ + put_unaligned(*((type *)src), (type *)(dst)); \ + if (0) /* make sure the label looks used to the compiler */ \ + goto err_label; \ +} while (0) -#ifndef get_fs -#define get_fs() (current_thread_info()->addr_limit) - -static inline void set_fs(mm_segment_t fs) +static inline __must_check unsigned long +raw_copy_from_user(void *to, const void __user * from, unsigned long n) { - current_thread_info()->addr_limit = fs; + memcpy(to, (const void __force *)from, n); + return 0; } -#endif - -#ifndef uaccess_kernel -#define uaccess_kernel() (get_fs().seg == KERNEL_DS.seg) -#endif - -#define access_ok(addr, size) __access_ok((unsigned long)(addr),(size)) -/* - * The architecture should really override this if possible, at least - * doing a check on the get_fs() - */ -#ifndef __access_ok -static inline int __access_ok(unsigned long addr, unsigned long size) +static inline __must_check unsigned long +raw_copy_to_user(void __user *to, const void *from, unsigned long n) { - return 1; + memcpy((void __force *)to, from, n); + return 0; } -#endif +#define INLINE_COPY_FROM_USER +#define INLINE_COPY_TO_USER +#endif /* CONFIG_UACCESS_MEMCPY */ /* * These are the main single-value transfer routines. They automatically @@ -213,50 +205,6 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) extern int __get_user_bad(void) __attribute__((noreturn)); /* - * Copy a null terminated string from userspace. - */ -#ifndef __strncpy_from_user -static inline long -__strncpy_from_user(char *dst, const char __user *src, long count) -{ - char *tmp; - strncpy(dst, (const char __force *)src, count); - for (tmp = dst; *tmp && count > 0; tmp++, count--) - ; - return (tmp - dst); -} -#endif - -static inline long -strncpy_from_user(char *dst, const char __user *src, long count) -{ - if (!access_ok(src, 1)) - return -EFAULT; - return __strncpy_from_user(dst, src, count); -} - -/* - * Return the size of a string (including the ending 0) - * - * Return 0 on exception, a value greater than N if too long - */ -#ifndef __strnlen_user -#define __strnlen_user(s, n) (strnlen((s), (n)) + 1) -#endif - -/* - * Unlike strnlen, strnlen_user includes the nul terminator in - * its returned count. Callers should check for a returned value - * greater than N as an indication the string is too long. - */ -static inline long strnlen_user(const char __user *src, long n) -{ - if (!access_ok(src, 1)) - return 0; - return __strnlen_user(src, n); -} - -/* * Zero Userspace */ #ifndef __clear_user @@ -280,4 +228,8 @@ clear_user(void __user *to, unsigned long n) #include <asm/extable.h> +__must_check long strncpy_from_user(char *dst, const char __user *src, + long count); +__must_check long strnlen_user(const char __user *src, long n); + #endif /* __ASM_GENERIC_UACCESS_H */ |