diff options
| author | David S. Miller <davem@davemloft.net> | 2009-12-11 02:05:23 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-12-11 02:05:23 -0500 |
| commit | fb34035e7b4bb3edc7c2dc0683cfe21f57a9574d (patch) | |
| tree | ddde17e5690d77f4f61c6271fc8b6f520c746851 /arch/sparc/include | |
| parent | 4ed5d5e4299f42438dd5ac6dcb1f2168ea4fb02a (diff) | |
sparc: Use __builtin_object_size() to validate the buffer size for copy_from_user()
This mirrors x86 commit 9f0cf4adb6aa0bfccf675c938124e68f7f06349d
(x86: Use __builtin_object_size() to validate the buffer size for copy_from_user())
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/include')
| -rw-r--r-- | arch/sparc/include/asm/uaccess_32.h | 15 | ||||
| -rw-r--r-- | arch/sparc/include/asm/uaccess_64.h | 23 |
2 files changed, 34 insertions, 4 deletions
diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h index 8303ac481034..489d2ba92bcb 100644 --- a/arch/sparc/include/asm/uaccess_32.h +++ b/arch/sparc/include/asm/uaccess_32.h | |||
| @@ -260,8 +260,23 @@ static inline unsigned long __copy_to_user(void __user *to, const void *from, un | |||
| 260 | return __copy_user(to, (__force void __user *) from, n); | 260 | return __copy_user(to, (__force void __user *) from, n); |
| 261 | } | 261 | } |
| 262 | 262 | ||
| 263 | extern void copy_from_user_overflow(void) | ||
| 264 | #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS | ||
| 265 | __compiletime_error("copy_from_user() buffer size is not provably correct") | ||
| 266 | #else | ||
| 267 | __compiletime_warning("copy_from_user() buffer size is not provably correct") | ||
| 268 | #endif | ||
| 269 | ; | ||
| 270 | |||
| 263 | static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) | 271 | static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) |
| 264 | { | 272 | { |
| 273 | int sz = __compiletime_object_size(to); | ||
| 274 | |||
| 275 | if (unlikely(sz != -1 && sz < n)) { | ||
| 276 | copy_from_user_overflow(); | ||
| 277 | return -EFAULT; | ||
| 278 | } | ||
| 279 | |||
| 265 | if (n && __access_ok((unsigned long) from, n)) | 280 | if (n && __access_ok((unsigned long) from, n)) |
| 266 | return __copy_user((__force void __user *) to, from, n); | 281 | return __copy_user((__force void __user *) to, from, n); |
| 267 | else | 282 | else |
diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h index 9ea271e19c70..dbc141660994 100644 --- a/arch/sparc/include/asm/uaccess_64.h +++ b/arch/sparc/include/asm/uaccess_64.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #ifdef __KERNEL__ | 8 | #ifdef __KERNEL__ |
| 9 | #include <linux/errno.h> | ||
| 9 | #include <linux/compiler.h> | 10 | #include <linux/compiler.h> |
| 10 | #include <linux/string.h> | 11 | #include <linux/string.h> |
| 11 | #include <linux/thread_info.h> | 12 | #include <linux/thread_info.h> |
| @@ -204,6 +205,14 @@ __asm__ __volatile__( \ | |||
| 204 | 205 | ||
| 205 | extern int __get_user_bad(void); | 206 | extern int __get_user_bad(void); |
| 206 | 207 | ||
| 208 | extern void copy_from_user_overflow(void) | ||
| 209 | #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS | ||
| 210 | __compiletime_error("copy_from_user() buffer size is not provably correct") | ||
| 211 | #else | ||
| 212 | __compiletime_warning("copy_from_user() buffer size is not provably correct") | ||
| 213 | #endif | ||
| 214 | ; | ||
| 215 | |||
| 207 | extern unsigned long __must_check ___copy_from_user(void *to, | 216 | extern unsigned long __must_check ___copy_from_user(void *to, |
| 208 | const void __user *from, | 217 | const void __user *from, |
| 209 | unsigned long size); | 218 | unsigned long size); |
| @@ -212,10 +221,16 @@ extern unsigned long copy_from_user_fixup(void *to, const void __user *from, | |||
| 212 | static inline unsigned long __must_check | 221 | static inline unsigned long __must_check |
| 213 | copy_from_user(void *to, const void __user *from, unsigned long size) | 222 | copy_from_user(void *to, const void __user *from, unsigned long size) |
| 214 | { | 223 | { |
| 215 | unsigned long ret = ___copy_from_user(to, from, size); | 224 | unsigned long ret = (unsigned long) -EFAULT; |
| 216 | 225 | int sz = __compiletime_object_size(to); | |
| 217 | if (unlikely(ret)) | 226 | |
| 218 | ret = copy_from_user_fixup(to, from, size); | 227 | if (likely(sz == -1 || sz >= size)) { |
| 228 | ret = ___copy_from_user(to, from, size); | ||
| 229 | if (unlikely(ret)) | ||
| 230 | ret = copy_from_user_fixup(to, from, size); | ||
| 231 | } else { | ||
| 232 | copy_from_user_overflow(); | ||
| 233 | } | ||
| 219 | return ret; | 234 | return ret; |
| 220 | } | 235 | } |
| 221 | #define __copy_from_user copy_from_user | 236 | #define __copy_from_user copy_from_user |
