aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-06-29 21:42:43 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-06-29 22:21:21 -0400
commitb0377fedb6528087ed319b0d054d6ed82240372c (patch)
treeec1836456be61ee80f6cd416d9d98fcdbe548cd5
parent9c5f6908de03a4f52ba7364b11fcd6116225480c (diff)
copy_{to,from}_user(): consolidate object size checks
... and move them into thread_info.h, next to check_object_size() Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--include/linux/thread_info.h27
-rw-r--r--include/linux/uaccess.h28
2 files changed, 29 insertions, 26 deletions
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index d7d3ea637dd0..250a27614328 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -113,6 +113,33 @@ static inline void check_object_size(const void *ptr, unsigned long n,
113{ } 113{ }
114#endif /* CONFIG_HARDENED_USERCOPY */ 114#endif /* CONFIG_HARDENED_USERCOPY */
115 115
116extern void __compiletime_error("copy source size is too small")
117__bad_copy_from(void);
118extern void __compiletime_error("copy destination size is too small")
119__bad_copy_to(void);
120
121static inline void copy_overflow(int size, unsigned long count)
122{
123 WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count);
124}
125
126static __always_inline bool
127check_copy_size(const void *addr, size_t bytes, bool is_source)
128{
129 int sz = __compiletime_object_size(addr);
130 if (unlikely(sz >= 0 && sz < bytes)) {
131 if (!__builtin_constant_p(bytes))
132 copy_overflow(sz, bytes);
133 else if (is_source)
134 __bad_copy_from();
135 else
136 __bad_copy_to();
137 return false;
138 }
139 check_object_size(addr, bytes, is_source);
140 return true;
141}
142
116#ifndef arch_setup_new_exec 143#ifndef arch_setup_new_exec
117static inline void arch_setup_new_exec(void) { } 144static inline void arch_setup_new_exec(void) { }
118#endif 145#endif
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index e57328896a16..80b587085e79 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -139,43 +139,19 @@ extern unsigned long
139_copy_to_user(void __user *, const void *, unsigned long); 139_copy_to_user(void __user *, const void *, unsigned long);
140#endif 140#endif
141 141
142extern void __compiletime_error("usercopy buffer size is too small")
143__bad_copy_user(void);
144
145static inline void copy_user_overflow(int size, unsigned long count)
146{
147 WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count);
148}
149
150static __always_inline unsigned long __must_check 142static __always_inline unsigned long __must_check
151copy_from_user(void *to, const void __user *from, unsigned long n) 143copy_from_user(void *to, const void __user *from, unsigned long n)
152{ 144{
153 int sz = __compiletime_object_size(to); 145 if (likely(check_copy_size(to, n, false)))
154
155 if (likely(sz < 0 || sz >= n)) {
156 check_object_size(to, n, false);
157 n = _copy_from_user(to, from, n); 146 n = _copy_from_user(to, from, n);
158 } else if (!__builtin_constant_p(n))
159 copy_user_overflow(sz, n);
160 else
161 __bad_copy_user();
162
163 return n; 147 return n;
164} 148}
165 149
166static __always_inline unsigned long __must_check 150static __always_inline unsigned long __must_check
167copy_to_user(void __user *to, const void *from, unsigned long n) 151copy_to_user(void __user *to, const void *from, unsigned long n)
168{ 152{
169 int sz = __compiletime_object_size(from); 153 if (likely(check_copy_size(from, n, true)))
170
171 if (likely(sz < 0 || sz >= n)) {
172 check_object_size(from, n, true);
173 n = _copy_to_user(to, from, n); 154 n = _copy_to_user(to, from, n);
174 } else if (!__builtin_constant_p(n))
175 copy_user_overflow(sz, n);
176 else
177 __bad_copy_user();
178
179 return n; 155 return n;
180} 156}
181#ifdef CONFIG_COMPAT 157#ifdef CONFIG_COMPAT