Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm/usercopy: get rid of CONFIG_DEBUG_STRICT_USER_COPY_CHECKS

There are three usercopy warnings which are currently being silenced for
gcc 4.6 and newer:

1) "copy_from_user() buffer size is too small" compile warning/error

This is a static warning which happens when object size and copy size
are both const, and copy size > object size. I didn't see any false
positives for this one. So the function warning attribute seems to
be working fine here.

Note this scenario is always a bug and so I think it should be
changed to *always* be an error, regardless of
CONFIG_DEBUG_STRICT_USER_COPY_CHECKS.

2) "copy_from_user() buffer size is not provably correct" compile warning

This is another static warning which happens when I enable
__compiletime_object_size() for new compilers (and
CONFIG_DEBUG_STRICT_USER_COPY_CHECKS). It happens when object size
is const, but copy size is *not*. In this case there's no way to
compare the two at build time, so it gives the warning. (Note the
warning is a byproduct of the fact that gcc has no way of knowing
whether the overflow function will be called, so the call isn't dead
code and the warning attribute is activated.)

So this warning seems to only indicate "this is an unusual pattern,
maybe you should check it out" rather than "this is a bug".

I get 102(!) of these warnings with allyesconfig and the
__compiletime_object_size() gcc check removed. I don't know if there
are any real bugs hiding in there, but from looking at a small
sample, I didn't see any. According to Kees, it does sometimes find
real bugs. But the false positive rate seems high.

3) "Buffer overflow detected" runtime warning

This is a runtime warning where object size is const, and copy size >
object size.

All three warnings (both static and runtime) were completely disabled
for gcc 4.6 with the following commit:

2fb0815c9ee6 ("gcc4: disable __compiletime_object_size for GCC 4.6+")

That commit mistakenly assumed that the false positives were caused by a
gcc bug in __compiletime_object_size(). But in fact,
__compiletime_object_size() seems to be working fine. The false
positives were instead triggered by #2 above. (Though I don't have an
explanation for why the warnings supposedly only started showing up in
gcc 4.6.)

So remove warning #2 to get rid of all the false positives, and re-enable
warnings #1 and #3 by reverting the above commit.

Furthermore, since #1 is a real bug which is detected at compile time,
upgrade it to always be an error.

Having done all that, CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is no longer
needed.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: "H . Peter Anvin" <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Byungchul Park <byungchul.park@lge.com>
Cc: Nilay Vaish <nilayvaish@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Josh Poimboeuf and committed by
Linus Torvalds
0d025d27 d8dc020c

+45 -128
-1
arch/parisc/Kconfig
··· 1 1 config PARISC 2 2 def_bool y 3 - select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS 4 3 select ARCH_MIGHT_HAVE_PC_PARPORT 5 4 select HAVE_IDE 6 5 select HAVE_OPROFILE
-1
arch/parisc/configs/c8000_defconfig
··· 245 245 CONFIG_PROVE_RCU_DELAY=y 246 246 CONFIG_DEBUG_BLOCK_EXT_DEVT=y 247 247 CONFIG_LATENCYTOP=y 248 - CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y 249 248 CONFIG_KEYS=y 250 249 # CONFIG_CRYPTO_HW is not set 251 250 CONFIG_FONTS=y
-1
arch/parisc/configs/generic-64bit_defconfig
··· 291 291 CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y 292 292 # CONFIG_SCHED_DEBUG is not set 293 293 CONFIG_TIMER_STATS=y 294 - CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y 295 294 CONFIG_CRYPTO_MANAGER=y 296 295 CONFIG_CRYPTO_ECB=m 297 296 CONFIG_CRYPTO_PCBC=m
+12 -10
arch/parisc/include/asm/uaccess.h
··· 208 208 #define __copy_to_user_inatomic __copy_to_user 209 209 #define __copy_from_user_inatomic __copy_from_user 210 210 211 - extern void copy_from_user_overflow(void) 212 - #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS 213 - __compiletime_error("copy_from_user() buffer size is not provably correct") 214 - #else 215 - __compiletime_warning("copy_from_user() buffer size is not provably correct") 216 - #endif 217 - ; 211 + extern void __compiletime_error("usercopy buffer size is too small") 212 + __bad_copy_user(void); 213 + 214 + static inline void copy_user_overflow(int size, unsigned long count) 215 + { 216 + WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count); 217 + } 218 218 219 219 static inline unsigned long __must_check copy_from_user(void *to, 220 220 const void __user *from, ··· 223 223 int sz = __compiletime_object_size(to); 224 224 int ret = -EFAULT; 225 225 226 - if (likely(sz == -1 || !__builtin_constant_p(n) || sz >= n)) 226 + if (likely(sz == -1 || sz >= n)) 227 227 ret = __copy_from_user(to, from, n); 228 - else 229 - copy_from_user_overflow(); 228 + else if (!__builtin_constant_p(n)) 229 + copy_user_overflow(sz, n); 230 + else 231 + __bad_copy_user(); 230 232 231 233 return ret; 232 234 }
-1
arch/s390/Kconfig
··· 68 68 config S390 69 69 def_bool y 70 70 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE 71 - select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS 72 71 select ARCH_HAS_DEVMEM_IS_ALLOWED 73 72 select ARCH_HAS_ELF_RANDOMIZE 74 73 select ARCH_HAS_GCOV_PROFILE_ALL
-1
arch/s390/configs/default_defconfig
··· 602 602 CONFIG_FAULT_INJECTION_DEBUG_FS=y 603 603 CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y 604 604 CONFIG_LATENCYTOP=y 605 - CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y 606 605 CONFIG_IRQSOFF_TRACER=y 607 606 CONFIG_PREEMPT_TRACER=y 608 607 CONFIG_SCHED_TRACER=y
-1
arch/s390/configs/gcov_defconfig
··· 552 552 CONFIG_CPU_NOTIFIER_ERROR_INJECT=m 553 553 CONFIG_PM_NOTIFIER_ERROR_INJECT=m 554 554 CONFIG_LATENCYTOP=y 555 - CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y 556 555 CONFIG_BLK_DEV_IO_TRACE=y 557 556 # CONFIG_KPROBE_EVENT is not set 558 557 CONFIG_TRACE_ENUM_MAP_FILE=y
-1
arch/s390/configs/performance_defconfig
··· 549 549 CONFIG_RCU_TORTURE_TEST=m 550 550 CONFIG_RCU_CPU_STALL_TIMEOUT=60 551 551 CONFIG_LATENCYTOP=y 552 - CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y 553 552 CONFIG_SCHED_TRACER=y 554 553 CONFIG_FTRACE_SYSCALLS=y 555 554 CONFIG_STACK_TRACER=y
-1
arch/s390/defconfig
··· 172 172 CONFIG_RCU_CPU_STALL_TIMEOUT=60 173 173 CONFIG_RCU_TRACE=y 174 174 CONFIG_LATENCYTOP=y 175 - CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y 176 175 CONFIG_SCHED_TRACER=y 177 176 CONFIG_FTRACE_SYSCALLS=y 178 177 CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
+12 -7
arch/s390/include/asm/uaccess.h
··· 311 311 #define __put_user_unaligned __put_user 312 312 #define __get_user_unaligned __get_user 313 313 314 + extern void __compiletime_error("usercopy buffer size is too small") 315 + __bad_copy_user(void); 316 + 317 + static inline void copy_user_overflow(int size, unsigned long count) 318 + { 319 + WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count); 320 + } 321 + 314 322 /** 315 323 * copy_to_user: - Copy a block of data into user space. 316 324 * @to: Destination address, in user space. ··· 339 331 might_fault(); 340 332 return __copy_to_user(to, from, n); 341 333 } 342 - 343 - void copy_from_user_overflow(void) 344 - #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS 345 - __compiletime_warning("copy_from_user() buffer size is not provably correct") 346 - #endif 347 - ; 348 334 349 335 /** 350 336 * copy_from_user: - Copy a block of data from user space. ··· 364 362 365 363 might_fault(); 366 364 if (unlikely(sz != -1 && sz < n)) { 367 - copy_from_user_overflow(); 365 + if (!__builtin_constant_p(n)) 366 + copy_user_overflow(sz, n); 367 + else 368 + __bad_copy_user(); 368 369 return n; 369 370 } 370 371 return __copy_from_user(to, from, n);
-1
arch/tile/Kconfig
··· 4 4 config TILE 5 5 def_bool y 6 6 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE 7 - select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS 8 7 select ARCH_HAS_DEVMEM_IS_ALLOWED 9 8 select ARCH_HAVE_NMI_SAFE_CMPXCHG 10 9 select ARCH_WANT_FRAME_POINTERS
+10 -12
arch/tile/include/asm/uaccess.h
··· 416 416 return n; 417 417 } 418 418 419 - #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS 420 - /* 421 - * There are still unprovable places in the generic code as of 2.6.34, so this 422 - * option is not really compatible with -Werror, which is more useful in 423 - * general. 424 - */ 425 - extern void copy_from_user_overflow(void) 426 - __compiletime_warning("copy_from_user() size is not provably correct"); 419 + extern void __compiletime_error("usercopy buffer size is too small") 420 + __bad_copy_user(void); 421 + 422 + static inline void copy_user_overflow(int size, unsigned long count) 423 + { 424 + WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count); 425 + } 427 426 428 427 static inline unsigned long __must_check copy_from_user(void *to, 429 428 const void __user *from, ··· 432 433 433 434 if (likely(sz == -1 || sz >= n)) 434 435 n = _copy_from_user(to, from, n); 436 + else if (!__builtin_constant_p(n)) 437 + copy_user_overflow(sz, n); 435 438 else 436 - copy_from_user_overflow(); 439 + __bad_copy_user(); 437 440 438 441 return n; 439 442 } 440 - #else 441 - #define copy_from_user _copy_from_user 442 - #endif 443 443 444 444 #ifdef __tilegx__ 445 445 /**
-1
arch/x86/Kconfig
··· 24 24 select ARCH_DISCARD_MEMBLOCK 25 25 select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI 26 26 select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE 27 - select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS 28 27 select ARCH_HAS_DEVMEM_IS_ALLOWED 29 28 select ARCH_HAS_ELF_RANDOMIZE 30 29 select ARCH_HAS_FAST_MULTIPLIER
+9 -60
arch/x86/include/asm/uaccess.h
··· 697 697 unsigned long __must_check _copy_to_user(void __user *to, const void *from, 698 698 unsigned n); 699 699 700 - #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS 701 - # define copy_user_diag __compiletime_error 702 - #else 703 - # define copy_user_diag __compiletime_warning 704 - #endif 700 + extern void __compiletime_error("usercopy buffer size is too small") 701 + __bad_copy_user(void); 705 702 706 - extern void copy_user_diag("copy_from_user() buffer size is too small") 707 - copy_from_user_overflow(void); 708 - extern void copy_user_diag("copy_to_user() buffer size is too small") 709 - copy_to_user_overflow(void) __asm__("copy_from_user_overflow"); 710 - 711 - #undef copy_user_diag 712 - 713 - #ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS 714 - 715 - extern void 716 - __compiletime_warning("copy_from_user() buffer size is not provably correct") 717 - __copy_from_user_overflow(void) __asm__("copy_from_user_overflow"); 718 - #define __copy_from_user_overflow(size, count) __copy_from_user_overflow() 719 - 720 - extern void 721 - __compiletime_warning("copy_to_user() buffer size is not provably correct") 722 - __copy_to_user_overflow(void) __asm__("copy_from_user_overflow"); 723 - #define __copy_to_user_overflow(size, count) __copy_to_user_overflow() 724 - 725 - #else 726 - 727 - static inline void 728 - __copy_from_user_overflow(int size, unsigned long count) 703 + static inline void copy_user_overflow(int size, unsigned long count) 729 704 { 730 705 WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count); 731 706 } 732 - 733 - #define __copy_to_user_overflow __copy_from_user_overflow 734 - 735 - #endif 736 707 737 708 static inline unsigned long __must_check 738 709 copy_from_user(void *to, const void __user *from, unsigned long n) ··· 714 743 715 744 kasan_check_write(to, n); 716 745 717 - /* 718 - * While we would like to have the compiler do the checking for us 719 - * even in the non-constant size case, any false positives there are 720 - * a problem (especially when DEBUG_STRICT_USER_COPY_CHECKS, but even 721 - * without - the [hopefully] dangerous looking nature of the warning 722 - * would make people go look at the respecitive call sites over and 723 - * over again just to find that there's no problem). 724 - * 725 - * And there are cases where it's just not realistic for the compiler 726 - * to prove the count to be in range. For example when multiple call 727 - * sites of a helper function - perhaps in different source files - 728 - * all doing proper range checking, yet the helper function not doing 729 - * so again. 730 - * 731 - * Therefore limit the compile time checking to the constant size 732 - * case, and do only runtime checking for non-constant sizes. 733 - */ 734 - 735 746 if (likely(sz < 0 || sz >= n)) { 736 747 check_object_size(to, n, false); 737 748 n = _copy_from_user(to, from, n); 738 - } else if (__builtin_constant_p(n)) 739 - copy_from_user_overflow(); 749 + } else if (!__builtin_constant_p(n)) 750 + copy_user_overflow(sz, n); 740 751 else 741 - __copy_from_user_overflow(sz, n); 752 + __bad_copy_user(); 742 753 743 754 return n; 744 755 } ··· 734 781 735 782 might_fault(); 736 783 737 - /* See the comment in copy_from_user() above. */ 738 784 if (likely(sz < 0 || sz >= n)) { 739 785 check_object_size(from, n, true); 740 786 n = _copy_to_user(to, from, n); 741 - } else if (__builtin_constant_p(n)) 742 - copy_to_user_overflow(); 787 + } else if (!__builtin_constant_p(n)) 788 + copy_user_overflow(sz, n); 743 789 else 744 - __copy_to_user_overflow(sz, n); 790 + __bad_copy_user(); 745 791 746 792 return n; 747 793 } 748 - 749 - #undef __copy_from_user_overflow 750 - #undef __copy_to_user_overflow 751 794 752 795 /* 753 796 * We rely on the nested NMI work to allow atomic faults from the NMI path; the
+1
include/asm-generic/uaccess.h
··· 72 72 /* Returns 0 if exception not found and fixup otherwise. */ 73 73 extern unsigned long search_exception_table(unsigned long); 74 74 75 + 75 76 /* 76 77 * architectures with an MMU should override these two 77 78 */
+1 -1
include/linux/compiler-gcc.h
··· 158 158 #define __compiler_offsetof(a, b) \ 159 159 __builtin_offsetof(a, b) 160 160 161 - #if GCC_VERSION >= 40100 && GCC_VERSION < 40600 161 + #if GCC_VERSION >= 40100 162 162 # define __compiletime_object_size(obj) __builtin_object_size(obj, 0) 163 163 #endif 164 164
-18
lib/Kconfig.debug
··· 1686 1686 Enable this option if you want to use the LatencyTOP tool 1687 1687 to find out which userspace is blocking on what kernel operations. 1688 1688 1689 - config ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS 1690 - bool 1691 - 1692 - config DEBUG_STRICT_USER_COPY_CHECKS 1693 - bool "Strict user copy size checks" 1694 - depends on ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS 1695 - depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING 1696 - help 1697 - Enabling this option turns a certain set of sanity checks for user 1698 - copy operations into compile time failures. 1699 - 1700 - The copy_from_user() etc checks are there to help test if there 1701 - are sufficient security checks on the length argument of 1702 - the copy operation, by having gcc prove that the argument is 1703 - within bounds. 1704 - 1705 - If unsure, say N. 1706 - 1707 1689 source kernel/trace/Kconfig 1708 1690 1709 1691 menu "Runtime Testing"
-1
lib/Makefile
··· 24 24 is_single_threaded.o plist.o decompress.o kobject_uevent.o \ 25 25 earlycpio.o seq_buf.o nmi_backtrace.o nodemask.o 26 26 27 - obj-$(CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS) += usercopy.o 28 27 lib-$(CONFIG_MMU) += ioremap.o 29 28 lib-$(CONFIG_SMP) += cpumask.o 30 29 lib-$(CONFIG_HAS_DMA) += dma-noop.o
-9
lib/usercopy.c
··· 1 - #include <linux/export.h> 2 - #include <linux/bug.h> 3 - #include <linux/uaccess.h> 4 - 5 - void copy_from_user_overflow(void) 6 - { 7 - WARN(1, "Buffer overflow detected!\n"); 8 - } 9 - EXPORT_SYMBOL(copy_from_user_overflow);