Call exit directly in clone (BZ #21512)

On aarch64, alpha, arm, hppa, mips, nios2, powerpc, sh, sparc, tile,
and x86_64 the clone syscall jumps to _exit after the child execution
and the function ends the process execution by calling exit_group.
This behavior have a small issue where threads created with
CLONE_THREAD using clone syscall directly will eventually exit the
whole group altogether instead of just the thread created.  Also,
s390, microblaze, ia64, i386, and m68k differs by calling exit
syscall directly.

This patch changes all architectures to call the exit syscall
directly, as for s390, microblaze, ia64, i386, and m68k.  This do not
have change glibc internal behavior in any sort, since the only
usage of clone implementation in posix_spawn calls _exit directly
in the created child (fork uses a direct call to clone).

Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu,
powerpc-linux-gnu, powerpc64le-linux-gnu, sparc64-linux-gnu,
and sparcv9-linux-gnu.

	[BZ #21512]
	* sysdeps/unix/sysv/linux/aarch64/clone.S (__clone): Call exit
	syscall instead of jump to _exit.
	(CLONE_VM_BIT): Remove unused define.
	(CLONE_VM): Likewise.
	(CLONE_THREAD_BIT): Likewise.
	(CLONE_THREAD): Likewise.
	* sysdeps/unix/sysv/linux/alpha/clone.S (__clone): Likewise.
	(CLONE_VM): Remove unused define.
	* sysdeps/unix/sysv/linux/arm/clone.S (__clone): Likewise.
	(CLONE_VM): Remove unused define.
	(CLONE_THREAD): Likewise.
	* sysdeps/unix/sysv/linux/i386/clone.S (CLONE_VM): Likewise.
	* sysdeps/unix/sysv/linux/ia64/clone2.S (__clone2): Call exit
	syscall instead of jump to _exit.
	* sysdeps/unix/sysv/linux/hppa/clone.S (__clone): Likewise.
	* sysdeps/unix/sysv/linux/mips/clone.S (__clone): Likewise.
	(CLONE_VM): Remove unused define.
	(CLONE_THREAD): Likewise.
	* sysdeps/unix/sysv/linux/nios2/clone.S (__clone): Likewise.
	(CLONE_VM): Remove unused define.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S (__clone):
	Likewise.
	(CLONE_VM): Remove unused define.
	(CLONE_THREAD): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S (__clone):
	Likewise.
	(CLONE_VM): Remove unused define.
	(CLONE_THREAD): Likewise.
	* sysdeps/unix/sysv/linux/sh/clone.S  (__clone): Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/clone.S (__clone): Likewise.
	(CLONE_VM): Remove unused define.
	* sysdeps/unix/sysv/linux/sparc/sparc64/clone.S (__clone): Likewise.
	(CLONE_VM): Remove unused define.
	* sysdeps/unix/sysv/linux/tile/clone.S (__clone): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/clone.S (__clone): Likewise.
	(CLONE_VM): Remove unused define.
	* sysdeps/unix/sysv/linux/Makefile (tests): Add tst-clone3.
	* sysdeps/unix/sysv/linux/tst-clone3.c: New file.

Fix
This commit is contained in:
Adhemerval Zanella 2017-06-22 08:49:34 -03:00
parent f819dbea0a
commit 3f823e87cc
19 changed files with 171 additions and 104 deletions

View File

@ -1,3 +1,45 @@
2017-06-26 Adhemerval Zanella <adhemerval.zanella@linaro.org>
[BZ #21512]
* sysdeps/unix/sysv/linux/aarch64/clone.S (__clone): Call exit
syscall instead of jump to _exit.
(CLONE_VM_BIT): Remove unused define.
(CLONE_VM): Likewise.
(CLONE_THREAD_BIT): Likewise.
(CLONE_THREAD): Likewise.
* sysdeps/unix/sysv/linux/alpha/clone.S (__clone): Likewise.
(CLONE_VM): Remove unused define.
* sysdeps/unix/sysv/linux/arm/clone.S (__clone): Likewise.
(CLONE_VM): Remove unused define.
(CLONE_THREAD): Likewise.
* sysdeps/unix/sysv/linux/i386/clone.S (CLONE_VM): Likewise.
* sysdeps/unix/sysv/linux/ia64/clone2.S (__clone2): Call exit
syscall instead of jump to _exit.
* sysdeps/unix/sysv/linux/hppa/clone.S (__clone): Likewise.
* sysdeps/unix/sysv/linux/mips/clone.S (__clone): Likewise.
(CLONE_VM): Remove unused define.
(CLONE_THREAD): Likewise.
* sysdeps/unix/sysv/linux/nios2/clone.S (__clone): Likewise.
(CLONE_VM): Remove unused define.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S (__clone):
Likewise.
(CLONE_VM): Remove unused define.
(CLONE_THREAD): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S (__clone):
Likewise.
(CLONE_VM): Remove unused define.
(CLONE_THREAD): Likewise.
* sysdeps/unix/sysv/linux/sh/clone.S (__clone): Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc32/clone.S (__clone): Likewise.
(CLONE_VM): Remove unused define.
* sysdeps/unix/sysv/linux/sparc/sparc64/clone.S (__clone): Likewise.
(CLONE_VM): Remove unused define.
* sysdeps/unix/sysv/linux/tile/clone.S (__clone): Likewise.
* sysdeps/unix/sysv/linux/x86_64/clone.S (__clone): Likewise.
(CLONE_VM): Remove unused define.
* sysdeps/unix/sysv/linux/Makefile (tests): Add tst-clone3.
* sysdeps/unix/sysv/linux/tst-clone3.c: New file.
2017-06-26 Paul E. Murphy <murphyp@linux.vnet.ibm.com>
Gabriel F. T. Gomes <gftg@linux.vnet.ibm.com>

View File

@ -49,8 +49,8 @@ sysdep_headers += sys/mount.h sys/acct.h sys/sysctl.h \
bits/mman-linux.h \
bits/siginfo-arch.h bits/siginfo-consts-arch.h
tests += tst-clone tst-clone2 tst-fanotify tst-personality tst-quota \
tst-sync_file_range test-errno-linux
tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \
tst-quota tst-sync_file_range test-errno-linux
# Generate the list of SYS_* macros for the system calls (__NR_* macros).

View File

@ -23,12 +23,6 @@
#define _ERRNO_H 1
#include <bits/errno.h>
#define CLONE_VM_BIT 8
#define CLONE_VM (1 << CLONE_VM_BIT)
#define CLONE_THREAD_BIT 16
#define CLONE_THREAD (1 << CLONE_THREAD_BIT)
/* int clone(int (*fn)(void *arg), x0
void *child_stack, x1
int flags, x2
@ -84,7 +78,8 @@ thread_start:
blr x10
/* We are done, pass the return value through x0. */
b HIDDEN_JUMPTARGET(_exit)
mov x8, #SYS_ify(exit)
svc 0x0
cfi_endproc
.size thread_start, .-thread_start

View File

@ -23,8 +23,6 @@
#define _ERRNO_H 1
#include <bits/errno.h>
#define CLONE_VM 0x00000100
/* int clone(int (*fn)(void *arg), void *child_stack, int flags,
void *arg, pid_t *ptid, void *tls, pid_t *ctid);
@ -100,13 +98,8 @@ thread_start:
jsr ra, (pv)
ldgp gp, 0(ra)
/* Call _exit rather than doing it inline for breakpoint purposes. */
mov v0, a0
#ifdef PIC
bsr ra, HIDDEN_JUMPTARGET(_exit) !samegp
#else
jsr ra, HIDDEN_JUMPTARGET(_exit)
#endif
ldiq v0, __NR_exit
call_pal PAL_callsys
/* Die horribly. */
.align 4

View File

@ -24,9 +24,6 @@
#define _ERRNO_H 1
#include <bits/errno.h>
#define CLONE_VM 0x00000100
#define CLONE_THREAD 0x00010000
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
pid_t *ptid, struct user_desc *tls, pid_t *ctid); */
@ -76,7 +73,8 @@ PSEUDO_END (__clone)
BLX (ip)
@ and we are done, passing the return value through r0
b PLTJMP(HIDDEN_JUMPTARGET(_exit))
ldr r7, =SYS_ify(exit)
swi 0x0
.fnend

View File

@ -148,10 +148,10 @@ ENTRY(__clone)
copy %r4, %r19
#endif
/* The call to _exit needs saved r19. */
bl _exit, %rp
copy %ret0, %arg0
ble 0x100(%sr2, %r0)
ldi __NR_exit, %r20
/* We should not return from _exit.
/* We should not return from exit.
We do not restore r4, or the stack state. */
iitlbp %r0, (%sr0, %r0)

View File

@ -39,8 +39,6 @@
#define __NR_clone 120
#define SYS_clone 120
#define CLONE_VM 0x00000100
.text
ENTRY (__clone)
/* Sanity check arguments. */

View File

@ -74,11 +74,11 @@ ENTRY(__clone2)
mov b6=out1
br.call.dptk.many rp=b6 /* Call fn(arg) in the child */
;;
mov out0=r8 /* Argument to _exit */
mov out0=r8 /* Argument to exit */
mov gp=loc0
.globl HIDDEN_JUMPTARGET(_exit)
br.call.dpnt.many rp=HIDDEN_JUMPTARGET(_exit)
/* call _exit with result from fn. */
mov r15=SYS_ify (exit)
.save rp, r0
break __BREAK_SYSCALL
ret /* Not reached. */
PSEUDO_END(__clone2)

View File

@ -24,8 +24,6 @@
#include <bits/errno.h>
#include <tls.h>
#define CLONE_VM 0x00000100
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
void *parent_tidptr, void *tls, void *child_tidptr) */

View File

@ -25,9 +25,6 @@
#include <bits/errno.h>
#include <tls.h>
#define CLONE_VM 0x00000100
#define CLONE_THREAD 0x00010000
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
void *parent_tidptr, void *tls, void *child_tidptr) */
@ -137,14 +134,9 @@ L(thread_start):
/* Call the user's function. */
jal t9
/* Call _exit rather than doing it inline for breakpoint purposes. */
move a0,v0
#ifdef __PIC__
PTR_LA t9,_exit
jalr t9
#else
jal _exit
#endif
li v0,__NR_exit
syscall
END(__thread_start)

View File

@ -25,8 +25,6 @@
#include <bits/errno.h>
#include <tcb-offsets.h>
#define CLONE_VM 0x00000100
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
void *parent_tidptr, void *tls, void *child_tidptr) */
@ -75,18 +73,9 @@ thread_start:
/* Call the user's function. */
callr r5
/* _exit with the result. */
mov r4, r2
#ifdef PIC
nextpc r22
1: movhi r8, %hiadj(_gp_got - 1b)
addi r8, r8, %lo(_gp_got - 1b)
add r22, r22, r8
ldw r8, %call(HIDDEN_JUMPTARGET(_exit))(r22)
jmp r8
#else
jmpi _exit
#endif
/* exit with the result. */
movi r2, SYS_ify (exit)
trap
cfi_endproc
cfi_startproc

View File

@ -20,10 +20,6 @@
#define _ERRNO_H 1
#include <bits/errno.h>
#define CLONE_VM 0x00000100
#define CLONE_THREAD 0x00010000
/* This is the only really unusual system call in PPC linux, but not
because of any weirdness in the system call itself; because of
all the freaky stuff we have to do to make the call useful. */
@ -80,8 +76,7 @@ ENTRY (__clone)
mtctr r30
mr r3,r31
bctrl
/* Call _exit with result from procedure. */
b HIDDEN_JUMPTARGET(_exit)
DO_CALL(SYS_ify(exit))
L(parent):
/* Parent. Restore registers & return. */

View File

@ -20,9 +20,6 @@
#define _ERRNO_H 1
#include <bits/errno.h>
#define CLONE_VM 0x00000100
#define CLONE_THREAD 0x00010000
/* This is the only really unusual system call in PPC linux, but not
because of any weirdness in the system call itself; because of
all the freaky stuff we have to do to make the call useful. */
@ -84,15 +81,11 @@ ENTRY (__clone)
mr r3,r31
bctrl
ld r2,FRAME_TOC_SAVE(r1)
/* Call _exit with result from procedure. */
#ifdef SHARED
b JUMPTARGET(__GI__exit)
#else
bl JUMPTARGET(_exit)
DO_CALL(SYS_ify(exit))
/* We won't ever get here but provide a nop so that the linker
will insert a toc adjusting stub if necessary. */
nop
#endif
L(badargs):
cfi_startproc

View File

@ -73,25 +73,8 @@ ENTRY(__clone)
mov.l @(4,r15), r4
/* we are done, passing the return value through r0 */
mov.l .L3, r1
#ifdef SHARED
mov.l r12, @-r15
sts.l pr, @-r15
mov r0, r4
mova .LG, r0
mov.l .LG, r12
add r0, r12
mova .L3, r0
add r0, r1
jsr @r1
nop
lds.l @r15+, pr
rts
mov.l @r15+, r12
#else
jmp @r1
mov r0, r4
#endif
mov #+SYS_ify(exit), r3
trapa #0x15
.align 2
.LG:
.long _GLOBAL_OFFSET_TABLE_

View File

@ -24,8 +24,6 @@
#include <tcb-offsets.h>
#include <sysdep.h>
#define CLONE_VM 0x00000100
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
pid_t *ptid, void *tls, pid_t *ctid); */
@ -81,7 +79,8 @@ __thread_start:
mov %g0, %fp /* terminate backtrace */
call %g2
mov %g3,%o0
call HIDDEN_JUMPTARGET(_exit),0
set __NR_exit, %g1
ta 0x10
nop
.size __thread_start, .-__thread_start

View File

@ -24,8 +24,6 @@
#include <tcb-offsets.h>
#include <sysdep.h>
#define CLONE_VM 0x00000100
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
pid_t *ptid, void *tls, pid_t *ctid); */
@ -78,7 +76,8 @@ __thread_start:
mov %g0, %fp /* terminate backtrace */
call %g2
mov %g3,%o0
call HIDDEN_JUMPTARGET(_exit),0
set __NR_exit, %g1
ta 0x6d
nop
.size __thread_start, .-__thread_start

View File

@ -168,10 +168,8 @@ ENTRY (__clone)
move r0, r31
jalr r32
}
{
j HIDDEN_JUMPTARGET(_exit)
info INFO_OP_CANNOT_BACKTRACE /* Notify backtracer to stop. */
}
moveli TREG_SYSCALL_NR_NAME, __NR_exit
swint1
PSEUDO_END (__clone)
libc_hidden_def (__clone)

View File

@ -0,0 +1,96 @@
/* Check if clone (CLONE_THREAD) does not call exit_group (BZ #21512)
Copyright (C) 2017 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <string.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <linux/futex.h>
#include <stackinfo.h> /* For _STACK_GROWS_{UP,DOWN}. */
#include <support/check.h>
/* Test if clone call with CLONE_THREAD does not call exit_group. The 'f'
function returns '1', which will be used by clone thread to call the
'exit' syscall directly. If _exit is used instead, exit_group will be
used and thus the thread group will finish with return value of '1'
(where '2' from main thread is expected. */
static int
f (void *a)
{
return 1;
}
/* Futex wait for TID argument, similar to pthread_join internal
implementation. */
#define wait_tid(tid) \
do { \
__typeof (tid) __tid; \
while ((__tid = (tid)) != 0) \
futex_wait (&(tid), __tid); \
} while (0)
static inline int
futex_wait (int *futexp, int val)
{
return syscall (__NR_futex, futexp, FUTEX_WAIT, val);
}
static int
do_test (void)
{
char st[1024] __attribute__ ((aligned));
int clone_flags = CLONE_THREAD;
/* Minimum required flags to used along with CLONE_THREAD. */
clone_flags |= CLONE_VM | CLONE_SIGHAND;
/* We will used ctid to call on futex to wait for thread exit. */
clone_flags |= CLONE_CHILD_CLEARTID;
pid_t ctid, tid;
#ifdef __ia64__
extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base,
size_t __child_stack_size, int __flags,
void *__arg, ...);
tid = __clone2 (f, st, sizeof (st), clone_flags, NULL, /* ptid */ NULL,
/* tls */ NULL, &ctid);
#else
#if _STACK_GROWS_DOWN
tid = clone (f, st + sizeof (st), clone_flags, NULL, /* ptid */ NULL,
/* tls */ NULL, &ctid);
#elif _STACK_GROWS_UP
tid = clone (f, st, clone_flags, NULL, /* ptid */ NULL, /* tls */ NULL,
&ctid);
#else
#error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
#endif
#endif
if (tid == -1)
FAIL_EXIT1 ("clone failed: %m");
ctid = tid;
wait_tid (ctid);
return 2;
}
#define EXPECTED_STATUS 2
#include <support/test-driver.c>

View File

@ -23,8 +23,6 @@
#include <bits/errno.h>
#include <asm-syntax.h>
#define CLONE_VM 0x00000100
/* The userland implementation is:
int clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg),
the kernel entry is:
@ -97,7 +95,8 @@ L(thread_start):
call *%rax
/* Call exit with return value from function call. */
movq %rax, %rdi
call HIDDEN_JUMPTARGET (_exit)
movl $SYS_ify(exit), %eax
syscall
cfi_endproc;
cfi_startproc;