On Sun, Apr 22, 2018 at 10:26:14PM +0300, Konstantin Belousov wrote: > On Sun, Apr 22, 2018 at 09:06:56PM +0200, Tijl Coosemans wrote: > > On Fri, 13 Apr 2018 20:30:49 +0000 (UTC) Konstantin Belousov > > <k...@freebsd.org> wrote: > > Could this have broken the linux futex syscall? I have a linux program > > that gets stuck in linux_sys_futex and becomes unkillable. Note that the > > routines in sys/i386/linux/linux_support.s try to do atomic operations on > > user space addresses. > > Yes, it is quite possible. I will try to look next week.
Try this. I only compile-tested it as a module. diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c index 7741983bcd3..a82672eaa4f 100644 --- a/sys/compat/linux/linux_futex.c +++ b/sys/compat/linux/linux_futex.c @@ -273,14 +273,6 @@ static int handle_futex_death(struct linux_emuldata *, uint32_t *, static int fetch_robust_entry(struct linux_robust_list **, struct linux_robust_list **, unsigned int *); -/* support.s */ -int futex_xchgl(int oparg, uint32_t *uaddr, int *oldval); -int futex_addl(int oparg, uint32_t *uaddr, int *oldval); -int futex_orl(int oparg, uint32_t *uaddr, int *oldval); -int futex_andl(int oparg, uint32_t *uaddr, int *oldval); -int futex_xorl(int oparg, uint32_t *uaddr, int *oldval); - - static int futex_copyin_timeout(int op, struct l_timespec *luts, int clockrt, struct timespec *ts) diff --git a/sys/compat/linux/linux_futex.h b/sys/compat/linux/linux_futex.h index d5798e91560..4171dd70504 100644 --- a/sys/compat/linux/linux_futex.h +++ b/sys/compat/linux/linux_futex.h @@ -78,6 +78,11 @@ extern struct mtx futex_mtx; #define FUTEX_TID_MASK 0x3fffffff #define FUTEX_BITSET_MATCH_ANY 0xffffffff +int futex_xchgl(int oparg, uint32_t *uaddr, int *oldval); +int futex_addl(int oparg, uint32_t *uaddr, int *oldval); +int futex_orl(int oparg, uint32_t *uaddr, int *oldval); +int futex_andl(int oparg, uint32_t *uaddr, int *oldval); +int futex_xorl(int oparg, uint32_t *uaddr, int *oldval); void release_futexes(struct thread *, struct linux_emuldata *); diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index ab48a533893..9fe32a20eb6 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -536,11 +536,10 @@ i386/ibcs2/ibcs2_xenix.c optional ibcs2 i386/ibcs2/ibcs2_xenix_sysent.c optional ibcs2 i386/ibcs2/imgact_coff.c optional ibcs2 i386/linux/imgact_linux.c optional compat_linux +i386/linux/linux_copyout.c optional compat_linux i386/linux/linux_dummy.c optional compat_linux i386/linux/linux_machdep.c optional compat_linux i386/linux/linux_ptrace.c optional compat_linux -i386/linux/linux_support.s optional compat_linux \ - dependency "linux_assym.h" i386/linux/linux_sysent.c optional compat_linux i386/linux/linux_sysvec.c optional compat_linux i386/pci/pci_cfgreg.c optional pci diff --git a/sys/i386/i386/copyout.c b/sys/i386/i386/copyout.c index 3767ff9e54b..9d855eea70e 100644 --- a/sys/i386/i386/copyout.c +++ b/sys/i386/i386/copyout.c @@ -97,7 +97,7 @@ copyout_init_tramp(void) (uintptr_t)suword_fast + setidt_disp); } -static int +int cp_slow0(vm_offset_t uva, size_t len, bool write, void (*f)(vm_offset_t, void *), void *arg) { diff --git a/sys/i386/include/md_var.h b/sys/i386/include/md_var.h index 828b633067d..73c3cba069f 100644 --- a/sys/i386/include/md_var.h +++ b/sys/i386/include/md_var.h @@ -55,6 +55,8 @@ struct segment_descriptor; union savefpu; void bcopyb(const void *from, void *to, size_t len); +int cp_slow0(vm_offset_t uva, size_t len, bool write, + void (*f)(vm_offset_t, void *), void *arg); void cpu_switch_load_gs(void) __asm(__STRING(cpu_switch_load_gs)); void copyout_init_tramp(void); void doreti_iret(void) __asm(__STRING(doreti_iret)); diff --git a/sys/i386/linux/linux_copyout.c b/sys/i386/linux/linux_copyout.c new file mode 100644 index 00000000000..6bb8165ddd9 --- /dev/null +++ b/sys/i386/linux/linux_copyout.c @@ -0,0 +1,193 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Konstantin Belousov <k...@freebsd.org> + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/imgact.h> +#include <sys/lock.h> +#include <sys/sx.h> +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/vm_extern.h> +#include <vm/pmap.h> + +#include <machine/atomic.h> +#include <machine/md_var.h> + +#include <compat/linux/linux_emul.h> +#include <compat/linux/linux_futex.h> + +struct futex_st0 { + int oparg; + int *oldval; +}; + +static void +futex_xchgl_slow0(vm_offset_t kva, void *arg) +{ + struct futex_st0 *st; + + st = arg; + *st->oldval = atomic_swap_int((int *)kva, st->oparg); +} + +int +futex_xchgl(int oparg, uint32_t *uaddr, int *oldval) +{ + struct futex_st0 st; + + if ((uintptr_t)uaddr + sizeof(uint32_t) < (uintptr_t)uaddr || + (uintptr_t)uaddr + sizeof(uint32_t) > VM_MAXUSER_ADDRESS) + return (-EFAULT); + st.oparg = oparg; + st.oldval = oldval; + if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, + futex_xchgl_slow0, &st) != 0) + return (-EFAULT); + return (0); +} + +static void +futex_addl_slow0(vm_offset_t kva, void *arg) +{ + struct futex_st0 *st; + + st = arg; + *st->oldval = atomic_fetchadd_int((int *)kva, st->oparg); +} + +int +futex_addl(int oparg, uint32_t *uaddr, int *oldval) +{ + struct futex_st0 st; + + if ((uintptr_t)uaddr + sizeof(uint32_t) < (uintptr_t)uaddr || + (uintptr_t)uaddr + sizeof(uint32_t) > VM_MAXUSER_ADDRESS) + return (-EFAULT); + st.oparg = oparg; + st.oldval = oldval; + if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, + futex_addl_slow0, &st) != 0) + return (-EFAULT); + return (0); +} + +static void +futex_orl_slow0(vm_offset_t kva, void *arg) +{ + struct futex_st0 *st; + int old; + + st = arg; + old = *(int *)kva; + while (!atomic_fcmpset_int((int *)kva, &old, old | st->oparg)) + ; + *st->oldval = old; +} + +int +futex_orl(int oparg, uint32_t *uaddr, int *oldval) +{ + struct futex_st0 st; + + if ((uintptr_t)uaddr + sizeof(uint32_t) < (uintptr_t)uaddr || + (uintptr_t)uaddr + sizeof(uint32_t) > VM_MAXUSER_ADDRESS) + return (-EFAULT); + st.oparg = oparg; + st.oldval = oldval; + if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, + futex_orl_slow0, &st) != 0) + return (-EFAULT); + return (0); +} + +static void +futex_andl_slow0(vm_offset_t kva, void *arg) +{ + struct futex_st0 *st; + int old; + + st = arg; + old = *(int *)kva; + while (!atomic_fcmpset_int((int *)kva, &old, old & st->oparg)) + ; + *st->oldval = old; +} + +int +futex_andl(int oparg, uint32_t *uaddr, int *oldval) +{ + struct futex_st0 st; + + if ((uintptr_t)uaddr + sizeof(uint32_t) < (uintptr_t)uaddr || + (uintptr_t)uaddr + sizeof(uint32_t) > VM_MAXUSER_ADDRESS) + return (-EFAULT); + st.oparg = oparg; + st.oldval = oldval; + if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, + futex_andl_slow0, &st) != 0) + return (-EFAULT); + return (0); +} + +static void +futex_xorl_slow0(vm_offset_t kva, void *arg) +{ + struct futex_st0 *st; + int old; + + st = arg; + old = *(int *)kva; + while (!atomic_fcmpset_int((int *)kva, &old, old ^ st->oparg)) + ; + *st->oldval = old; +} + +int +futex_xorl(int oparg, uint32_t *uaddr, int *oldval) +{ + struct futex_st0 st; + + if ((uintptr_t)uaddr + sizeof(uint32_t) < (uintptr_t)uaddr || + (uintptr_t)uaddr + sizeof(uint32_t) > VM_MAXUSER_ADDRESS) + return (-EFAULT); + st.oparg = oparg; + st.oldval = oldval; + if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, + futex_xorl_slow0, &st) != 0) + return (-EFAULT); + return (0); +} diff --git a/sys/i386/linux/linux_support.s b/sys/i386/linux/linux_support.s deleted file mode 100644 index fe49dd9effd..00000000000 --- a/sys/i386/linux/linux_support.s +++ /dev/null @@ -1,126 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2006,2007 Konstantin Belousov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include "linux_assym.h" /* system definitions */ -#include <machine/asmacros.h> /* miscellaneous asm macros */ - -#include "assym.inc" - -futex_fault_decx: - movl PCPU(CURPCB),%ecx -futex_fault: - movl $0,PCB_ONFAULT(%ecx) - movl $-EFAULT,%eax - ret - -ENTRY(futex_xchgl) - movl PCPU(CURPCB),%ecx - movl $futex_fault,PCB_ONFAULT(%ecx) - movl 4(%esp),%eax - movl 8(%esp),%edx - cmpl $VM_MAXUSER_ADDRESS-4,%edx - ja futex_fault - xchgl %eax,(%edx) - movl 12(%esp),%edx - movl %eax,(%edx) - xorl %eax,%eax - movl %eax,PCB_ONFAULT(%ecx) - ret - -ENTRY(futex_addl) - movl PCPU(CURPCB),%ecx - movl $futex_fault,PCB_ONFAULT(%ecx) - movl 4(%esp),%eax - movl 8(%esp),%edx - cmpl $VM_MAXUSER_ADDRESS-4,%edx - ja futex_fault -#ifdef SMP - lock -#endif - xaddl %eax,(%edx) - movl 12(%esp),%edx - movl %eax,(%edx) - xorl %eax,%eax - movl %eax,PCB_ONFAULT(%ecx) - ret - -ENTRY(futex_orl) - movl PCPU(CURPCB),%ecx - movl $futex_fault_decx,PCB_ONFAULT(%ecx) - movl 8(%esp),%edx - cmpl $VM_MAXUSER_ADDRESS-4,%edx - ja futex_fault - movl (%edx),%eax -1: movl %eax,%ecx - orl 4(%esp),%ecx -#ifdef SMP - lock -#endif - cmpxchgl %ecx,(%edx) - jnz 1b -futex_tail: - movl 12(%esp),%edx - movl %eax,(%edx) - xorl %eax,%eax - movl PCPU(CURPCB),%ecx - movl %eax,PCB_ONFAULT(%ecx) - ret - -ENTRY(futex_andl) - movl PCPU(CURPCB),%ecx - movl $futex_fault_decx,PCB_ONFAULT(%ecx) - movl 8(%esp),%edx - cmpl $VM_MAXUSER_ADDRESS-4,%edx - ja futex_fault - movl (%edx),%eax -1: movl %eax,%ecx - andl 4(%esp),%ecx -#ifdef SMP - lock -#endif - cmpxchgl %ecx,(%edx) - jnz 1b - jmp futex_tail - -ENTRY(futex_xorl) - movl PCPU(CURPCB),%ecx - movl $futex_fault_decx,PCB_ONFAULT(%ecx) - movl 8(%esp),%edx - cmpl $VM_MAXUSER_ADDRESS-4,%edx - ja futex_fault - movl (%edx),%eax -1: movl %eax,%ecx - xorl 4(%esp),%ecx -#ifdef SMP - lock -#endif - cmpxchgl %ecx,(%edx) - jnz 1b - jmp futex_tail diff --git a/sys/modules/linux/Makefile b/sys/modules/linux/Makefile index 4055fcb3c8a..e49b8da15a9 100644 --- a/sys/modules/linux/Makefile +++ b/sys/modules/linux/Makefile @@ -17,8 +17,12 @@ SRCS= linux_fork.c linux${SFX}_dummy.c linux_file.c linux_event.c \ linux${SFX}_sysvec.c linux_uid16.c linux_time.c \ linux_timer.c linux_vdso.c \ opt_inet6.h opt_compat.h opt_posix.h opt_usb.h vnode_if.h \ - device_if.h bus_if.h \ - linux${SFX}_support.s + device_if.h bus_if.h +.if ${MACHINE_CPUARCH} == "amd64" +SRCS+= linux${SFX}_support.s +.else +SRCS+= linux_copyout.c +.endif DPSRCS= assym.inc linux${SFX}_genassym.c # XXX: for assym.inc @@ -56,11 +60,11 @@ linux${SFX}_locore.o: linux${SFX}_assym.h assym.inc -Wl,-soname=${VDSO}.so.1,--eh-frame-hdr,-warn-common \ ${.IMPSRC} -o ${.TARGET} +.if ${MACHINE_CPUARCH} == "amd64" linux${SFX}_support.o: linux${SFX}_assym.h assym.inc ${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \ ${.IMPSRC} -o ${.TARGET} -.if ${MACHINE_CPUARCH} == "amd64" ${VDSO}.so: linux${SFX}_locore.o ${OBJCOPY} --input-target binary --output-target elf64-x86-64-freebsd \ --binary-architecture i386 linux${SFX}_locore.o ${.TARGET} _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"