| 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 |  | 
|---|