Fix copy_from_user_nofault()
Subsystems (6)
v2 cover Fix copy_from_user_nofault()
The original patch got submitted by Alexei Starovoitov with [0] and fixes issues that got also reported in [1].
This resubmission adds !pagefault_disabled() to the check in check_heap_object().
Changelog:v1->v2: Addressed comments from Alexei Starovoitov
- move pagefault_disabled() check into first patch
- keep __copy_from_user_inatomic() in copy_from_user_nofault()
[0] https://lore.kernel.org/all/[email protected]/
[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1033398
Alexei Starovoitov (2):
mm: Fix copy_from_user_nofault().
perf: Fix arch_perf_out_copy_user().
arch/x86/include/asm/perf_event.h | 2 -- arch/x86/lib/Makefile | 2 +- arch/x86/lib/usercopy.c | 55 ------------------------------- kernel/events/internal.h | 16 +-------- mm/maccess.c | 52 ++++++++++++++++++++++++----- mm/usercopy.c | 2 +- 6 files changed, 47 insertions(+), 82 deletions(-) delete mode 100644 arch/x86/lib/usercopy.c
Signature · 1 line
2.39.2
PATCH v2 1/2 mm: Fix copy_from_user_nofault().
From: Alexei Starovoitov <[email protected]>
There are several issues with copy_from_user_nofault():
- access_ok() is designed for user context only and for that reason it has WARN_ON_IN_IRQ() which triggers when bpf, kprobe, eprobe and perf on ppc are calling it from irq.
- it's missing nmi_uaccess_okay() which is a nop on all architectures except x86 where it's required.
The comment in arch/x86/mm/tlb.c explains the details why it's necessary. Calling copy_from_user_nofault() from bpf, [ke]probe without this check is not safe.
- __copy_from_user_inatomic() under CONFIG_HARDENED_USERCOPY is calling check_object_size()->__check_object_size()->check_heap_object()->find_vmap_area()->spin_lock() which is not safe to do from bpf, [ke]probe and perf due to potential deadlock.
Fix all three issues. At the end the copy_from_user_nofault() becomes equivalent to copy_from_user_nmi() from safety point of view with a difference in the return value.
--- mm/maccess.c | 16 +++++++++++----- mm/usercopy.c | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-)
mm/maccess.c +11 -5
@@ -5,6 +5,7 @@#include <linux/export.h> #include <linux/mm.h> #include <linux/uaccess.h> +#include <asm/tlb.h> bool __weak copy_from_kernel_nofault_allowed (const void *unsafe_src,size_t size)
@@ -113,11 +114,16 @@ long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)long copy_from_user_nofault (void *dst,const void __user *src,size_t size) {long ret = -EFAULT ; -if (access_ok (src, size)) { -pagefault_disable (); - ret =__copy_from_user_inatomic (dst, src, size); -pagefault_enable (); - } + +if (!__access_ok (src, size)) +return ret; + +if (!nmi_uaccess_okay ()) +return ret; + +pagefault_disable (); + ret =__copy_from_user_inatomic (dst, src, size); +pagefault_enable ();if (ret)return -EFAULT ;
mm/usercopy.c +1 -1
@@ -173,7 +173,7 @@ static inline void check_heap_object(const void *ptr, unsigned long n,return ; } -if (is_vmalloc_addr (ptr)) { +if (is_vmalloc_addr (ptr) && !pagefault_disabled ()) {struct vmap_area *area =find_vmap_area (addr);if (!area)
Signature · 1 line
2.39.2
PATCH v2 2/2 perf: Fix arch_perf_out_copy_user().
In reply to Florian LehnerFrom: Alexei Starovoitov <[email protected]>
There are several issues with arch_perf_out_copy_user(). On x86 it's the same as copy_from_user_nmi() and all is good, but on other archs:
- __access_ok() is missing.
Only on m68k, s390, parisc, sparc64 archs this function returns 'true'. Other archs must call it before user memory access.
- nmi_uaccess_okay() is missing.
- __copy_from_user_inatomic() issues under CONFIG_HARDENED_USERCOPY.
The latter two issues existed in copy_from_user_nofault() as well and were fixed in the previous patch.
This patch copies comments from copy_from_user_nmi() into mm/maccess.c and splits copy_from_user_nofault() into copy_from_user_nmi() that returns number of not copied bytes and copy_from_user_nofault() that returns -EFAULT or zero.
With that copy_from_user_nmi() becomes generic and is used by perf on all architectures.
--- arch/x86/include/asm/perf_event.h | 2 -- arch/x86/lib/Makefile | 2 +- arch/x86/lib/usercopy.c | 55 ------------------------------- kernel/events/internal.h | 16 +-------- mm/maccess.c | 48 ++++++++++++++++++++++----- 5 files changed, 41 insertions(+), 82 deletions(-) delete mode 100644 arch/x86/lib/usercopy.c
arch/x86/include/asm/perf_event.h +0 -2
@@ -598,6 +598,4 @@ static __always_inline void perf_lopwr_cb(bool lopwr_in)static inline void amd_pmu_disable_virt (void ) { }#endif -#define arch_perf_out_copy_user copy_from_user_nmi -#endif /* _ASM_X86_PERF_EVENT_H */
arch/x86/lib/Makefile +1 -1
@@ -42,7 +42,7 @@ clean-files := inat-tables.c obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o lib-y := delay.o misc.o cmdline.o cpu.o -lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o +lib-y += usercopy_$(BITS).o getuser.o putuser.o lib-y += memcpy_$(BITS).o lib-y += pc-conf-reg.o lib-$(CONFIG_ARCH_HAS_COPY_MC) += copy_mc.o copy_mc_64.o
arch/x86/lib/usercopy.c deleted +0 -55
55 lines not on this page · raw message
kernel/events/internal.h +1 -15
@@ -190,21 +190,7 @@ memcpy_skip(void *dst, const void *src, unsigned long n) DEFINE_OUTPUT_COPY(__output_skip, memcpy_skip) -#ifndef arch_perf_out_copy_user -#define arch_perf_out_copy_user arch_perf_out_copy_user - -static inline unsigned long -arch_perf_out_copy_user (void *dst,const void *src,unsigned long n) -{ -unsigned long ret; - -pagefault_disable (); - ret =__copy_from_user_inatomic (dst, src, n); -pagefault_enable (); - -return ret; -} -#endif +#define arch_perf_out_copy_user copy_from_user_nmiDEFINE_OUTPUT_COPY (__output_copy_user, arch_perf_out_copy_user)
mm/maccess.c +39 -9
67 lines not on this page · raw message
Signature · 1 line
2.39.2
Re: [v2 bpf-next 2/2] perf: Fix arch_perf_out_copy_user().
Quoted 8 lines · Florian Lehner
kernel/events/internal.h +0
-6-#ifndef arch_perf_out_copy_user -#define arch_perf_out_copy_user arch_perf_out_copy_user - -static inline unsigned long -arch_perf_out_copy_user (void *dst,const void *src,unsigned long n) -{
kernel/events/internal.h memcpy_skip(void *dst, const void *src, unsigned long n) · line 193
Quoted 10 lines
kernel/events/internal.h +1
-9-unsigned long ret; - -pagefault_disable (); - ret =__copy_from_user_inatomic (dst, src, n); -pagefault_enable (); - - return ret; -} -#endif +#define arch_perf_out_copy_user copy_from_user_nmi
This fails to build on aarch64. See BPF CI:
https://github.com/kernel-patches/bpf/actions/runs/4683969153/jobs/8299612449
Easy to fix, but I'd like to get an Ack from x86 folks for the 2nd patch.
I've applied the first patch to bpf-next, since it fixes the real issue for kernels with hardened_usercopy=y
This series was applied to bpf/bpf-next.git (master) by Alexei Starovoitov <[email protected]>:
Hello:
This series was applied to bpf/bpf-next.git (master) by Alexei Starovoitov <[email protected]>:
Quoted 6 lines · On Mon, 10 Apr 2023 19:43:43 +0200 you wrote:
The original patch got submitted by Alexei Starovoitov with [0] and fixes issues that got also reported in [1].
This resubmission adds !pagefault_disabled() to the check in
check_heap_object().
Quoted 6 lines
Changelog:
v1->v2: Addressed comments from Alexei Starovoitov
- movepagefault_disabled()check into first patch
- keep__copy_from_user_inatomic()incopy_from_user_nofault()[...]
Here is the summary with links:
- [v2,bpf-next,1/2] mm: Fix copy_from_user_nofault().
https://git.kernel.org/bpf/bpf-next/c/d319f344561d
- [v2,bpf-next,2/2] perf: Fix arch_perf_out_copy_user(). (no matching commit)
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html