diff options
-rw-r--r-- | arch/sparc/Kconfig.debug | 14 | ||||
-rw-r--r-- | arch/sparc/include/asm/uaccess_32.h | 15 | ||||
-rw-r--r-- | arch/sparc/include/asm/uaccess_64.h | 23 | ||||
-rw-r--r-- | arch/sparc/lib/Makefile | 1 | ||||
-rw-r--r-- | arch/sparc/lib/usercopy.c | 8 |
5 files changed, 57 insertions, 4 deletions
diff --git a/arch/sparc/Kconfig.debug b/arch/sparc/Kconfig.debug index 90d5fe223a74..9d3c889718ac 100644 --- a/arch/sparc/Kconfig.debug +++ b/arch/sparc/Kconfig.debug | |||
@@ -33,4 +33,18 @@ config FRAME_POINTER | |||
33 | depends on MCOUNT | 33 | depends on MCOUNT |
34 | default y | 34 | default y |
35 | 35 | ||
36 | config DEBUG_STRICT_USER_COPY_CHECKS | ||
37 | bool "Strict copy size checks" | ||
38 | depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING | ||
39 | ---help--- | ||
40 | Enabling this option turns a certain set of sanity checks for user | ||
41 | copy operations into compile time failures. | ||
42 | |||
43 | The copy_from_user() etc checks are there to help test if there | ||
44 | are sufficient security checks on the length argument of | ||
45 | the copy operation, by having gcc prove that the argument is | ||
46 | within bounds. | ||
47 | |||
48 | If unsure, or if you run an older (pre 4.4) gcc, say N. | ||
49 | |||
36 | endmenu | 50 | endmenu |
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 |
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index e75faf0e59ae..c4b5e03af115 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile | |||
@@ -44,3 +44,4 @@ obj-y += iomap.o | |||
44 | obj-$(CONFIG_SPARC32) += atomic32.o | 44 | obj-$(CONFIG_SPARC32) += atomic32.o |
45 | obj-y += ksyms.o | 45 | obj-y += ksyms.o |
46 | obj-$(CONFIG_SPARC64) += PeeCeeI.o | 46 | obj-$(CONFIG_SPARC64) += PeeCeeI.o |
47 | obj-y += usercopy.o | ||
diff --git a/arch/sparc/lib/usercopy.c b/arch/sparc/lib/usercopy.c new file mode 100644 index 000000000000..14b363fec8a2 --- /dev/null +++ b/arch/sparc/lib/usercopy.c | |||
@@ -0,0 +1,8 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/bug.h> | ||
3 | |||
4 | void copy_from_user_overflow(void) | ||
5 | { | ||
6 | WARN(1, "Buffer overflow detected!\n"); | ||
7 | } | ||
8 | EXPORT_SYMBOL(copy_from_user_overflow); | ||