Commit fb34035e authored by David S. Miller's avatar David S. Miller

sparc: Use __builtin_object_size() to validate the buffer size for copy_from_user()

This mirrors x86 commit 9f0cf4ad
(x86: Use __builtin_object_size() to validate the buffer size for copy_from_user())
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4ed5d5e4
...@@ -33,4 +33,18 @@ config FRAME_POINTER ...@@ -33,4 +33,18 @@ config FRAME_POINTER
depends on MCOUNT depends on MCOUNT
default y default y
config DEBUG_STRICT_USER_COPY_CHECKS
bool "Strict copy size checks"
depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING
---help---
Enabling this option turns a certain set of sanity checks for user
copy operations into compile time failures.
The copy_from_user() etc checks are there to help test if there
are sufficient security checks on the length argument of
the copy operation, by having gcc prove that the argument is
within bounds.
If unsure, or if you run an older (pre 4.4) gcc, say N.
endmenu endmenu
...@@ -260,8 +260,23 @@ static inline unsigned long __copy_to_user(void __user *to, const void *from, un ...@@ -260,8 +260,23 @@ static inline unsigned long __copy_to_user(void __user *to, const void *from, un
return __copy_user(to, (__force void __user *) from, n); return __copy_user(to, (__force void __user *) from, n);
} }
extern void copy_from_user_overflow(void)
#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
__compiletime_error("copy_from_user() buffer size is not provably correct")
#else
__compiletime_warning("copy_from_user() buffer size is not provably correct")
#endif
;
static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
{ {
int sz = __compiletime_object_size(to);
if (unlikely(sz != -1 && sz < n)) {
copy_from_user_overflow();
return -EFAULT;
}
if (n && __access_ok((unsigned long) from, n)) if (n && __access_ok((unsigned long) from, n))
return __copy_user((__force void __user *) to, from, n); return __copy_user((__force void __user *) to, from, n);
else else
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/errno.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/thread_info.h> #include <linux/thread_info.h>
...@@ -204,6 +205,14 @@ __asm__ __volatile__( \ ...@@ -204,6 +205,14 @@ __asm__ __volatile__( \
extern int __get_user_bad(void); extern int __get_user_bad(void);
extern void copy_from_user_overflow(void)
#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
__compiletime_error("copy_from_user() buffer size is not provably correct")
#else
__compiletime_warning("copy_from_user() buffer size is not provably correct")
#endif
;
extern unsigned long __must_check ___copy_from_user(void *to, extern unsigned long __must_check ___copy_from_user(void *to,
const void __user *from, const void __user *from,
unsigned long size); unsigned long size);
...@@ -212,10 +221,16 @@ extern unsigned long copy_from_user_fixup(void *to, const void __user *from, ...@@ -212,10 +221,16 @@ extern unsigned long copy_from_user_fixup(void *to, const void __user *from,
static inline unsigned long __must_check static inline unsigned long __must_check
copy_from_user(void *to, const void __user *from, unsigned long size) copy_from_user(void *to, const void __user *from, unsigned long size)
{ {
unsigned long ret = ___copy_from_user(to, from, size); unsigned long ret = (unsigned long) -EFAULT;
int sz = __compiletime_object_size(to);
if (likely(sz == -1 || sz >= size)) {
ret = ___copy_from_user(to, from, size);
if (unlikely(ret)) if (unlikely(ret))
ret = copy_from_user_fixup(to, from, size); ret = copy_from_user_fixup(to, from, size);
} else {
copy_from_user_overflow();
}
return ret; return ret;
} }
#define __copy_from_user copy_from_user #define __copy_from_user copy_from_user
......
...@@ -44,3 +44,4 @@ obj-y += iomap.o ...@@ -44,3 +44,4 @@ obj-y += iomap.o
obj-$(CONFIG_SPARC32) += atomic32.o obj-$(CONFIG_SPARC32) += atomic32.o
obj-y += ksyms.o obj-y += ksyms.o
obj-$(CONFIG_SPARC64) += PeeCeeI.o obj-$(CONFIG_SPARC64) += PeeCeeI.o
obj-y += usercopy.o
#include <linux/module.h>
#include <linux/bug.h>
void copy_from_user_overflow(void)
{
WARN(1, "Buffer overflow detected!\n");
}
EXPORT_SYMBOL(copy_from_user_overflow);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment