Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

uaccess: always export _copy_[from|to]_user with CONFIG_RUST

Rust code needs to be able to access _copy_from_user and _copy_to_user
so that it can skip the check_copy_size check in cases where the length
is known at compile-time, mirroring the logic for when C code will skip
check_copy_size. To do this, we ensure that exported versions of these
methods are available when CONFIG_RUST is enabled.

Alice has verified that this patch passes the CONFIG_TEST_USER_COPY test
on x86 using the Android cuttlefish emulator.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Tested-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Acked-by: Andrew Morton <akpm@linux-foundation.org>
Link: https://lore.kernel.org/r/20240528-alice-mm-v7-2-78222c31b8f4@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

authored by

Arnd Bergmann and committed by
Miguel Ojeda
1f9a8286 1b580e7b

+36 -40
+32 -14
include/linux/uaccess.h
··· 5 5 #include <linux/fault-inject-usercopy.h> 6 6 #include <linux/instrumented.h> 7 7 #include <linux/minmax.h> 8 + #include <linux/nospec.h> 8 9 #include <linux/sched.h> 9 10 #include <linux/thread_info.h> 10 11 ··· 139 138 return raw_copy_to_user(to, from, n); 140 139 } 141 140 142 - #ifdef INLINE_COPY_FROM_USER 141 + /* 142 + * Architectures that #define INLINE_COPY_TO_USER use this function 143 + * directly in the normal copy_to/from_user(), the other ones go 144 + * through an extern _copy_to/from_user(), which expands the same code 145 + * here. 146 + * 147 + * Rust code always uses the extern definition. 148 + */ 143 149 static inline __must_check unsigned long 144 - _copy_from_user(void *to, const void __user *from, unsigned long n) 150 + _inline_copy_from_user(void *to, const void __user *from, unsigned long n) 145 151 { 146 152 unsigned long res = n; 147 153 might_fault(); 148 154 if (!should_fail_usercopy() && likely(access_ok(from, n))) { 155 + /* 156 + * Ensure that bad access_ok() speculation will not 157 + * lead to nasty side effects *after* the copy is 158 + * finished: 159 + */ 160 + barrier_nospec(); 149 161 instrument_copy_from_user_before(to, from, n); 150 162 res = raw_copy_from_user(to, from, n); 151 163 instrument_copy_from_user_after(to, from, n, res); ··· 167 153 memset(to + (n - res), 0, res); 168 154 return res; 169 155 } 170 - #else 171 156 extern __must_check unsigned long 172 157 _copy_from_user(void *, const void __user *, unsigned long); 173 - #endif 174 158 175 - #ifdef INLINE_COPY_TO_USER 176 159 static inline __must_check unsigned long 177 - _copy_to_user(void __user *to, const void *from, unsigned long n) 160 + _inline_copy_to_user(void __user *to, const void *from, unsigned long n) 178 161 { 179 162 might_fault(); 180 163 if (should_fail_usercopy()) ··· 182 171 } 183 172 return n; 184 173 } 185 - #else 186 174 extern __must_check unsigned long 187 175 _copy_to_user(void __user *, const void *, unsigned long); 188 - #endif 189 176 190 177 static __always_inline unsigned long __must_check 191 178 copy_from_user(void *to, const void __user *from, unsigned long n) 192 179 { 193 - if (check_copy_size(to, n, false)) 194 - n = _copy_from_user(to, from, n); 195 - return n; 180 + if (!check_copy_size(to, n, false)) 181 + return n; 182 + #ifdef INLINE_COPY_FROM_USER 183 + return _inline_copy_from_user(to, from, n); 184 + #else 185 + return _copy_from_user(to, from, n); 186 + #endif 196 187 } 197 188 198 189 static __always_inline unsigned long __must_check 199 190 copy_to_user(void __user *to, const void *from, unsigned long n) 200 191 { 201 - if (check_copy_size(from, n, true)) 202 - n = _copy_to_user(to, from, n); 203 - return n; 192 + if (!check_copy_size(from, n, true)) 193 + return n; 194 + 195 + #ifdef INLINE_COPY_TO_USER 196 + return _inline_copy_to_user(to, from, n); 197 + #else 198 + return _copy_to_user(to, from, n); 199 + #endif 204 200 } 205 201 206 202 #ifndef copy_mc_to_kernel
+4 -26
lib/usercopy.c
··· 12 12 13 13 /* out-of-line parts */ 14 14 15 - #ifndef INLINE_COPY_FROM_USER 15 + #if !defined(INLINE_COPY_FROM_USER) || defined(CONFIG_RUST) 16 16 unsigned long _copy_from_user(void *to, const void __user *from, unsigned long n) 17 17 { 18 - unsigned long res = n; 19 - might_fault(); 20 - if (!should_fail_usercopy() && likely(access_ok(from, n))) { 21 - /* 22 - * Ensure that bad access_ok() speculation will not 23 - * lead to nasty side effects *after* the copy is 24 - * finished: 25 - */ 26 - barrier_nospec(); 27 - instrument_copy_from_user_before(to, from, n); 28 - res = raw_copy_from_user(to, from, n); 29 - instrument_copy_from_user_after(to, from, n, res); 30 - } 31 - if (unlikely(res)) 32 - memset(to + (n - res), 0, res); 33 - return res; 18 + return _inline_copy_from_user(to, from, n); 34 19 } 35 20 EXPORT_SYMBOL(_copy_from_user); 36 21 #endif 37 22 38 - #ifndef INLINE_COPY_TO_USER 23 + #if !defined(INLINE_COPY_TO_USER) || defined(CONFIG_RUST) 39 24 unsigned long _copy_to_user(void __user *to, const void *from, unsigned long n) 40 25 { 41 - might_fault(); 42 - if (should_fail_usercopy()) 43 - return n; 44 - if (likely(access_ok(to, n))) { 45 - instrument_copy_to_user(to, from, n); 46 - n = raw_copy_to_user(to, from, n); 47 - } 48 - return n; 26 + return _inline_copy_to_user(to, from, n); 49 27 } 50 28 EXPORT_SYMBOL(_copy_to_user); 51 29 #endif