Commit 888c31fc83ddc7fcd9947cb67c5718b4e3dd5e1b
Committed by
Kyle McMartin
1 parent
a3bee03e71
Exists in
master
and in
7 other branches
parisc: add strict copy size checks (v2)
Add CONFIG_DEBUG_STRICT_USER_COPY_CHECKS, copied from the x86 implementation. Tested with 32 and 64bit kernel. Signed-off-by: Helge Deller <deller@gmx.de> Signed-off-by: Kyle McMartin <kyle@mcmartin.ca>
Showing 3 changed files with 41 additions and 3 deletions Side-by-side Diff
arch/parisc/Kconfig.debug
... | ... | @@ -12,5 +12,19 @@ |
12 | 12 | portion of the kernel code won't be covered by a TLB anymore. |
13 | 13 | If in doubt, say "N". |
14 | 14 | |
15 | +config DEBUG_STRICT_USER_COPY_CHECKS | |
16 | + bool "Strict copy size checks" | |
17 | + depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING | |
18 | + ---help--- | |
19 | + Enabling this option turns a certain set of sanity checks for user | |
20 | + copy operations into compile time failures. | |
21 | + | |
22 | + The copy_from_user() etc checks are there to help test if there | |
23 | + are sufficient security checks on the length argument of | |
24 | + the copy operation, by having gcc prove that the argument is | |
25 | + within bounds. | |
26 | + | |
27 | + If unsure, or if you run an older (pre 4.4) gcc, say N. | |
28 | + | |
15 | 29 | endmenu |
arch/parisc/include/asm/uaccess.h
... | ... | @@ -7,6 +7,7 @@ |
7 | 7 | #include <asm/page.h> |
8 | 8 | #include <asm/system.h> |
9 | 9 | #include <asm/cache.h> |
10 | +#include <asm/errno.h> | |
10 | 11 | #include <asm-generic/uaccess-unaligned.h> |
11 | 12 | |
12 | 13 | #define VERIFY_READ 0 |
13 | 14 | |
... | ... | @@ -234,12 +235,34 @@ |
234 | 235 | |
235 | 236 | unsigned long copy_to_user(void __user *dst, const void *src, unsigned long len); |
236 | 237 | #define __copy_to_user copy_to_user |
237 | -unsigned long copy_from_user(void *dst, const void __user *src, unsigned long len); | |
238 | -#define __copy_from_user copy_from_user | |
238 | +unsigned long __copy_from_user(void *dst, const void __user *src, unsigned long len); | |
239 | 239 | unsigned long copy_in_user(void __user *dst, const void __user *src, unsigned long len); |
240 | 240 | #define __copy_in_user copy_in_user |
241 | 241 | #define __copy_to_user_inatomic __copy_to_user |
242 | 242 | #define __copy_from_user_inatomic __copy_from_user |
243 | + | |
244 | +extern void copy_from_user_overflow(void) | |
245 | +#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS | |
246 | + __compiletime_error("copy_from_user() buffer size is not provably correct") | |
247 | +#else | |
248 | + __compiletime_warning("copy_from_user() buffer size is not provably correct") | |
249 | +#endif | |
250 | +; | |
251 | + | |
252 | +static inline unsigned long __must_check copy_from_user(void *to, | |
253 | + const void __user *from, | |
254 | + unsigned long n) | |
255 | +{ | |
256 | + int sz = __compiletime_object_size(to); | |
257 | + int ret = -EFAULT; | |
258 | + | |
259 | + if (likely(sz == -1 || !__builtin_constant_p(n) || sz >= n)) | |
260 | + ret = __copy_from_user(to, from, n); | |
261 | + else | |
262 | + copy_from_user_overflow(); | |
263 | + | |
264 | + return ret; | |
265 | +} | |
243 | 266 | |
244 | 267 | struct pt_regs; |
245 | 268 | int fixup_exception(struct pt_regs *regs); |
arch/parisc/lib/memcpy.c
... | ... | @@ -475,7 +475,8 @@ |
475 | 475 | return pa_memcpy((void __force *)dst, src, len); |
476 | 476 | } |
477 | 477 | |
478 | -unsigned long copy_from_user(void *dst, const void __user *src, unsigned long len) | |
478 | +EXPORT_SYMBOL(__copy_from_user); | |
479 | +unsigned long __copy_from_user(void *dst, const void __user *src, unsigned long len) | |
479 | 480 | { |
480 | 481 | mtsp(get_user_space(), 1); |
481 | 482 | mtsp(get_kernel_space(), 2); |