mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-28 05:34:13 -05:00
uaccess: Introduce ucopysize.h
The object size sanity checking macros that uaccess.h and uio.h use have been living in thread_info.h for historical reasons. Needing to use jump labels for these checks, however, introduces a header include loop under certain conditions. The dependencies for the object checking macros are very limited, but they are used by separate header files, so introduce a new header that can be used directly by uaccess.h and uio.h. As a result, this also means thread_info.h (which is rather large) and be removed from those headers. Reported-by: kernel test robot <lkp@intel.com> Closes: https://lore.kernel.org/oe-kbuild-all/202502281153.TG2XK5SI-lkp@intel.com/ Signed-off-by: Kees Cook <kees@kernel.org>
This commit is contained in:
@@ -12586,6 +12586,7 @@ F: Documentation/ABI/testing/sysfs-kernel-warn_count
|
||||
F: arch/*/configs/hardening.config
|
||||
F: include/linux/overflow.h
|
||||
F: include/linux/randomize_kstack.h
|
||||
F: include/linux/ucopysize.h
|
||||
F: kernel/configs/hardening.config
|
||||
F: lib/usercopy_kunit.c
|
||||
F: mm/usercopy.c
|
||||
|
||||
@@ -217,54 +217,6 @@ static inline int arch_within_stack_frames(const void * const stack,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HARDENED_USERCOPY
|
||||
extern void __check_object_size(const void *ptr, unsigned long n,
|
||||
bool to_user);
|
||||
|
||||
static __always_inline void check_object_size(const void *ptr, unsigned long n,
|
||||
bool to_user)
|
||||
{
|
||||
if (!__builtin_constant_p(n))
|
||||
__check_object_size(ptr, n, to_user);
|
||||
}
|
||||
#else
|
||||
static inline void check_object_size(const void *ptr, unsigned long n,
|
||||
bool to_user)
|
||||
{ }
|
||||
#endif /* CONFIG_HARDENED_USERCOPY */
|
||||
|
||||
extern void __compiletime_error("copy source size is too small")
|
||||
__bad_copy_from(void);
|
||||
extern void __compiletime_error("copy destination size is too small")
|
||||
__bad_copy_to(void);
|
||||
|
||||
void __copy_overflow(int size, unsigned long count);
|
||||
|
||||
static inline void copy_overflow(int size, unsigned long count)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_BUG))
|
||||
__copy_overflow(size, count);
|
||||
}
|
||||
|
||||
static __always_inline __must_check bool
|
||||
check_copy_size(const void *addr, size_t bytes, bool is_source)
|
||||
{
|
||||
int sz = __builtin_object_size(addr, 0);
|
||||
if (unlikely(sz >= 0 && sz < bytes)) {
|
||||
if (!__builtin_constant_p(bytes))
|
||||
copy_overflow(sz, bytes);
|
||||
else if (is_source)
|
||||
__bad_copy_from();
|
||||
else
|
||||
__bad_copy_to();
|
||||
return false;
|
||||
}
|
||||
if (WARN_ON_ONCE(bytes > INT_MAX))
|
||||
return false;
|
||||
check_object_size(addr, bytes, is_source);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef arch_setup_new_exec
|
||||
static inline void arch_setup_new_exec(void) { }
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/thread_info.h>
|
||||
#include <linux/ucopysize.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
||||
56
include/linux/ucopysize.h
Normal file
56
include/linux/ucopysize.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Perform sanity checking for object sizes for uaccess.h and uio.h. */
|
||||
#ifndef __LINUX_UCOPYSIZE_H__
|
||||
#define __LINUX_UCOPYSIZE_H__
|
||||
|
||||
#include <linux/bug.h>
|
||||
|
||||
#ifdef CONFIG_HARDENED_USERCOPY
|
||||
extern void __check_object_size(const void *ptr, unsigned long n,
|
||||
bool to_user);
|
||||
|
||||
static __always_inline void check_object_size(const void *ptr, unsigned long n,
|
||||
bool to_user)
|
||||
{
|
||||
if (!__builtin_constant_p(n))
|
||||
__check_object_size(ptr, n, to_user);
|
||||
}
|
||||
#else
|
||||
static inline void check_object_size(const void *ptr, unsigned long n,
|
||||
bool to_user)
|
||||
{ }
|
||||
#endif /* CONFIG_HARDENED_USERCOPY */
|
||||
|
||||
extern void __compiletime_error("copy source size is too small")
|
||||
__bad_copy_from(void);
|
||||
extern void __compiletime_error("copy destination size is too small")
|
||||
__bad_copy_to(void);
|
||||
|
||||
void __copy_overflow(int size, unsigned long count);
|
||||
|
||||
static inline void copy_overflow(int size, unsigned long count)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_BUG))
|
||||
__copy_overflow(size, count);
|
||||
}
|
||||
|
||||
static __always_inline __must_check bool
|
||||
check_copy_size(const void *addr, size_t bytes, bool is_source)
|
||||
{
|
||||
int sz = __builtin_object_size(addr, 0);
|
||||
if (unlikely(sz >= 0 && sz < bytes)) {
|
||||
if (!__builtin_constant_p(bytes))
|
||||
copy_overflow(sz, bytes);
|
||||
else if (is_source)
|
||||
__bad_copy_from();
|
||||
else
|
||||
__bad_copy_to();
|
||||
return false;
|
||||
}
|
||||
if (WARN_ON_ONCE(bytes > INT_MAX))
|
||||
return false;
|
||||
check_object_size(addr, bytes, is_source);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* __LINUX_UCOPYSIZE_H__ */
|
||||
@@ -6,8 +6,8 @@
|
||||
#define __LINUX_UIO_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/thread_info.h>
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/ucopysize.h>
|
||||
#include <uapi/linux/uio.h>
|
||||
|
||||
struct page;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/task.h>
|
||||
#include <linux/sched/task_stack.h>
|
||||
#include <linux/thread_info.h>
|
||||
#include <linux/ucopysize.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
Reference in New Issue
Block a user