Skip to content

Commit 53a41cb

Browse files
committed
Revert "x86/fault: BUG() when uaccess helpers fault on kernel addresses"
This reverts commit 9da3f2b. It was well-intentioned, but wrong. Overriding the exception tables for instructions for random reasons is just wrong, and that is what the new code did. It caused problems for tracing, and it caused problems for strncpy_from_user(), because the new checks made perfectly valid use cases break, rather than catch things that did bad things. Unchecked user space accesses are a problem, but that's not a reason to add invalid checks that then people have to work around with silly flags (in this case, that 'kernel_uaccess_faults_ok' flag, which is just an odd way to say "this commit was wrong" and was sprinked into random places to hide the wrongness). The real fix to unchecked user space accesses is to get rid of the special "let's not check __get_user() and __put_user() at all" logic. Make __{get|put}_user() be just aliases to the regular {get|put}_user() functions, and make it impossible to access user space without having the proper checks in places. The raison d'être of the special double-underscore versions used to be that the range check was expensive, and if you did multiple user accesses, you'd do the range check up front (like the signal frame handling code, for example). But SMAP (on x86) and PAN (on ARM) have made that optimization pointless, because the _real_ expense is the "set CPU flag to allow user space access". Do let's not break the valid cases to catch invalid cases that shouldn't even exist. Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Kees Cook <keescook@chromium.org> Cc: Tobin C. Harding <tobin@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Andy Lutomirski <luto@kernel.org> Cc: Jann Horn <jannh@google.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 5908e6b commit 53a41cb

File tree

4 files changed

+0
-72
lines changed

4 files changed

+0
-72
lines changed

arch/x86/mm/extable.c

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -117,67 +117,11 @@ __visible bool ex_handler_fprestore(const struct exception_table_entry *fixup,
117117
}
118118
EXPORT_SYMBOL_GPL(ex_handler_fprestore);
119119

120-
/* Helper to check whether a uaccess fault indicates a kernel bug. */
121-
static bool bogus_uaccess(struct pt_regs *regs, int trapnr,
122-
unsigned long fault_addr)
123-
{
124-
/* This is the normal case: #PF with a fault address in userspace. */
125-
if (trapnr == X86_TRAP_PF && fault_addr < TASK_SIZE_MAX)
126-
return false;
127-
128-
/*
129-
* This code can be reached for machine checks, but only if the #MC
130-
* handler has already decided that it looks like a candidate for fixup.
131-
* This e.g. happens when attempting to access userspace memory which
132-
* the CPU can't access because of uncorrectable bad memory.
133-
*/
134-
if (trapnr == X86_TRAP_MC)
135-
return false;
136-
137-
/*
138-
* There are two remaining exception types we might encounter here:
139-
* - #PF for faulting accesses to kernel addresses
140-
* - #GP for faulting accesses to noncanonical addresses
141-
* Complain about anything else.
142-
*/
143-
if (trapnr != X86_TRAP_PF && trapnr != X86_TRAP_GP) {
144-
WARN(1, "unexpected trap %d in uaccess\n", trapnr);
145-
return false;
146-
}
147-
148-
/*
149-
* This is a faulting memory access in kernel space, on a kernel
150-
* address, in a usercopy function. This can e.g. be caused by improper
151-
* use of helpers like __put_user and by improper attempts to access
152-
* userspace addresses in KERNEL_DS regions.
153-
* The one (semi-)legitimate exception are probe_kernel_{read,write}(),
154-
* which can be invoked from places like kgdb, /dev/mem (for reading)
155-
* and privileged BPF code (for reading).
156-
* The probe_kernel_*() functions set the kernel_uaccess_faults_ok flag
157-
* to tell us that faulting on kernel addresses, and even noncanonical
158-
* addresses, in a userspace accessor does not necessarily imply a
159-
* kernel bug, root might just be doing weird stuff.
160-
*/
161-
if (current->kernel_uaccess_faults_ok)
162-
return false;
163-
164-
/* This is bad. Refuse the fixup so that we go into die(). */
165-
if (trapnr == X86_TRAP_PF) {
166-
pr_emerg("BUG: pagefault on kernel address 0x%lx in non-whitelisted uaccess\n",
167-
fault_addr);
168-
} else {
169-
pr_emerg("BUG: GPF in non-whitelisted uaccess (non-canonical address?)\n");
170-
}
171-
return true;
172-
}
173-
174120
__visible bool ex_handler_uaccess(const struct exception_table_entry *fixup,
175121
struct pt_regs *regs, int trapnr,
176122
unsigned long error_code,
177123
unsigned long fault_addr)
178124
{
179-
if (bogus_uaccess(regs, trapnr, fault_addr))
180-
return false;
181125
regs->ip = ex_fixup_addr(fixup);
182126
return true;
183127
}
@@ -188,8 +132,6 @@ __visible bool ex_handler_ext(const struct exception_table_entry *fixup,
188132
unsigned long error_code,
189133
unsigned long fault_addr)
190134
{
191-
if (bogus_uaccess(regs, trapnr, fault_addr))
192-
return false;
193135
/* Special hack for uaccess_err */
194136
current->thread.uaccess_err = 1;
195137
regs->ip = ex_fixup_addr(fixup);

fs/namespace.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2698,7 +2698,6 @@ static long exact_copy_from_user(void *to, const void __user * from,
26982698
if (!access_ok(from, n))
26992699
return n;
27002700

2701-
current->kernel_uaccess_faults_ok++;
27022701
while (n) {
27032702
if (__get_user(c, f)) {
27042703
memset(t, 0, n);
@@ -2708,7 +2707,6 @@ static long exact_copy_from_user(void *to, const void __user * from,
27082707
f++;
27092708
n--;
27102709
}
2711-
current->kernel_uaccess_faults_ok--;
27122710
return n;
27132711
}
27142712

include/linux/sched.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -739,12 +739,6 @@ struct task_struct {
739739
unsigned use_memdelay:1;
740740
#endif
741741

742-
/*
743-
* May usercopy functions fault on kernel addresses?
744-
* This is not just a single bit because this can potentially nest.
745-
*/
746-
unsigned int kernel_uaccess_faults_ok;
747-
748742
unsigned long atomic_flags; /* Flags requiring atomic access. */
749743

750744
struct restart_block restart_block;

mm/maccess.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@ long __probe_kernel_read(void *dst, const void *src, size_t size)
3030

3131
set_fs(KERNEL_DS);
3232
pagefault_disable();
33-
current->kernel_uaccess_faults_ok++;
3433
ret = __copy_from_user_inatomic(dst,
3534
(__force const void __user *)src, size);
36-
current->kernel_uaccess_faults_ok--;
3735
pagefault_enable();
3836
set_fs(old_fs);
3937

@@ -60,9 +58,7 @@ long __probe_kernel_write(void *dst, const void *src, size_t size)
6058

6159
set_fs(KERNEL_DS);
6260
pagefault_disable();
63-
current->kernel_uaccess_faults_ok++;
6461
ret = __copy_to_user_inatomic((__force void __user *)dst, src, size);
65-
current->kernel_uaccess_faults_ok--;
6662
pagefault_enable();
6763
set_fs(old_fs);
6864

@@ -98,13 +94,11 @@ long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
9894

9995
set_fs(KERNEL_DS);
10096
pagefault_disable();
101-
current->kernel_uaccess_faults_ok++;
10297

10398
do {
10499
ret = __get_user(*dst++, (const char __user __force *)src++);
105100
} while (dst[-1] && ret == 0 && src - unsafe_addr < count);
106101

107-
current->kernel_uaccess_faults_ok--;
108102
dst[-1] = '\0';
109103
pagefault_enable();
110104
set_fs(old_fs);

0 commit comments

Comments
 (0)