diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-26 14:09:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-26 14:33:54 -0400 |
commit | 5723aa993d83803157c22327e90cd59e3dcbe879 (patch) | |
tree | 9b5cd120395a44bd59ce74552f33d372617a47b0 | |
parent | a08c5356a3aaf638c41897ae4169de18db89595e (diff) |
x86: use the new generic strnlen_user() function
This throws away the old x86-specific functions in favor of the generic
optimized version.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/x86/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/uaccess.h | 3 | ||||
-rw-r--r-- | arch/x86/include/asm/uaccess_32.h | 17 | ||||
-rw-r--r-- | arch/x86/include/asm/uaccess_64.h | 3 | ||||
-rw-r--r-- | arch/x86/lib/usercopy_32.c | 41 | ||||
-rw-r--r-- | arch/x86/lib/usercopy_64.c | 48 |
6 files changed, 4 insertions, 109 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 3220d44e24d0..d700811785ea 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -94,6 +94,7 @@ config X86 | |||
94 | select GENERIC_TIME_VSYSCALL if X86_64 | 94 | select GENERIC_TIME_VSYSCALL if X86_64 |
95 | select KTIME_SCALAR if X86_32 | 95 | select KTIME_SCALAR if X86_32 |
96 | select GENERIC_STRNCPY_FROM_USER | 96 | select GENERIC_STRNCPY_FROM_USER |
97 | select GENERIC_STRNLEN_USER | ||
97 | 98 | ||
98 | config INSTRUCTION_DECODER | 99 | config INSTRUCTION_DECODER |
99 | def_bool (KPROBES || PERF_EVENTS || UPROBES) | 100 | def_bool (KPROBES || PERF_EVENTS || UPROBES) |
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 1354facd8f63..04cd6882308e 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h | |||
@@ -566,6 +566,9 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n); | |||
566 | extern __must_check long | 566 | extern __must_check long |
567 | strncpy_from_user(char *dst, const char __user *src, long count); | 567 | strncpy_from_user(char *dst, const char __user *src, long count); |
568 | 568 | ||
569 | extern __must_check long strlen_user(const char __user *str); | ||
570 | extern __must_check long strnlen_user(const char __user *str, long n); | ||
571 | |||
569 | /* | 572 | /* |
570 | * movsl can be slow when source and dest are not both 8-byte aligned | 573 | * movsl can be slow when source and dest are not both 8-byte aligned |
571 | */ | 574 | */ |
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h index 8084bc73b18c..576e39bca6ad 100644 --- a/arch/x86/include/asm/uaccess_32.h +++ b/arch/x86/include/asm/uaccess_32.h | |||
@@ -213,23 +213,6 @@ static inline unsigned long __must_check copy_from_user(void *to, | |||
213 | return n; | 213 | return n; |
214 | } | 214 | } |
215 | 215 | ||
216 | /** | ||
217 | * strlen_user: - Get the size of a string in user space. | ||
218 | * @str: The string to measure. | ||
219 | * | ||
220 | * Context: User context only. This function may sleep. | ||
221 | * | ||
222 | * Get the size of a NUL-terminated string in user space. | ||
223 | * | ||
224 | * Returns the size of the string INCLUDING the terminating NUL. | ||
225 | * On exception, returns 0. | ||
226 | * | ||
227 | * If there is a limit on the length of a valid string, you may wish to | ||
228 | * consider using strnlen_user() instead. | ||
229 | */ | ||
230 | #define strlen_user(str) strnlen_user(str, LONG_MAX) | ||
231 | |||
232 | long strnlen_user(const char __user *str, long n); | ||
233 | unsigned long __must_check clear_user(void __user *mem, unsigned long len); | 216 | unsigned long __must_check clear_user(void __user *mem, unsigned long len); |
234 | unsigned long __must_check __clear_user(void __user *mem, unsigned long len); | 217 | unsigned long __must_check __clear_user(void __user *mem, unsigned long len); |
235 | 218 | ||
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index fcd4b6f3ef02..8e796fbbf9c6 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h | |||
@@ -208,9 +208,6 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size) | |||
208 | } | 208 | } |
209 | } | 209 | } |
210 | 210 | ||
211 | __must_check long strnlen_user(const char __user *str, long n); | ||
212 | __must_check long __strnlen_user(const char __user *str, long n); | ||
213 | __must_check long strlen_user(const char __user *str); | ||
214 | __must_check unsigned long clear_user(void __user *mem, unsigned long len); | 211 | __must_check unsigned long clear_user(void __user *mem, unsigned long len); |
215 | __must_check unsigned long __clear_user(void __user *mem, unsigned long len); | 212 | __must_check unsigned long __clear_user(void __user *mem, unsigned long len); |
216 | 213 | ||
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c index 883b216c60b2..1781b2f950e2 100644 --- a/arch/x86/lib/usercopy_32.c +++ b/arch/x86/lib/usercopy_32.c | |||
@@ -95,47 +95,6 @@ __clear_user(void __user *to, unsigned long n) | |||
95 | } | 95 | } |
96 | EXPORT_SYMBOL(__clear_user); | 96 | EXPORT_SYMBOL(__clear_user); |
97 | 97 | ||
98 | /** | ||
99 | * strnlen_user: - Get the size of a string in user space. | ||
100 | * @s: The string to measure. | ||
101 | * @n: The maximum valid length | ||
102 | * | ||
103 | * Get the size of a NUL-terminated string in user space. | ||
104 | * | ||
105 | * Returns the size of the string INCLUDING the terminating NUL. | ||
106 | * On exception, returns 0. | ||
107 | * If the string is too long, returns a value greater than @n. | ||
108 | */ | ||
109 | long strnlen_user(const char __user *s, long n) | ||
110 | { | ||
111 | unsigned long mask = -__addr_ok(s); | ||
112 | unsigned long res, tmp; | ||
113 | |||
114 | might_fault(); | ||
115 | |||
116 | __asm__ __volatile__( | ||
117 | " testl %0, %0\n" | ||
118 | " jz 3f\n" | ||
119 | " andl %0,%%ecx\n" | ||
120 | "0: repne; scasb\n" | ||
121 | " setne %%al\n" | ||
122 | " subl %%ecx,%0\n" | ||
123 | " addl %0,%%eax\n" | ||
124 | "1:\n" | ||
125 | ".section .fixup,\"ax\"\n" | ||
126 | "2: xorl %%eax,%%eax\n" | ||
127 | " jmp 1b\n" | ||
128 | "3: movb $1,%%al\n" | ||
129 | " jmp 1b\n" | ||
130 | ".previous\n" | ||
131 | _ASM_EXTABLE(0b,2b) | ||
132 | :"=&r" (n), "=&D" (s), "=&a" (res), "=&c" (tmp) | ||
133 | :"0" (n), "1" (s), "2" (0), "3" (mask) | ||
134 | :"cc"); | ||
135 | return res & mask; | ||
136 | } | ||
137 | EXPORT_SYMBOL(strnlen_user); | ||
138 | |||
139 | #ifdef CONFIG_X86_INTEL_USERCOPY | 98 | #ifdef CONFIG_X86_INTEL_USERCOPY |
140 | static unsigned long | 99 | static unsigned long |
141 | __copy_user_intel(void __user *to, const void *from, unsigned long size) | 100 | __copy_user_intel(void __user *to, const void *from, unsigned long size) |
diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index 0d0326f388c0..e5b130bc2d0e 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c | |||
@@ -52,54 +52,6 @@ unsigned long clear_user(void __user *to, unsigned long n) | |||
52 | } | 52 | } |
53 | EXPORT_SYMBOL(clear_user); | 53 | EXPORT_SYMBOL(clear_user); |
54 | 54 | ||
55 | /* | ||
56 | * Return the size of a string (including the ending 0) | ||
57 | * | ||
58 | * Return 0 on exception, a value greater than N if too long | ||
59 | */ | ||
60 | |||
61 | long __strnlen_user(const char __user *s, long n) | ||
62 | { | ||
63 | long res = 0; | ||
64 | char c; | ||
65 | |||
66 | while (1) { | ||
67 | if (res>n) | ||
68 | return n+1; | ||
69 | if (__get_user(c, s)) | ||
70 | return 0; | ||
71 | if (!c) | ||
72 | return res+1; | ||
73 | res++; | ||
74 | s++; | ||
75 | } | ||
76 | } | ||
77 | EXPORT_SYMBOL(__strnlen_user); | ||
78 | |||
79 | long strnlen_user(const char __user *s, long n) | ||
80 | { | ||
81 | if (!access_ok(VERIFY_READ, s, 1)) | ||
82 | return 0; | ||
83 | return __strnlen_user(s, n); | ||
84 | } | ||
85 | EXPORT_SYMBOL(strnlen_user); | ||
86 | |||
87 | long strlen_user(const char __user *s) | ||
88 | { | ||
89 | long res = 0; | ||
90 | char c; | ||
91 | |||
92 | for (;;) { | ||
93 | if (get_user(c, s)) | ||
94 | return 0; | ||
95 | if (!c) | ||
96 | return res+1; | ||
97 | res++; | ||
98 | s++; | ||
99 | } | ||
100 | } | ||
101 | EXPORT_SYMBOL(strlen_user); | ||
102 | |||
103 | unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len) | 55 | unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len) |
104 | { | 56 | { |
105 | if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { | 57 | if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { |