Skip to content

Commit 285a76b

Browse files
bjdooks-ctpalmer-dabbelt
authored andcommitted
riscv: evaluate put_user() arg before enabling user access
The <asm/uaccess.h> header has a problem with put_user(a, ptr) if the 'a' is not a simple variable, such as a function. This can lead to the compiler producing code as so: 1: enable_user_access() 2: evaluate 'a' into register 'r' 3: put 'r' to 'ptr' 4: disable_user_acess() The issue is that 'a' is now being evaluated with the user memory protections disabled. So we try and force the evaulation by assigning 'x' to __val at the start, and hoping the compiler barriers in enable_user_access() do the job of ordering step 2 before step 1. This has shown up in a bug where 'a' sleeps and thus schedules out and loses the SR_SUM flag. This isn't sufficient to fully fix, but should reduce the window of opportunity. The first instance of this we found is in scheudle_tail() where the code does: $ less -N kernel/sched/core.c 4263 if (current->set_child_tid) 4264 put_user(task_pid_vnr(current), current->set_child_tid); Here, the task_pid_vnr(current) is called within the block that has enabled the user memory access. This can be made worse with KASAN which makes task_pid_vnr() a rather large call with plenty of opportunity to sleep. Signed-off-by: Ben Dooks <[email protected]> Reported-by: [email protected] Suggested-by: Arnd Bergman <[email protected]> -- Changes since v1: - fixed formatting and updated the patch description with more info Changes since v2: - fixed commenting on __put_user() ([email protected]) Change since v3: - fixed RFC in patch title. Should be ready to merge. Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 23c1075 commit 285a76b

File tree

1 file changed

+5
-2
lines changed

1 file changed

+5
-2
lines changed

arch/riscv/include/asm/uaccess.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,9 @@ do { \
306306
* data types like structures or arrays.
307307
*
308308
* @ptr must have pointer-to-simple-variable type, and @x must be assignable
309-
* to the result of dereferencing @ptr.
309+
* to the result of dereferencing @ptr. The value of @x is copied to avoid
310+
* re-ordering where @x is evaluated inside the block that enables user-space
311+
* access (thus bypassing user space protection if @x is a function).
310312
*
311313
* Caller must check the pointer with access_ok() before calling this
312314
* function.
@@ -316,12 +318,13 @@ do { \
316318
#define __put_user(x, ptr) \
317319
({ \
318320
__typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
321+
__typeof__(*__gu_ptr) __val = (x); \
319322
long __pu_err = 0; \
320323
\
321324
__chk_user_ptr(__gu_ptr); \
322325
\
323326
__enable_user_access(); \
324-
__put_user_nocheck(x, __gu_ptr, __pu_err); \
327+
__put_user_nocheck(__val, __gu_ptr, __pu_err); \
325328
__disable_user_access(); \
326329
\
327330
__pu_err; \

0 commit comments

Comments
 (0)