Skip to content

Commit 68025ad

Browse files
committed
um: fix _nofault accesses
Nathan reported [1] that when built with clang, the um kernel crashes pretty much immediately. This turned out to be an issue with the inline assembly I had added, when clang used %rax/%eax for both operands. Reorder it so current->thread.segv_continue is written first, and then the lifetime of _faulted won't have overlap with the lifetime of segv_continue. In the email thread Benjamin also pointed out that current->mm is only NULL for true kernel tasks, but we could do this for a userspace task, so the current->thread.segv_continue logic must be lifted out of the mm==NULL check. Finally, while looking at this, put a barrier() so the NULL assignment to thread.segv_continue cannot be reorder before the possibly faulting operation. Reported-by: Nathan Chancellor <nathan@kernel.org> Closes: https://lore.kernel.org/r/20250402221254.GA384@ax162 [1] Fixes: d1d7f01 ("um: mark rodata read-only and implement _nofault accesses") Tested-by: Nathan Chancellor <nathan@kernel.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent 92a09c4 commit 68025ad

File tree

4 files changed

+17
-15
lines changed

4 files changed

+17
-15
lines changed

arch/um/include/asm/uaccess.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ do { \
5555
goto err_label; \
5656
} \
5757
*((type *)dst) = get_unaligned((type *)(src)); \
58+
barrier(); \
5859
current->thread.segv_continue = NULL; \
5960
} while (0)
6061

@@ -66,6 +67,7 @@ do { \
6667
if (__faulted) \
6768
goto err_label; \
6869
put_unaligned(*((type *)src), (type *)(dst)); \
70+
barrier(); \
6971
current->thread.segv_continue = NULL; \
7072
} while (0)
7173

arch/um/kernel/trap.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -225,20 +225,20 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
225225
panic("Failed to sync kernel TLBs: %d", err);
226226
goto out;
227227
}
228-
else if (current->mm == NULL) {
229-
if (current->pagefault_disabled) {
230-
if (!mc) {
231-
show_regs(container_of(regs, struct pt_regs, regs));
232-
panic("Segfault with pagefaults disabled but no mcontext");
233-
}
234-
if (!current->thread.segv_continue) {
235-
show_regs(container_of(regs, struct pt_regs, regs));
236-
panic("Segfault without recovery target");
237-
}
238-
mc_set_rip(mc, current->thread.segv_continue);
239-
current->thread.segv_continue = NULL;
240-
goto out;
228+
else if (current->pagefault_disabled) {
229+
if (!mc) {
230+
show_regs(container_of(regs, struct pt_regs, regs));
231+
panic("Segfault with pagefaults disabled but no mcontext");
241232
}
233+
if (!current->thread.segv_continue) {
234+
show_regs(container_of(regs, struct pt_regs, regs));
235+
panic("Segfault without recovery target");
236+
}
237+
mc_set_rip(mc, current->thread.segv_continue);
238+
current->thread.segv_continue = NULL;
239+
goto out;
240+
}
241+
else if (current->mm == NULL) {
242242
show_regs(container_of(regs, struct pt_regs, regs));
243243
panic("Segfault with no mm");
244244
}

arch/x86/um/shared/sysdep/faultinfo_32.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ struct faultinfo {
3131

3232
#define ___backtrack_faulted(_faulted) \
3333
asm volatile ( \
34-
"mov $0, %0\n" \
3534
"movl $__get_kernel_nofault_faulted_%=,%1\n" \
35+
"mov $0, %0\n" \
3636
"jmp _end_%=\n" \
3737
"__get_kernel_nofault_faulted_%=:\n" \
3838
"mov $1, %0;" \

arch/x86/um/shared/sysdep/faultinfo_64.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ struct faultinfo {
3131

3232
#define ___backtrack_faulted(_faulted) \
3333
asm volatile ( \
34-
"mov $0, %0\n" \
3534
"movq $__get_kernel_nofault_faulted_%=,%1\n" \
35+
"mov $0, %0\n" \
3636
"jmp _end_%=\n" \
3737
"__get_kernel_nofault_faulted_%=:\n" \
3838
"mov $1, %0;" \

0 commit comments

Comments
 (0)