| 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | /* Perform sanity checking for object sizes for uaccess.h and uio.h. */ |
| 3 | #ifndef __LINUX_UCOPYSIZE_H__ |
| 4 | #define __LINUX_UCOPYSIZE_H__ |
| 5 | |
| 6 | #include <linux/bug.h> |
| 7 | |
| 8 | #ifdef CONFIG_HARDENED_USERCOPY |
| 9 | #include <linux/jump_label.h> |
| 10 | extern void __check_object_size(const void *ptr, unsigned long n, |
| 11 | bool to_user); |
| 12 | |
| 13 | DECLARE_STATIC_KEY_MAYBE(CONFIG_HARDENED_USERCOPY_DEFAULT_ON, |
| 14 | validate_usercopy_range); |
| 15 | |
| 16 | static __always_inline void check_object_size(const void *ptr, unsigned long n, |
| 17 | bool to_user) |
| 18 | { |
| 19 | if (!__builtin_constant_p(n) && |
| 20 | static_branch_maybe(CONFIG_HARDENED_USERCOPY_DEFAULT_ON, |
| 21 | &validate_usercopy_range)) { |
| 22 | __check_object_size(ptr, n, to_user); |
| 23 | } |
| 24 | } |
| 25 | #else |
| 26 | static inline void check_object_size(const void *ptr, unsigned long n, |
| 27 | bool to_user) |
| 28 | { } |
| 29 | #endif /* CONFIG_HARDENED_USERCOPY */ |
| 30 | |
| 31 | extern void __compiletime_error("copy source size is too small" ) |
| 32 | __bad_copy_from(void); |
| 33 | extern void __compiletime_error("copy destination size is too small" ) |
| 34 | __bad_copy_to(void); |
| 35 | |
| 36 | void __copy_overflow(int size, unsigned long count); |
| 37 | |
| 38 | static inline void copy_overflow(int size, unsigned long count) |
| 39 | { |
| 40 | if (IS_ENABLED(CONFIG_BUG)) |
| 41 | __copy_overflow(size, count); |
| 42 | } |
| 43 | |
| 44 | static __always_inline __must_check bool |
| 45 | check_copy_size(const void *addr, size_t bytes, bool is_source) |
| 46 | { |
| 47 | int sz = __builtin_object_size(addr, 0); |
| 48 | if (unlikely(sz >= 0 && sz < bytes)) { |
| 49 | if (!__builtin_constant_p(bytes)) |
| 50 | copy_overflow(size: sz, count: bytes); |
| 51 | else if (is_source) |
| 52 | __bad_copy_from(); |
| 53 | else |
| 54 | __bad_copy_to(); |
| 55 | return false; |
| 56 | } |
| 57 | if (WARN_ON_ONCE(bytes > INT_MAX)) |
| 58 | return false; |
| 59 | check_object_size(ptr: addr, n: bytes, to_user: is_source); |
| 60 | return true; |
| 61 | } |
| 62 | |
| 63 | #endif /* __LINUX_UCOPYSIZE_H__ */ |
| 64 | |