From patchwork Sat May 15 12:34:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 43433 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E7FA53951884; Sat, 15 May 2021 12:34:51 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E7FA53951884 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1621082092; bh=6l9XCRglA4CkQLsLdK3OHzzi/fha9f+u1xG72JWiqec=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=gykyb2qNdgJV//WhTV76P58ehE5ul6lAVFNNeGU77XEXixy3+xYcXEwRi+/sOZIBO VVIeIukawbTgzulWnM4jEzPswGKrTiYSu0MWlG787nS4Ys9bNMbN8n4JFYiacShRtj UoqyV6jjl3+HTOvD0y0rHzgxRYirbFG/NkMEKRDE= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pl1-x632.google.com (mail-pl1-x632.google.com [IPv6:2607:f8b0:4864:20::632]) by sourceware.org (Postfix) with ESMTPS id 493D33858018 for ; Sat, 15 May 2021 12:34:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 493D33858018 Received: by mail-pl1-x632.google.com with SMTP id 69so697444plc.5 for ; Sat, 15 May 2021 05:34:47 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6l9XCRglA4CkQLsLdK3OHzzi/fha9f+u1xG72JWiqec=; b=rFFIDJzAYrUWkVKudGUZVpQm5KlwY6PCTVpuRNBGBswqPlYWozijvfububC7HhVwL3 PQGa4uT+4489YmKHCVLQYpFa2KlggxEZH8qkEAuSQfTEOlS+6l27XnCI4udy8Xuy9KyA 78AJ0S5qZpmUXPDAHS02AQvI/0nr328bAVKbui6E42e6uT6gJkdXFvNcq3W6AXbPO6ox 34B0E8dl4kAOkkLtJw1ALU0l8ogXa26J0xoURIHmQxHX5BQsHC+4n5qcykVTG/5iKFCw 9U91+38y/e1jUOhE1rbEv/1vNZ973BDVGAoUid36y6kyn8EnBJr+RI+mrSYD5r5ZV5AG 2hAA== X-Gm-Message-State: AOAM533zBBgdW4U/1abEZlmG6PbLqfBbVhOItdG2zpjgnmLyxSmbw5dA cz/eaFeWSLG2Tc9KXh7l/lw= X-Google-Smtp-Source: ABdhPJy7FQ7PlX88AHfStMGHEmpgtsLjke2AGwJDc47JKSSWaC1rMPfVWc1xcqUXzd2Qt/LkB9MgyQ== X-Received: by 2002:a17:902:e8cb:b029:ee:f963:4fd8 with SMTP id v11-20020a170902e8cbb02900eef9634fd8mr50226136plg.40.1621082086392; Sat, 15 May 2021 05:34:46 -0700 (PDT) Received: from gnu-cfl-2.localdomain ([172.56.39.231]) by smtp.gmail.com with ESMTPSA id g6sm5981145pfr.213.2021.05.15.05.34.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 May 2021 05:34:44 -0700 (PDT) Received: from gnu-cfl-2.. (localhost [IPv6:::1]) by gnu-cfl-2.localdomain (Postfix) with ESMTP id 36735C0361; Sat, 15 May 2021 05:34:42 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v5 1/5] Add an internal wrapper for clone, clone2 and clone3 Date: Sat, 15 May 2021 05:34:38 -0700 Message-Id: <20210515123442.1432385-2-hjl.tools@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210515123442.1432385-1-hjl.tools@gmail.com> References: <20210515123442.1432385-1-hjl.tools@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-3035.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_NUMSUBJECT, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: "H.J. Lu via Libc-alpha" From: "H.J. Lu" Reply-To: "H.J. Lu" Cc: Florian Weimer Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" The clone3 system call provides a superset of the functionality of clone and clone2. It also provides a number of API improve ments, including the ability to specify the size of the child's stack area which can be used by kernel to compute the shadow stack size when allocating the shadow stack. Add: extern int __clone_internal (struct clone_args *__cl_args, int (*__func) (void *__arg), void *__arg); to provide an abstract interface for clone, clone2 and clone3. 1. Add cast_to_pointer to cast an integer to void * pointer. 2. Simplify stack management for thread creation by passing both stack base and size to create_thread. 3. Consolidate clone vs clone2 differences into a single file. 4. Use only __clone_internal to clone a thread. 5. Call __clone3 if HAVE_CLONE3_WAPPER is defined. If __clone3 returns -1 with ENOSYS, fall back to clone or clone2. 6. Enable the public clone3 wrapper in the future after it has been added to all targets. Tested with build-many-glibcs.py. --- include/clone_internal.h | 14 ++++ include/libc-pointer-arith.h | 3 + sysdeps/unix/sysv/linux/Makefile | 4 +- sysdeps/unix/sysv/linux/clone-internal.c | 97 +++++++++++++++++++++++ sysdeps/unix/sysv/linux/clone-offsets.sym | 5 ++ sysdeps/unix/sysv/linux/clone3.c | 1 + sysdeps/unix/sysv/linux/clone3.h | 55 +++++++++++++ sysdeps/unix/sysv/linux/createthread.c | 25 +++--- sysdeps/unix/sysv/linux/spawni.c | 26 +++--- 9 files changed, 202 insertions(+), 28 deletions(-) create mode 100644 include/clone_internal.h create mode 100644 sysdeps/unix/sysv/linux/clone-internal.c create mode 100644 sysdeps/unix/sysv/linux/clone-offsets.sym create mode 100644 sysdeps/unix/sysv/linux/clone3.c create mode 100644 sysdeps/unix/sysv/linux/clone3.h diff --git a/include/clone_internal.h b/include/clone_internal.h new file mode 100644 index 0000000000..124f7ba169 --- /dev/null +++ b/include/clone_internal.h @@ -0,0 +1,14 @@ +#ifndef _CLONE3_H +#include_next + +extern __typeof (clone3) __clone3; + +/* The internal wrapper of clone and clone3. */ +extern __typeof (clone3) __clone_internal; + +#ifndef _ISOMAC +libc_hidden_proto (__clone3) +libc_hidden_proto (__clone_internal) +#endif + +#endif diff --git a/include/libc-pointer-arith.h b/include/libc-pointer-arith.h index 72e722c5aa..04ba537617 100644 --- a/include/libc-pointer-arith.h +++ b/include/libc-pointer-arith.h @@ -37,6 +37,9 @@ /* Cast an integer or a pointer VAL to integer with proper type. */ # define cast_to_integer(val) ((__integer_if_pointer_type (val)) (val)) +/* Cast an integer VAL to void * pointer. */ +# define cast_to_pointer(val) ((void *) (uintptr_t) (val)) + /* Align a value by rounding down to closest size. e.g. Using size of 4096, we get this behavior: {4095, 4096, 4097} = {0, 4096, 4096}. */ diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index fb155cf856..7c1f32b84d 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -54,6 +54,8 @@ CFLAGS-malloc.c += -DMORECORE_CLEARS=2 endif ifeq ($(subdir),misc) +gen-as-const-headers += clone-offsets.sym + sysdep_routines += adjtimex clone umount umount2 readahead sysctl \ setfsuid setfsgid epoll_pwait signalfd \ eventfd eventfd_read eventfd_write prlimit \ @@ -64,7 +66,7 @@ sysdep_routines += adjtimex clone umount umount2 readahead sysctl \ time64-support pselect32 \ xstat fxstat lxstat xstat64 fxstat64 lxstat64 \ fxstatat fxstatat64 \ - xmknod xmknodat + xmknod xmknodat clone3 clone-internal CFLAGS-gethostid.c = -fexceptions CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables diff --git a/sysdeps/unix/sysv/linux/clone-internal.c b/sysdeps/unix/sysv/linux/clone-internal.c new file mode 100644 index 0000000000..c357b0ac14 --- /dev/null +++ b/sysdeps/unix/sysv/linux/clone-internal.c @@ -0,0 +1,97 @@ +/* The internal wrapper of clone and clone3. + Copyright (C) 2021 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 + . */ + +#include +#include +#include +#include +#include +#include /* For cast_to_pointer. */ +#include /* For _STACK_GROWS_{UP,DOWN}. */ + +#define CLONE_ARGS_SIZE_VER0 64 /* sizeof first published struct */ +#define CLONE_ARGS_SIZE_VER1 80 /* sizeof second published struct */ +#define CLONE_ARGS_SIZE_VER2 88 /* sizeof third published struct */ + +#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) +#define offsetofend(TYPE, MEMBER) \ + (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER)) + +_Static_assert (__alignof(struct clone_args) == 8, + "__alignof(struct clone_args) != 8"); +_Static_assert (offsetofend(struct clone_args, tls) == CLONE_ARGS_SIZE_VER0, + "offsetofend(struct clone_args, tls) != CLONE_ARGS_SIZE_VER0"); +_Static_assert (offsetofend(struct clone_args, set_tid_size) == CLONE_ARGS_SIZE_VER1, + "offsetofend(struct clone_args, set_tid_size) != CLONE_ARGS_SIZE_VER1"); +_Static_assert (offsetofend(struct clone_args, cgroup) == CLONE_ARGS_SIZE_VER2, + "offsetofend(struct clone_args, cgroup) != CLONE_ARGS_SIZE_VER2"); +_Static_assert (sizeof(struct clone_args) == CLONE_ARGS_SIZE_VER2, + "sizeof(struct clone_args) != CLONE_ARGS_SIZE_VER2"); + +int +__clone_internal (struct clone_args *cl_args, + int (*func) (void *arg), void *arg) +{ + int ret; +#ifdef HAVE_CLONE3_WAPPER + /* Try clone3 first. */ + int saved_errno = errno; + ret = __clone3 (cl_args, func, arg); + if (ret != -1 || errno != ENOSYS) + return ret; + + /* NB: Restore errno since errno may be checked against non-zero + return value. */ + __set_errno (saved_errno); +#else + /* Check invalid arguments. */ + if (cl_args == NULL || func == NULL) + { + __set_errno (EINVAL); + return -1; + } +#endif + + /* Map clone3 arguments to clone arguments. NB: No need to check + invalid clone3 specific bits since this is an internal function. */ + int flags = cl_args->flags | cl_args->exit_signal; + void *stack = cast_to_pointer (cl_args->stack); + +#ifdef __ia64__ + ret = __clone2 (func, stack, cl_args->stack_size, + flags, arg, + cast_to_pointer (cl_args->parent_tid), + cast_to_pointer (cl_args->tls), + cast_to_pointer (cl_args->child_tid)); +#else +# if !_STACK_GROWS_DOWN && !_STACK_GROWS_UP +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +# endif + +# if _STACK_GROWS_DOWN + stack += cl_args->stack_size; +# endif + ret = __clone (func, stack, flags, arg, + cast_to_pointer (cl_args->parent_tid), + cast_to_pointer (cl_args->tls), + cast_to_pointer (cl_args->child_tid)); +#endif + return ret; +} + +libc_hidden_def (__clone_internal) diff --git a/sysdeps/unix/sysv/linux/clone-offsets.sym b/sysdeps/unix/sysv/linux/clone-offsets.sym new file mode 100644 index 0000000000..d767e49fc8 --- /dev/null +++ b/sysdeps/unix/sysv/linux/clone-offsets.sym @@ -0,0 +1,5 @@ +#include + +-- + +CLONE_ARGS_SIZE sizeof (struct clone_args) diff --git a/sysdeps/unix/sysv/linux/clone3.c b/sysdeps/unix/sysv/linux/clone3.c new file mode 100644 index 0000000000..de963ef89d --- /dev/null +++ b/sysdeps/unix/sysv/linux/clone3.c @@ -0,0 +1 @@ +/* An empty placeholder. */ diff --git a/sysdeps/unix/sysv/linux/clone3.h b/sysdeps/unix/sysv/linux/clone3.h new file mode 100644 index 0000000000..a222948d55 --- /dev/null +++ b/sysdeps/unix/sysv/linux/clone3.h @@ -0,0 +1,55 @@ +/* The wrapper of clone3. + Copyright (C) 2021 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 + . */ + +#ifndef _CLONE3_H +#define _CLONE3_H 1 + +#include +#include + +__BEGIN_DECLS + +struct clone_args +{ + uint64_t flags; /* Flags bit mask. */ + uint64_t pidfd; /* Where to store PID file descriptor + (pid_t *). */ + uint64_t child_tid; /* Where to store child TID, in child's memory + (pid_t *). */ + uint64_t parent_tid; /* Where to store child TID, in parent's memory + (int *). */ + uint64_t exit_signal; /* Signal to deliver to parent on child + termination */ + uint64_t stack; /* The lowest address of stack. */ + uint64_t stack_size; /* Size of stack. */ + uint64_t tls; /* Location of new TLS. */ + uint64_t set_tid; /* Pointer to a pid_t array + (since Linux 5.5). */ + uint64_t set_tid_size; /* Number of elements in set_tid + (since Linux 5.5). */ + uint64_t cgroup; /* File descriptor for target cgroup + of child (since Linux 5.7). */ +} __attribute__ ((aligned (8))); + +/* The wrapper of clone3. */ +extern int clone3 (struct clone_args *__cl_args, + int (*__func) (void *__arg), void *__arg); + +__END_DECLS + +#endif /* clone3.h */ diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c index bc3409b326..406c73ba00 100644 --- a/sysdeps/unix/sysv/linux/createthread.c +++ b/sysdeps/unix/sysv/linux/createthread.c @@ -25,15 +25,10 @@ #include #include #include +#include #include -#ifdef __NR_clone2 -# define ARCH_CLONE __clone2 -#else -# define ARCH_CLONE __clone -#endif - /* See the comments in pthread_create.c for the requirements for these two macros and the create_thread function. */ @@ -47,7 +42,8 @@ static int start_thread (void *arg) __attribute__ ((noreturn)); static int create_thread (struct pthread *pd, const struct pthread_attr *attr, - bool *stopped_start, STACK_VARIABLES_PARMS, bool *thread_ran) + bool *stopped_start, void *stackaddr, size_t stacksize, + bool *thread_ran) { /* Determine whether the newly created threads has to be started stopped since we have to set the scheduling parameters or set the @@ -100,9 +96,18 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr, TLS_DEFINE_INIT_TP (tp, pd); - if (__glibc_unlikely (ARCH_CLONE (&start_thread, STACK_VARIABLES_ARGS, - clone_flags, pd, &pd->tid, tp, &pd->tid) - == -1)) + struct clone_args args = + { + .flags = clone_flags, + .pidfd = (uintptr_t) &pd->tid, + .parent_tid = (uintptr_t) &pd->tid, + .child_tid = (uintptr_t) &pd->tid, + .stack = (uintptr_t) stackaddr, + .stack_size = stacksize, + .tls = (uintptr_t) tp, + }; + int ret = __clone_internal (&args, &start_thread, pd); + if (__glibc_unlikely (ret == -1)) return errno; /* It's started now, so if we fail below, we'll have to cancel it diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index 501f8fbccd..fd29858cf5 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "spawn_int.h" /* The Linux implementation of posix_spawn{p} uses the clone syscall directly @@ -59,21 +60,6 @@ normal program exit with the exit code 127. */ #define SPAWN_ERROR 127 -#ifdef __ia64__ -# define CLONE(__fn, __stackbase, __stacksize, __flags, __args) \ - __clone2 (__fn, __stackbase, __stacksize, __flags, __args, 0, 0, 0) -#else -# define CLONE(__fn, __stack, __stacksize, __flags, __args) \ - __clone (__fn, __stack, __flags, __args) -#endif - -/* Since ia64 wants the stackbase w/clone2, re-use the grows-up macro. */ -#if _STACK_GROWS_UP || defined (__ia64__) -# define STACK(__stack, __stack_size) (__stack) -#elif _STACK_GROWS_DOWN -# define STACK(__stack, __stack_size) (__stack + __stack_size) -#endif - struct posix_spawn_args { @@ -378,8 +364,14 @@ __spawnix (pid_t * pid, const char *file, need for CLONE_SETTLS. Although parent and child share the same TLS namespace, there will be no concurrent access for TLS variables (errno for instance). */ - new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size, - CLONE_VM | CLONE_VFORK | SIGCHLD, &args); + struct clone_args clone_args = + { + .flags = CLONE_VM | CLONE_VFORK, + .exit_signal = SIGCHLD, + .stack = (uintptr_t) stack, + .stack_size = stack_size, + }; + new_pid = __clone_internal (&clone_args, __spawni_child, &args); /* It needs to collect the case where the auxiliary process was created but failed to execute the file (due either any preparation step or