Skip to content

Commit 60becd4

Browse files
arndbfbq
authored andcommitted
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 <[email protected]> Tested-by: Alice Ryhl <[email protected]> Reviewed-by: Boqun Feng <[email protected]> Reviewed-by: Kees Cook <[email protected]> Signed-off-by: Alice Ryhl <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 134ba52 commit 60becd4

File tree

2 files changed

+28
-40
lines changed

2 files changed

+28
-40
lines changed

include/linux/uaccess.h

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/fault-inject-usercopy.h>
66
#include <linux/instrumented.h>
77
#include <linux/minmax.h>
8+
#include <linux/nospec.h>
89
#include <linux/sched.h>
910
#include <linux/thread_info.h>
1011

@@ -138,13 +139,18 @@ __copy_to_user(void __user *to, const void *from, unsigned long n)
138139
return raw_copy_to_user(to, from, n);
139140
}
140141

141-
#ifdef INLINE_COPY_FROM_USER
142142
static inline __must_check unsigned long
143-
_copy_from_user(void *to, const void __user *from, unsigned long n)
143+
_inline_copy_from_user(void *to, const void __user *from, unsigned long n)
144144
{
145145
unsigned long res = n;
146146
might_fault();
147147
if (!should_fail_usercopy() && likely(access_ok(from, n))) {
148+
/*
149+
* Ensure that bad access_ok() speculation will not
150+
* lead to nasty side effects *after* the copy is
151+
* finished:
152+
*/
153+
barrier_nospec();
148154
instrument_copy_from_user_before(to, from, n);
149155
res = raw_copy_from_user(to, from, n);
150156
instrument_copy_from_user_after(to, from, n, res);
@@ -153,14 +159,11 @@ _copy_from_user(void *to, const void __user *from, unsigned long n)
153159
memset(to + (n - res), 0, res);
154160
return res;
155161
}
156-
#else
157162
extern __must_check unsigned long
158163
_copy_from_user(void *, const void __user *, unsigned long);
159-
#endif
160164

161-
#ifdef INLINE_COPY_TO_USER
162165
static inline __must_check unsigned long
163-
_copy_to_user(void __user *to, const void *from, unsigned long n)
166+
_inline_copy_to_user(void __user *to, const void *from, unsigned long n)
164167
{
165168
might_fault();
166169
if (should_fail_usercopy())
@@ -171,25 +174,32 @@ _copy_to_user(void __user *to, const void *from, unsigned long n)
171174
}
172175
return n;
173176
}
174-
#else
175177
extern __must_check unsigned long
176178
_copy_to_user(void __user *, const void *, unsigned long);
177-
#endif
178179

179180
static __always_inline unsigned long __must_check
180181
copy_from_user(void *to, const void __user *from, unsigned long n)
181182
{
182-
if (check_copy_size(to, n, false))
183-
n = _copy_from_user(to, from, n);
184-
return n;
183+
if (!check_copy_size(to, n, false))
184+
return n;
185+
#ifdef INLINE_COPY_FROM_USER
186+
return _inline_copy_from_user(to, from, n);
187+
#else
188+
return _copy_from_user(to, from, n);
189+
#endif
185190
}
186191

187192
static __always_inline unsigned long __must_check
188193
copy_to_user(void __user *to, const void *from, unsigned long n)
189194
{
190-
if (check_copy_size(from, n, true))
191-
n = _copy_to_user(to, from, n);
192-
return n;
195+
if (!check_copy_size(from, n, true))
196+
return n;
197+
198+
#ifdef INLINE_COPY_TO_USER
199+
return _inline_copy_to_user(to, from, n);
200+
#else
201+
return _copy_to_user(to, from, n);
202+
#endif
193203
}
194204

195205
#ifndef copy_mc_to_kernel

lib/usercopy.c

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,18 @@
77

88
/* out-of-line parts */
99

10-
#ifndef INLINE_COPY_FROM_USER
10+
#if !defined(INLINE_COPY_FROM_USER) || defined(CONFIG_RUST)
1111
unsigned long _copy_from_user(void *to, const void __user *from, unsigned long n)
1212
{
13-
unsigned long res = n;
14-
might_fault();
15-
if (!should_fail_usercopy() && likely(access_ok(from, n))) {
16-
/*
17-
* Ensure that bad access_ok() speculation will not
18-
* lead to nasty side effects *after* the copy is
19-
* finished:
20-
*/
21-
barrier_nospec();
22-
instrument_copy_from_user_before(to, from, n);
23-
res = raw_copy_from_user(to, from, n);
24-
instrument_copy_from_user_after(to, from, n, res);
25-
}
26-
if (unlikely(res))
27-
memset(to + (n - res), 0, res);
28-
return res;
13+
return _inline_copy_from_user(to, from, n);
2914
}
3015
EXPORT_SYMBOL(_copy_from_user);
3116
#endif
3217

33-
#ifndef INLINE_COPY_TO_USER
18+
#if !defined(INLINE_COPY_TO_USER) || defined(CONFIG_RUST)
3419
unsigned long _copy_to_user(void __user *to, const void *from, unsigned long n)
3520
{
36-
might_fault();
37-
if (should_fail_usercopy())
38-
return n;
39-
if (likely(access_ok(to, n))) {
40-
instrument_copy_to_user(to, from, n);
41-
n = raw_copy_to_user(to, from, n);
42-
}
43-
return n;
21+
return _inline_copy_to_user(to, from, n);
4422
}
4523
EXPORT_SYMBOL(_copy_to_user);
4624
#endif

0 commit comments

Comments
 (0)