sparc: Use __builtin_object_size() to validate the buffer size for copy_from_user()
This mirrors x86 commit 9f0cf4adb6
(x86: Use __builtin_object_size() to validate the buffer size for copy_from_user())
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -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
|
|||||||
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 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#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__( \
|
|||||||
|
|
||||||
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,
|
|||||||
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 (unlikely(ret))
|
if (likely(sz == -1 || sz >= size)) {
|
||||||
ret = copy_from_user_fixup(to, from, size);
|
ret = ___copy_from_user(to, from, size);
|
||||||
|
if (unlikely(ret))
|
||||||
|
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
|
|||||||
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
|
||||||
|
8
arch/sparc/lib/usercopy.c
Normal file
8
arch/sparc/lib/usercopy.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#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);
|
Reference in New Issue
Block a user