From patchwork Wed Jul 31 18:31:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 170204 Delivered-To: patch@linaro.org Received: by 2002:ac9:2daa:0:0:0:0:0 with SMTP id g42csp6294712oce; Wed, 31 Jul 2019 11:31:54 -0700 (PDT) X-Google-Smtp-Source: APXvYqx0Hbb+KtLHMBGJ7Ewi6KdwMDFkyK4Pq0VdgQHAnErglZZsDmbf1oV82UAc2pgDekhDL8FU X-Received: by 2002:a17:90a:9386:: with SMTP id q6mr4209325pjo.81.1564597914868; Wed, 31 Jul 2019 11:31:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1564597914; cv=none; d=google.com; s=arc-20160816; b=g2kP89f6Xsp640tCg8tL8nPyQ86vyDHkh8IWMjs+dWA1dSLVfAcbLfD1HOCDuMZhVE e3ovLv5JT92w2g1iGvP01cAG/ZzgdXS0NXkbWWXa7qXora0n3jvc64UiAUnjrcIpegHT R5drI1A+lqqz1AfWn7S/EMDXTDnyPO5lO2kz4JRgxv7PmksyLHCc61LojSoiAPIyAoI0 Xa7Ggi1zFy8twcZCubzdNCIYg9UTa4rL1gYGodJj0VxCHdQ45Kt+V76IUIqw6XZAW1Jd ZNYrP/njHWZU5VAdxlqbt/LoJIUwv9YYMLCFoKE9+LuqDZD9vmH3cJVIYV2uBoadPW+G fgnQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=message-id:date:subject:to:from:dkim-signature:delivered-to:sender :list-help:list-post:list-archive:list-subscribe:list-unsubscribe :list-id:precedence:mailing-list:dkim-signature:domainkey-signature; bh=uujKKiaFQSuV6+tEBdmXKlpITJ6uszb/OBs3WzZXiEU=; b=YRpOieSrrE2sE/AKUpbKI6sMmOj6D0SRS21VZOe5R5qjHYttqsz8Kjj/c6HcKSitjH q8h6t4qe0d7PKKRdj8ylLS59CfYvUtMklBZDYfQ7PHz1MaYk8mdWKRjZz/89ZimmCo11 zv7kl7MWc/1TvXsojsGSLMgXioPEP47PlLufHJbMemLlbX7QDH4XSPfw6TVehfIzKR29 bzsAc6i7UGqFxIRPuhSwwipj2W/ePiZCiWoJA13UMapE4luidVOcgLTD0h8EhO0GSwvn hYgvkoybDEveGdjybK96+0p3GZaHLfDItcS8GVa8Hj8w13yDu7aW486MXU9zNFWMha1F e0Eg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=UzAJJLye; dkim=pass header.i=@linaro.org header.s=google header.b=r7B77di0; spf=pass (google.com: domain of libc-alpha-return-104073-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-104073-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id k72si36050667pge.95.2019.07.31.11.31.54 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 31 Jul 2019 11:31:54 -0700 (PDT) Received-SPF: pass (google.com: domain of libc-alpha-return-104073-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=UzAJJLye; dkim=pass header.i=@linaro.org header.s=google header.b=r7B77di0; spf=pass (google.com: domain of libc-alpha-return-104073-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-104073-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id; q=dns; s= default; b=oLKne2bkilr4uvqEpGaB7Kw5CNtFYpiJVXHL5OEX7fImV6hN4hI66 9PcIwalEKz3JKahWVjyTgU9E4ZKsf8vd/9nBRl+vCLEsx+IIoP0zH3q9ueCiCZ8a 4syaalTH8dYNARKzv5Y3CxQc48YUAgLBvLbF2hNoqopmQx/hkA1pY0= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id; s=default; bh=UOFESxQPEbJRJzak1ffKHuePnVo=; b=UzAJJLyePrWbFrIW6jn4fXVFuEiS zMn0p27gkm1X4eypbMMCILxcm73IkCmPGwyW3Yju2RXkX+4fkDCJsBMcJY8ek3KL zxui5Sp1Og2fjsEaIapzBKCFCC+GQgjsvdeP00ikXSJxiGbbqpWaML5vc7NpeIl5 wosEcIPuifOXHq8= Received: (qmail 122212 invoked by alias); 31 Jul 2019 18:31:45 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 122204 invoked by uid 89); 31 Jul 2019 18:31:44 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-15.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=offsetof, Our X-HELO: mail-qt1-f196.google.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id; bh=uujKKiaFQSuV6+tEBdmXKlpITJ6uszb/OBs3WzZXiEU=; b=r7B77di0zkdgNvPkidszJW5/Hcm7ICMCZ40/00t/TVIgdqw+/txdjLrE2sOr6Kk4bX aMNCwYX4ylgCDMvJIu2yBXX8FsxhVObBq50tqdLPTEKZb8F9aOWbF+GmNPbzqgwasnc2 Ti1b7pjgM3rG4XYBA+BIJ1Thnu75p+2INdv5LON1btoHnd8T0BDC9pPLPzFRlck03iM5 2A+aNlHmdvTaKfqNINb1igwEfTjAD4N/FadkUk0PiFw1ea7BySCIlXjcphQ4Yb/NSOuE Ws/r4VRrRu8Q2Umpb6sgnBg4RfSEIJz7LpHKMEiuiDl+nNib/Fl72uhVpJk/OTjG9v1I B+cg== Return-Path: From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH v2 1/5] mips: Do not malloc on getdents64 fallback Date: Wed, 31 Jul 2019 15:31:32 -0300 Message-Id: <20190731183136.21545-1-adhemerval.zanella@linaro.org> This patch changes how the fallback getdents64 implementation calls non-LFS getdents by replacing the scratch_buffer with static buffer plus a loop on getdents calls. This avoids the potential malloc call on scratch_buffer_set_array_size for large input buffer size at the cost of more getdents syscalls. It also adds a small optimization for older kernels, where the first ENOSYS failure for getdents64 disable subsequent calls. Check the dirent tests on a mips64-linux-gnu with getdents64 code disabled. * sysdeps/unix/sysv/linux/mips/mips64/getdents64.c (__getdents64): Add small optimization for older kernel to avoid issuing __NR_getdents64 on each call and replace scratch_buffer usage with a static allocated buffer. --- .../unix/sysv/linux/mips/mips64/getdents64.c | 122 ++++++++---------- 1 file changed, 54 insertions(+), 68 deletions(-) -- 2.17.1 diff --git a/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c b/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c index 8bf3abb0e0..3b5afd9324 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c +++ b/sysdeps/unix/sysv/linux/mips/mips64/getdents64.c @@ -22,98 +22,84 @@ #include #include #include -#include #include ssize_t -__getdents64 (int fd, void *buf0, size_t nbytes) +__getdents64 (int fd, void *buf, size_t nbytes) { - char *buf = buf0; - /* The system call takes an unsigned int argument, and some length checks in the kernel use an int type. */ if (nbytes > INT_MAX) nbytes = INT_MAX; #ifdef __NR_getdents64 - ssize_t ret = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes); - if (ret != -1) - return ret; + static bool getdents64_supportted = true; + if (atomic_load_relaxed (&getdents64_supportted)) + { + ssize_t ret = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes); + if (ret >= 0 || errno != ENOSYS) + return ret; + + atomic_store_relaxed (&getdents64_supportted, false); + } #endif /* Unfortunately getdents64 was only wire-up for MIPS n64 on Linux 3.10. - If syscall is not available it need to fallback to non-LFS one. */ + If the syscall is not available it need to fallback to the non-LFS one. + Also to avoid an unbounded allocation through VLA/alloca or malloc (which + would make the syscall non async-signal-safe) it uses a limited buffer. + This is sub-optimal for large NBYTES, however this is a fallback + mechanism to emulate a syscall that kernel should provide. */ + enum { KBUF_SIZE = 1024 }; struct kernel_dirent - { - unsigned long d_ino; - unsigned long d_off; - unsigned short int d_reclen; - char d_name[256]; - }; - - const size_t size_diff = (offsetof (struct dirent64, d_name) - - offsetof (struct kernel_dirent, d_name)); - - size_t red_nbytes = MIN (nbytes - - ((nbytes / (offsetof (struct dirent64, d_name) - + 14)) * size_diff), - nbytes - size_diff); - - struct scratch_buffer tmpbuf; - scratch_buffer_init (&tmpbuf); - if (!scratch_buffer_set_array_size (&tmpbuf, red_nbytes, sizeof (uint8_t))) - INLINE_SYSCALL_ERROR_RETURN_VALUE (ENOMEM); - - struct kernel_dirent *skdp, *kdp; - skdp = kdp = tmpbuf.data; - - ssize_t retval = INLINE_SYSCALL_CALL (getdents, fd, kdp, red_nbytes); - if (retval == -1) - { - scratch_buffer_free (&tmpbuf); - return -1; - } + { + unsigned long d_ino; + unsigned long d_off; + unsigned short int d_reclen; + char d_name[1]; + } kbuf[KBUF_SIZE / sizeof (struct kernel_dirent)]; + size_t kbuf_size = nbytes < KBUF_SIZE ? nbytes : KBUF_SIZE; - off64_t last_offset = -1; struct dirent64 *dp = (struct dirent64 *) buf; - while ((char *) kdp < (char *) skdp + retval) + + size_t nb = 0; + off64_t last_offset = -1; + + ssize_t r; + while ((r = INLINE_SYSCALL_CALL (getdents, fd, kbuf, kbuf_size)) > 0) { - const size_t alignment = _Alignof (struct dirent64); - /* Since kdp->d_reclen is already aligned for the kernel structure - this may compute a value that is bigger than necessary. */ - size_t new_reclen = ((kdp->d_reclen + size_diff + alignment - 1) - & ~(alignment - 1)); - if ((char *) dp + new_reclen > buf + nbytes) - { - /* Our heuristic failed. We read too many entries. Reset - the stream. */ - assert (last_offset != -1); - __lseek64 (fd, last_offset, SEEK_SET); - - if ((char *) dp == buf) + struct kernel_dirent *skdp, *kdp; + skdp = kdp = kbuf; + + while ((char *) kdp < (char *) skdp + r) + { + const size_t alignment = _Alignof (struct dirent64); + size_t new_reclen = ((kdp->d_reclen + alignment - 1) + & ~(alignment - 1)); + if (nb + new_reclen > nbytes) { - scratch_buffer_free (&tmpbuf); - return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL); + /* The new entry will overflow the input buffer, rewind to + last obtained entry and return. */ + __lseek64 (fd, last_offset, SEEK_SET); + goto out; } + nb += new_reclen; - break; - } - - last_offset = kdp->d_off; - dp->d_ino = kdp->d_ino; - dp->d_off = kdp->d_off; - dp->d_reclen = new_reclen; - dp->d_type = *((char *) kdp + kdp->d_reclen - 1); - memcpy (dp->d_name, kdp->d_name, - kdp->d_reclen - offsetof (struct kernel_dirent, d_name)); + dp->d_ino = kdp->d_ino; + dp->d_off = last_offset = kdp->d_off; + dp->d_reclen = new_reclen; + dp->d_type = *((char *) kdp + kdp->d_reclen - 1); + memcpy (dp->d_name, kdp->d_name, + kdp->d_reclen - offsetof (struct kernel_dirent, d_name)); - dp = (struct dirent64 *) ((char *) dp + new_reclen); - kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen); + dp = (struct dirent64 *) ((char *) dp + new_reclen); + kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen); + } } - scratch_buffer_free (&tmpbuf); - return (char *) dp - buf; +out: + return (char *) dp - (char *) buf; } libc_hidden_def (__getdents64) weak_alias (__getdents64, getdents64) From patchwork Wed Jul 31 18:31:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 170207 Delivered-To: patch@linaro.org Received: by 2002:ac9:2daa:0:0:0:0:0 with SMTP id g42csp6295159oce; Wed, 31 Jul 2019 11:32:23 -0700 (PDT) X-Google-Smtp-Source: APXvYqzP1T/3oaHOY7uoIHiDEkvQJ42I52Wcb8eLKJ2f6U3e2h2AluRKcU7wn3/h7APyUnOnKZxn X-Received: by 2002:a63:7e1d:: with SMTP id z29mr114987338pgc.346.1564597943464; Wed, 31 Jul 2019 11:32:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1564597943; cv=none; d=google.com; s=arc-20160816; b=ODVlgZW+avPKaUFLN7S46X4wE9lRZJJSN3miZUCtHneISvzu3oPcmVza3UPT9Hhkhk lCkhLQ0ot8kru5QWKGAQ2d8sxgBjzRd8zn8zEIKIK/lB9LdnizAu/UfP3NlB7JFksDI9 Zhv//bIcpSml5zuXHuPugh5CZLPf93C/hI6a2qYbGFgzNOqlb5GyCVucsHUwFeVeC6Yu P1i1A0lSfJ2kxA+4EAag7mou4Av7n8Jw9YNHP41qPu4UPj7U8NDZgs24zjxBzR65kmyE g1HWErdvYFpL+vK22gtv8gWa4wXBiEH9mJl4ZkJT4oi5VpCmpyMo8k3hDNQAR86ZAhWK 9HCA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:to:from :dkim-signature:delivered-to:sender:list-help:list-post:list-archive :list-subscribe:list-unsubscribe:list-id:precedence:mailing-list :dkim-signature:domainkey-signature; bh=Qz0DjXicIgB6d19nq1z7PECVNaviQddausDcUHlrfcQ=; b=Z+F0E86R6m46MYYV10gpozkdFakCWStxsQyy4zMUCSTflrg6JElapEQ+xzj6KoOpS3 LNT2S/z6KQ9cKOnMsU3ZV9qCggrdvfW7EIfTkYUDMaZtB5pq0QzpNfPctP57dnaf8/PN zrWzcuK41ADgQ73VVd3ToE8k6UK61LqYBhvUHSkpI7MALMFhGz7d+0i8naC0Pbl2ntJ5 dGG4Y/ubGdSlwZTGP4DsYvFk8mm+kzy9G8rrDCWp5eFiIIbtj7tqFtBb7t0+PzL9IXS5 KiyvsRlBZHmcIwSnWrhmnmUpcXt4StpaLJX8PYfLMQqHpbX8pT3kYWaf5IdVzCzuRSzN 7Prw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b="GI+TOk/H"; dkim=pass header.i=@linaro.org header.s=google header.b=I95qmbOQ; spf=pass (google.com: domain of libc-alpha-return-104076-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-104076-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id o13si1962256pjr.101.2019.07.31.11.32.23 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 31 Jul 2019 11:32:23 -0700 (PDT) Received-SPF: pass (google.com: domain of libc-alpha-return-104076-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b="GI+TOk/H"; dkim=pass header.i=@linaro.org header.s=google header.b=I95qmbOQ; spf=pass (google.com: domain of libc-alpha-return-104076-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-104076-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; q=dns; s=default; b=efEAFYO69k2Nv3YaA8lPFlqWmHXEKXz PwT3n73J6a9kmQnIfhZDmRBIVBnG3imJ6RbtyImZvZZSrMd8T7BU5uMt3DqYRpDF Xz+GbaNk9/WqAEUfjyOGvTQ9DTAr7EB1A/X2C+rykLrdV5A7DlloL86HfVgB00hS hnoqkRkbhyWA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; s=default; bh=50M+YaXe8Oh44EFniPzLdY5NMfU=; b=GI+TO k/HvUG6OR/ikGU5p8Q4KaSuoV5zacjvvAqj+MMM79wNQfhVXB6Zz2y+HxatRLHRo +27qbID+yuLHBHyqDJV66I5CBphdM0f0Wy/szBY5ZKUBxxHIWAuX6vW5yGyq/2xu CDX/IAln17UPUTN2qafwqoWrmWe0P8TbVjLb+8= Received: (qmail 123174 invoked by alias); 31 Jul 2019 18:31:53 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 123090 invoked by uid 89); 31 Jul 2019 18:31:52 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-15.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=Plus, usages X-HELO: mail-qt1-f195.google.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references; bh=Qz0DjXicIgB6d19nq1z7PECVNaviQddausDcUHlrfcQ=; b=I95qmbOQkNPgDh6Kxxyh0H5JS8jdYKcDSyo117jkL1Rp4ly3zSMm42ObtcjWveAPnG HPevKc6EHO6/zDiVB7ZhRmDJn6x25brJ7ug85BDe2t6/i7OnWH97bT6bLh/Nu0lqCohn SUCVU8H4N9gfTybu9Wi5xdX/R0Cu/t0Qbv/473x3YXJAX1Cr2NvVh6jGKW9H7DcVSsda 8X5dceHo7jEHkU9GQ5YZCUXwjM9KQm2TRndAjNqtHP/YZz5XuutzxjDYE7/y5+p0kBHg WwOaMLyZ4BrdnweRFAtan1GBzEkj+gTBH2PEOB9SaSY1Fx/KPpddxCqZkf4TkO07ZzBm xEHw== Return-Path: From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH v2 2/5] posix: Add posix_spawn_file_actions_closefrom Date: Wed, 31 Jul 2019 15:31:33 -0300 Message-Id: <20190731183136.21545-2-adhemerval.zanella@linaro.org> In-Reply-To: <20190731183136.21545-1-adhemerval.zanella@linaro.org> References: <20190731183136.21545-1-adhemerval.zanella@linaro.org> Changes from previous version: - Remove __spawn_valid_fd check on posix_spawn_file_actions_addclosefrom. - Rename __SUPPORT_SPAWN_CLOSEFROM macro to __SPAWN_SUPPORT_CLOSEFROM. - Use getdents64 instead of changing add internal __opendir_inplace. Regarding the lseek to reset the descriptor offset after each file removal, I think that by iteracting the descriptor based on getdents64 results there is no real need for it. The kernel returns the fds sequentially and there is no open operations done concurrently, so both my expectations and the tests result is getdents returns an updated version after a close() call. -- This patch adds a way to close a range of file descriptors on posix_spawn as a new file action. The API is similar to the one provided by Solaris 11 [1], where the file action causes the all open file descriptors greater than or equal to input on to be closed when the new process is spawned. There are some discussions on BZ#10353 [2], although the bug itself asks for a generic solution (similar to the closeall provided by some BSD). The posix_spawn is safe to be implemented by interacting over /proc/self/fd, the Linux spawni.c does not use CLONE_FILES, so the helper process has its own file descriptor table and any failure (in /proc operation) aborts the process creation and returns an error to the caller. I am aware that this file action might be redundant to the current approach of POSIX in promoting O_CLOEXEC in more interfaces. However O_CLOEXEC is still not the default and for some specific usages, the caller needs to close all possible file descriptors to avoid them leaking. Some examples are CPython (discussed in BZ#10353) and OpenJDK jspawnhelper [3] (where OpenJDK spawns a helper process to exactly closes all file descriptors). Most likely any environment which calls functions that might open file descriptor under the hood and aim to use posix_spawn might face the same requirement. Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc64le-linux-gnu, and aarch64-linux-gnu. * posix/Makefile (routines): Add spawn_faction_addclosefrom. (tests): Add tst-spawn5. (tst-spawn5-ARGS): New rule. * posix/Versions [GLIBC_2.30] (libc): Add posix_spawn_file_actions_addclosefrom_np. * posix/spawn.h (posix_spawn_file_actions_addclosefrom_np): New prototype. * posix/spawn_faction_addclosefrom.c: New file * posix/spawn_faction_destroy.c (__posix_spawn_file_actions_destroy): Handle spawn_do_closefrom. * posix/spawn_int.h (__spawn_action): Add closefrom_action and spawn_do_closefrom. * posix/spawn_int_abi.h: New file. * sysdeps/unix/sysv/linux/spawn_int_abi.h: Likewise. * posix/tst-spawn5.c: Likewise. * sysdeps/mach/hurd/spawni.c (__spawni, __spawni_child): Handle spawn_do_closefrom. * sysdeps/posix/spawni.c (__spawni_child): Likewise. * sysdeps/unix/sysv/linux/spawni.c (__spawni_child, __spawnix): Likewise. (spawn_closefrom): New function. * sysdeps/mach/hurd/i386/libc.abilist (2.30): Add posix_spawn_file_actions_addclosefrom_np. * sysdeps/unix/sysv/linux/aarch64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/csky/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise. * sysdeps/unix/sysv/unix/sysv/linux/x86_64/64/libc.abilist: Likewise. * sysdeps/unix/sysv/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise. --- posix/Makefile | 5 +- posix/Versions | 1 + posix/spawn.h | 7 + posix/spawn_faction_addclosefrom.c | 58 +++++ posix/spawn_faction_destroy.c | 1 + posix/spawn_int.h | 6 + posix/spawn_int_abi.h | 27 +++ posix/tst-spawn5.c | 210 ++++++++++++++++++ sysdeps/mach/hurd/i386/libc.abilist | 1 + sysdeps/mach/hurd/spawni.c | 4 + sysdeps/posix/spawni.c | 4 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/libc.abilist | 1 + sysdeps/unix/sysv/linux/csky/libc.abilist | 1 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 + sysdeps/unix/sysv/linux/i386/libc.abilist | 1 + sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 + .../sysv/linux/m68k/coldfire/libc.abilist | 1 + .../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 + .../unix/sysv/linux/microblaze/libc.abilist | 1 + .../sysv/linux/mips/mips32/fpu/libc.abilist | 1 + .../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 + .../sysv/linux/mips/mips64/n32/libc.abilist | 1 + .../sysv/linux/mips/mips64/n64/libc.abilist | 1 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 + .../linux/powerpc/powerpc32/fpu/libc.abilist | 1 + .../linux/powerpc/powerpc64/be/libc.abilist | 1 + .../linux/powerpc/powerpc64/le/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv64/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-32/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-64/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/libc.abilist | 1 + .../sysv/linux/sparc/sparc32/libc.abilist | 1 + .../sysv/linux/sparc/sparc64/libc.abilist | 1 + sysdeps/unix/sysv/linux/spawn_int_abi.h | 25 +++ sysdeps/unix/sysv/linux/spawni.c | 62 +++++- .../unix/sysv/linux/x86_64/64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/x32/libc.abilist | 1 + 39 files changed, 425 insertions(+), 12 deletions(-) create mode 100644 posix/spawn_faction_addclosefrom.c create mode 100644 posix/spawn_int_abi.h create mode 100644 posix/tst-spawn5.c create mode 100644 sysdeps/unix/sysv/linux/spawn_int_abi.h -- 2.17.1 diff --git a/posix/Makefile b/posix/Makefile index 8ac6743ad7..1ac41ad85a 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -57,6 +57,7 @@ routines := \ spawn_faction_init spawn_faction_destroy spawn_faction_addclose \ spawn_faction_addopen spawn_faction_adddup2 spawn_valid_fd \ spawn_faction_addchdir spawn_faction_addfchdir \ + spawn_faction_addclosefrom \ spawnattr_init spawnattr_destroy \ spawnattr_getdefault spawnattr_setdefault \ spawnattr_getflags spawnattr_setflags \ @@ -100,7 +101,8 @@ tests := test-errno tstgetopt testfnm runtests runptests \ tst-posix_fadvise tst-posix_fadvise64 \ tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \ tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \ - bug-regex38 tst-regcomp-truncated tst-spawn-chdir + bug-regex38 tst-regcomp-truncated tst-spawn-chdir \ + tst-spawn5 tests-internal := bug-regex5 bug-regex20 bug-regex33 \ tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \ tst-glob_lstat_compat tst-spawn4-compat @@ -254,6 +256,7 @@ tst-exec-static-ARGS = $(tst-exec-ARGS) tst-execvpe5-ARGS = -- $(host-test-program-cmd) tst-spawn-ARGS = -- $(host-test-program-cmd) tst-spawn-static-ARGS = $(tst-spawn-ARGS) +tst-spawn5-ARGS = -- $(host-test-program-cmd) tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); pwd` $(objpfx)tst-dir tst-chmod-ARGS = $(objdir) tst-vfork3-ARGS = --test-dir=$(objpfx) diff --git a/posix/Versions b/posix/Versions index 7d06a6d0c0..c8268e5996 100644 --- a/posix/Versions +++ b/posix/Versions @@ -146,6 +146,7 @@ libc { posix_spawn_file_actions_addfchdir_np; } GLIBC_2.30 { + posix_spawn_file_actions_addclosefrom_np; } GLIBC_PRIVATE { __libc_fork; __libc_pread; __libc_pwrite; diff --git a/posix/spawn.h b/posix/spawn.h index 471dbea022..773f416b2e 100644 --- a/posix/spawn.h +++ b/posix/spawn.h @@ -213,6 +213,13 @@ extern int posix_spawn_file_actions_addchdir_np (posix_spawn_file_actions_t * extern int posix_spawn_file_actions_addfchdir_np (posix_spawn_file_actions_t *, int __fd) __THROW __nonnull ((1)); + +/* Add an action to close all file descriptor greater than FROM during + spawn. This affects the subsequent file actions. */ +extern int posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t *, + int __from) + __THROW __nonnull ((1)); + #endif __END_DECLS diff --git a/posix/spawn_faction_addclosefrom.c b/posix/spawn_faction_addclosefrom.c new file mode 100644 index 0000000000..52e949c8b3 --- /dev/null +++ b/posix/spawn_faction_addclosefrom.c @@ -0,0 +1,58 @@ +/* Add a closefrom to a file action list for posix_spawn. + Copyright (C) 2019 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 + +int +__posix_spawn_file_actions_addclosefrom (posix_spawn_file_actions_t + *file_actions, int from) +{ +#if __SPAWN_SUPPORT_CLOSEFROM + struct __spawn_action *rec; + + if (fd < 0) + return EBADF; + + /* Allocate more memory if needed. */ + if (file_actions->__used == file_actions->__allocated + && __posix_spawn_file_actions_realloc (file_actions) != 0) + /* This can only mean we ran out of memory. */ + return ENOMEM; + + /* Add the new value. */ + rec = &file_actions->__actions[file_actions->__used]; + rec->tag = spawn_do_closefrom; + rec->action.closefrom_action.from = from; + + /* Account for the new entry. */ + ++file_actions->__used; + + return 0; +#else + __set_errno (EINVAL); + return -1; +#endif +} +weak_alias (__posix_spawn_file_actions_addclosefrom, + posix_spawn_file_actions_addclosefrom_np) +#if !__SPAWN_SUPPORT_CLOSEFROM +stub_warning (posix_spawn_file_actions_addclosefrom_np) +#endif diff --git a/posix/spawn_faction_destroy.c b/posix/spawn_faction_destroy.c index 51fab13585..b45d1cd889 100644 --- a/posix/spawn_faction_destroy.c +++ b/posix/spawn_faction_destroy.c @@ -39,6 +39,7 @@ __posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) case spawn_do_close: case spawn_do_dup2: case spawn_do_fchdir: + case spawn_do_closefrom: /* No cleanup required. */ break; } diff --git a/posix/spawn_int.h b/posix/spawn_int.h index 93b7597f90..0bc29226e4 100644 --- a/posix/spawn_int.h +++ b/posix/spawn_int.h @@ -20,6 +20,7 @@ #define _SPAWN_INT_H #include +#include #include /* Data structure to contain the action information. */ @@ -32,6 +33,7 @@ struct __spawn_action spawn_do_open, spawn_do_chdir, spawn_do_fchdir, + spawn_do_closefrom, } tag; union @@ -60,6 +62,10 @@ struct __spawn_action { int fd; } fchdir_action; + struct + { + int from; + } closefrom_action; } action; }; diff --git a/posix/spawn_int_abi.h b/posix/spawn_int_abi.h new file mode 100644 index 0000000000..142efed339 --- /dev/null +++ b/posix/spawn_int_abi.h @@ -0,0 +1,27 @@ +/* Internal ABI specific for posix_spawn functionality. Generic version. + Copyright (C) 2019 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 _SPAWN_INT_ABI_H +#define _SPAWN_INT_ABI_H + +/* The closefrom file actions requires either a syscall or an arch-specific + way to interact over all file descriptors and act uppon them (such + /proc/self/fd on Linux). */ +#define __SPAWN_SUPPOR_CLOSEFROM 0 + +#endif /* _SPAWN_INT_H */ diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c new file mode 100644 index 0000000000..7af33a4dbe --- /dev/null +++ b/posix/tst-spawn5.c @@ -0,0 +1,210 @@ +/* Tests for posix_spawn signal handling. + Copyright (C) 2019 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Nonzero if the program gets called via `exec'. */ +static int restart; +#define CMDLINE_OPTIONS \ + { "restart", no_argument, &restart, 1 }, + +/* Called on process re-execution. */ +static int +handle_restart (int from) +{ + DIR *fds = opendir ("/proc/self/fd"); + if (fds == NULL) + FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m"); + + while (true) + { + errno = 0; + struct dirent64 *e = readdir64 (fds); + if (e == NULL) + { + if (errno != 0) + FAIL_EXIT1 ("readdir: %m"); + break; + } + + if (e->d_name[0] == '.') + continue; + + char *endptr; + long int fd = strtol (e->d_name, &endptr, 10); + if (*endptr != '\0' || fd < 0 || fd > INT_MAX) + FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s", + e->d_name); + + /* Skip the descriptor which is used to enumerate the + descriptors. */ + if (fd == dirfd (fds)) + continue; + + struct stat64 st; + if (fstat64 (fd, &st) != 0) + FAIL_EXIT1 ("readdir: fstat64 (%ld) failed: %m", fd); + + if (fd >= from) + FAIL_EXIT1 ("error: fd (%ld) greater than from (%d)", fd, from); + } + + closedir (fds); + + return 0; +} + +/* Common argument used for process re-execution. */ +static char *initial_spargv[5]; +static size_t initial_spargv_size; + +/* Re-execute the test process with both '--direct', '--restart', and the + TEST (as integer value) as arguments. */ +static void +reexecute (int fd, const posix_spawn_file_actions_t *fa) +{ + char *spargv[8]; + int i; + + for (i = 0; i < initial_spargv_size; i++) + spargv[i] = initial_spargv[i]; + /* Three digits per byte plus null terminator. */ + char teststr[3 * sizeof (fd) + 1]; + snprintf (teststr, array_length (teststr), "%d", fd); + spargv[i++] = teststr; + spargv[i] = NULL; + TEST_VERIFY (i < 8); + + pid_t pid; + int status; + + TEST_COMPARE (posix_spawn (&pid, spargv[0], fa, NULL, spargv, environ), + 0); + TEST_COMPARE (xwaitpid (pid, &status, 0), pid); + TEST_VERIFY (WIFEXITED (status)); + TEST_VERIFY (!WIFSIGNALED (status)); + TEST_COMPARE (WEXITSTATUS (status), 0); +} + +static void +do_test_closefrom (int num_fd_to_open) +{ + int *fds = xmalloc (num_fd_to_open * sizeof (int)); + for (int i = 0; i < num_fd_to_open; i++) + fds[i] = xopen ("/dev/null", O_WRONLY, 0); + + posix_spawn_file_actions_t fa; + /* posix_spawn_file_actions_init does not fail. */ + posix_spawn_file_actions_init (&fa); + + { + int ret = posix_spawn_file_actions_addclosefrom_np (&fa, fds[0]); + if (ret == -1) + { + if (errno == ENOSYS) + /* Hurd currently does not support closefrom fileaction. */ + FAIL_UNSUPPORTED ("posix_spawn_file_actions_addclosefrom_np unsupported"); + else + FAIL_EXIT1 ("posix_spawn_file_actions_addclosefrom_np failed"); + } + } + + /* Default check, all file descriptor from [fd[0], fd[1]) are opened. */ + reexecute (fds[0], &fa); + + /* Add a gap in the range. */ + xclose (fds[num_fd_to_open/2]); + xclose (fds[num_fd_to_open/2 + 1]); + reexecute (fds[0], &fa); + + /* Add another gap, at the beginning. */ + xclose (fds[0]); + xclose (fds[1]); + reexecute (fds[0], &fa); + + /* Add another gap, now at the end. */ + xclose (fds[num_fd_to_open-1]); + xclose (fds[num_fd_to_open-2]); + reexecute (fds[0], &fa); + + /* Open some more files, filling the gaps. */ + for (int i = 0; i < 6; i++) + xopen ("/dev/null", O_WRONLY, 0); + reexecute (fds[0], &fa); + + /* Open some more, but with O_CLOEXEC. */ + for (int i = 0; i < num_fd_to_open/2; i++) + xopen ("/dev/null", O_WRONLY | O_CLOEXEC, 0); + + free (fds); +} + + +static int +do_test (int argc, char *argv[]) +{ + /* We must have one or four parameters left if called initially: + + path for ld.so optional + + "--library-path" optional + + the library path optional + + the application name + + Plus one parameter to indicate which test to execute through + re-execution. + + So for default usage without --enable-hardcoded-path-in-tests, it + will be called initially with 5 arguments and later with 2. For + --enable-hardcoded-path-in-tests it will be called with 2 arguments + regardless. */ + + if (argc != (restart ? 2 : 5) && argc != 2) + FAIL_EXIT1 ("wrong number of arguments (%d)", argc); + + if (restart) + return handle_restart (atoi (argv[1])); + + /* Respawn using the same arguments. */ + for (initial_spargv_size = 0; + initial_spargv_size < (argc == 5 ? 4 : 1); + initial_spargv_size++) + initial_spargv[initial_spargv_size] = argv[initial_spargv_size + 1]; + initial_spargv[initial_spargv_size++] = (char *) "--direct"; + initial_spargv[initial_spargv_size++] = (char *) "--restart"; + + do_test_closefrom (10); + do_test_closefrom (100); + + return 0; +} + +#define TEST_FUNCTION_ARGV do_test +#include diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist index 1fc7ab2433..fcf957cfc6 100644 --- a/sysdeps/mach/hurd/i386/libc.abilist +++ b/sysdeps/mach/hurd/i386/libc.abilist @@ -2175,6 +2175,7 @@ GLIBC_2.3.4 setipv4sourcefilter F GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F GLIBC_2.4 __fgets_chk F diff --git a/sysdeps/mach/hurd/spawni.c b/sysdeps/mach/hurd/spawni.c index e8024a2679..720e56ffb3 100644 --- a/sysdeps/mach/hurd/spawni.c +++ b/sysdeps/mach/hurd/spawni.c @@ -597,6 +597,10 @@ __spawni (pid_t *pid, const char *file, case spawn_do_fchdir: err = child_fchdir (action->action.fchdir_action.fd); break; + + case spawn_do_closefrom: + err = EINVAL; + break; } if (err) diff --git a/sysdeps/posix/spawni.c b/sysdeps/posix/spawni.c index a5913feb14..3beaba91db 100644 --- a/sysdeps/posix/spawni.c +++ b/sysdeps/posix/spawni.c @@ -231,6 +231,10 @@ __spawni_child (void *arguments) if (__fchdir (action->action.fchdir_action.fd) != 0) goto fail; break; + + case spawn_do_closefrom: + __set_errno (EINVAL); + goto fail; } } } diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index a4c31932cb..e1e793b348 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2143,5 +2143,6 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index fe85a35620..735e54f433 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -2218,6 +2218,7 @@ GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist index bc3df8dcea..a3b9db6efa 100644 --- a/sysdeps/unix/sysv/linux/arm/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist @@ -128,6 +128,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 _Exit F diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 9b3cee65bb..88d112b9b1 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2087,5 +2087,6 @@ GLIBC_2.29 xprt_register F GLIBC_2.29 xprt_unregister F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 75edece94a..2925c96183 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2039,6 +2039,7 @@ GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index edeaf8e722..9fd8ceb639 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -2205,6 +2205,7 @@ GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist index b5d460eeb2..37d817eeb3 100644 --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist @@ -2071,6 +2071,7 @@ GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 05633b3cb8..e81ab1f0bf 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -129,6 +129,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 _Exit F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 47eb7b4608..cd5742bf63 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2148,6 +2148,7 @@ GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist index f7ced487f7..957b14d992 100644 --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist @@ -2135,5 +2135,6 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index e49dc4272e..b8ffdea448 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2122,6 +2122,7 @@ GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index daa3b60c5b..e1c861720a 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2120,6 +2120,7 @@ GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 457ce0b6f2..88fe3f4d26 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2128,6 +2128,7 @@ GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index 63d5c03bfb..7c6dafa818 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2122,6 +2122,7 @@ GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist index 7fec0c9670..487b005070 100644 --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist @@ -2176,5 +2176,6 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index 9200a54309..db81db978a 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -2178,6 +2178,7 @@ GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index 2860df8ebc..06dfdf1fed 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2041,6 +2041,7 @@ GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index 2229a1dcc0..eb0532937e 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2245,5 +2245,6 @@ GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 31010e6cf7..4985fa93e3 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2105,5 +2105,6 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index 576295deff..1ef1b9d4cc 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -2173,6 +2173,7 @@ GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index abf0473683..f9d9fe68ca 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2077,6 +2077,7 @@ GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist index 41977f6e9c..1b12384dd1 100644 --- a/sysdeps/unix/sysv/linux/sh/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist @@ -2043,6 +2043,7 @@ GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index 3d2f00ca52..a7c244cb56 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -2167,6 +2167,7 @@ GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 _IO_fprintf F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index 2f20643e8e..a71facfb43 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2094,6 +2094,7 @@ GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/spawn_int_abi.h b/sysdeps/unix/sysv/linux/spawn_int_abi.h new file mode 100644 index 0000000000..9c4b31ccae --- /dev/null +++ b/sysdeps/unix/sysv/linux/spawn_int_abi.h @@ -0,0 +1,25 @@ +/* Internal ABI specific for posix_spawn functionality. Linux version. + Copyright (C) 2019 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 _SPAWN_INT_ABI_H +#define _SPAWN_INT_ABI_H + +/* spawni.c implements closefrom by interacting over /proc/self/fd. */ +#define __SPAWN_SUPPORT_CLOSEFROM 1 + +#endif /* _SPAWN_INT_H */ diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index c1abf3f960..ca7bf99825 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -17,20 +17,16 @@ . */ #include -#include #include -#include +#include #include -#include -#include -#include #include #include #include -#include -#include -#include +#include +#include #include +#include #include "spawn_int.h" /* The Linux implementation of posix_spawn{p} uses the clone syscall directly @@ -114,6 +110,44 @@ maybe_script_execute (struct posix_spawn_args *args) } } +/* Close all file descriptor up to FROM by interacting /proc/self/fd. */ +static bool +spawn_closefrom (int from) +{ + struct dirent64 entries[1024 / sizeof (struct dirent64)]; + + int dirfd = __open ("/proc/self/fd", O_RDONLY | O_DIRECTORY, 0); + if (dirfd == -1) + return false; + + ssize_t r; + while ((r = __getdents64 (dirfd, entries, sizeof (entries))) > 0) + { + struct dirent64 *dp = entries; + struct dirent64 *edp = (void *)((uintptr_t) dp + r); + + for (struct dirent64 *dp = entries; dp < edp; + dp = (void *)((uintptr_t) dp + dp->d_reclen)) + { + int fd = 0; + + if (dp->d_name[0] == '.') + continue; + + for (const char *s = dp->d_name; isdigit (*s); s++) + fd = 10 * fd + (*s - '0'); + + if (fd == dirfd || fd < from) + continue; + + __close_nocancel (fd); + } + } + + __close_nocancel (dirfd); + return true; +} + /* Function used in the clone call to setup the signals mask, posix_spawn attributes, and file actions. It run on its own stack (provided by the posix_spawn call). */ @@ -280,6 +314,11 @@ __spawni_child (void *arguments) if (__fchdir (action->action.fchdir_action.fd) != 0) goto fail; break; + + case spawn_do_closefrom: + if (!spawn_closefrom (action->action.closefrom_action.from)) + goto fail; + break; } } } @@ -339,12 +378,13 @@ __spawnix (pid_t * pid, const char *file, int prot = (PROT_READ | PROT_WRITE | ((GL (dl_stack_flags) & PF_X) ? PROT_EXEC : 0)); - /* Add a slack area for child's stack. */ - size_t argv_size = (argc * sizeof (void *)) + 512; + size_t argv_size = (argc * sizeof (void *)); /* We need at least a few pages in case the compiler's stack checking is enabled. In some configs, it is known to use at least 24KiB. We use 32KiB to be "safe" from anything the compiler might do. Besides, the - extra pages won't actually be allocated unless they get used. */ + extra pages won't actually be allocated unless they get used. + It also acts the slack for spawn_closefrom (including MIPS64 getdents64 + where it might use about 1k extra stack space. */ argv_size += (32 * 1024); size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize)); void *stack = __mmap (NULL, stack_size, prot, diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index 59f85d9373..78a43f5851 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2052,6 +2052,7 @@ GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F GLIBC_2.4 __confstr_chk F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 67a4e238d6..b83897ddbf 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2151,5 +2151,6 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F GLIBC_2.30 tgkill F GLIBC_2.30 twalk_r F From patchwork Wed Jul 31 18:31:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 170205 Delivered-To: patch@linaro.org Received: by 2002:ac9:2daa:0:0:0:0:0 with SMTP id g42csp6294847oce; Wed, 31 Jul 2019 11:32:04 -0700 (PDT) X-Google-Smtp-Source: APXvYqxe9cRQjRjp5aTcgPTDfVoHIlxrFp4rb9VH1c4X5aNuvF6fQekJI97m39RF7YG6jykdglpt X-Received: by 2002:a63:7d49:: with SMTP id m9mr107196891pgn.161.1564597924420; Wed, 31 Jul 2019 11:32:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1564597924; cv=none; d=google.com; s=arc-20160816; b=KaVG545tkRiK+Tv9e/MAluKyQ/HeU/J9QVZ9XHdKDx7DoOG69RJNOYN6brLKmRkgRI cLC9uIfzRBAECneIp6zsYLdL5eg3y+JwLJ0Lx/KdWgppploYFjB0ujJ+yp8SCsdE9Jul 7AdJGohtOFyVieEjTeJWXlr2a08nHO35Xsd9Z/XpZULy96dg/knZpRfAQomJlTV4pexR 2oTvQLhohT4j/MDn9Pi+R84gAw496uz3q871U2NoIxVHNWkmz2RE6EqGMK7wZe4zi9Dw 9EadhJibguZDzykGLhURz7+4QsXLSywXJkaUZtNGD3/JtjmbizJ1g8lbRmsewmAEbjzZ ML/g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:to:from :dkim-signature:delivered-to:sender:list-help:list-post:list-archive :list-subscribe:list-unsubscribe:list-id:precedence:mailing-list :dkim-signature:domainkey-signature; bh=4Sn0rQZFIPBocZCEY/qEETeEVmc69kFdoP1yzbzVNhc=; b=WphbnEiVe8n6T3WYysuUnn4K5fN4d12rswnmMXpoAtRTf6iFdq+DplgceCDQAD7urg iRxAyNTB5ndP6Ut44UMlfL5s/SVPXjySWzw/+CLoKJN4h3Se9Fn2yCDyNcMpr1vDZOIT kpkdE3cdSyVVjhruhOQNfshEA8dD/r5rpsLDN+AT0IqVpPQq2XpIZK+xqYo+BwwhnFiR zs2FHRJlmWck8qC6g6jy6HFsktMhr9gwIZHKiov1WGOyv9cqiCqwrBLqhgrZ38aJ/ghY ylFbKnrvDC6tMpZtG7I1A5GLTD14pww+bwH/Y4jH8mR6BYT2Ow5ACg26xLRlIkNFAxKF iCPg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=ykFfB5Gq; dkim=pass header.i=@linaro.org header.s=google header.b=rrhi9CNN; spf=pass (google.com: domain of libc-alpha-return-104074-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-104074-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id c35si23412791pgm.51.2019.07.31.11.32.04 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 31 Jul 2019 11:32:04 -0700 (PDT) Received-SPF: pass (google.com: domain of libc-alpha-return-104074-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=ykFfB5Gq; dkim=pass header.i=@linaro.org header.s=google header.b=rrhi9CNN; spf=pass (google.com: domain of libc-alpha-return-104074-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-104074-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; q=dns; s=default; b=dpzEAOosE7N2qiSQ7Aodg6Lc/aUOr2s 3SiJhoQI8fUmfjgAop/sNwrZH/qnizFgDJ6XytIdAAp4hnI9ssb7IvQdWaEi4S21 yfQc7GBR39FU2xjxJAfHx6t2804S5xjJDZbrUx1usfOJJFFOfmFMq/V5NPNMT4l9 4rWERfVciFCI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; s=default; bh=ysySqSzo9FDiMK4wdCqc3wjtZVI=; b=ykFfB 5GqzLXVqlaME5Em1OrwTCpzwazo6tJNy/D6HOHfis0Y69ww6KdKMFWMCxnvPOEnm gyS5H4TOz3h76DlMgONjWh6gEUBZ2mtiOGC96Rc57bvEprko6utGPLQat47sm79H xIHXDT97teYNe+QdbCTZuxmGN8npumKNs8J4nU= Received: (qmail 122865 invoked by alias); 31 Jul 2019 18:31:51 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 122799 invoked by uid 89); 31 Jul 2019 18:31:50 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-15.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=cancelled X-HELO: mail-qt1-f195.google.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references; bh=4Sn0rQZFIPBocZCEY/qEETeEVmc69kFdoP1yzbzVNhc=; b=rrhi9CNNtvWGCPubS+MZ2HBNkUzJ7rr/RDkt1RFnvFk4eVWDa/EaWOmfNwMaNVhgI2 xMfPwTVRWPoNKuv0VU7VAO8EvHeXSKIHFmyDrhpjPIzQrVMGXBBcBAHPhqmIR799YlVu 2gHYlzv5OcPx8qx+LBEbd527jG+pcpsOpAcUgQTQdBaTXJp20noLrdIv+K2X8pdSXb7P 20EEGywd+yB+POXumtpBp2dZRl++5UM115+63WI9uHu0ykHNg4mq8457pipDImfjDsh2 GTPOHgTR5H+gZLZPyuQs59m1FYQtyZt6Vm1dW5UDs4MvgIp8HK+pPKqoGEIf6NPn1f71 YOGw== Return-Path: From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH v2 3/5] posix: Optimize stack Linux posix_spawn Date: Wed, 31 Jul 2019 15:31:34 -0300 Message-Id: <20190731183136.21545-3-adhemerval.zanella@linaro.org> In-Reply-To: <20190731183136.21545-1-adhemerval.zanella@linaro.org> References: <20190731183136.21545-1-adhemerval.zanella@linaro.org> Changes from previous version: * Move the logic of stack mapping creation to stackmap.h and added a guard page allocation for the compatibility case. -- The current internal posix_spawn symbol for Linux (__spawni) requires to allocate a dynamic stack based on input arguments to handle the SPAWN_XFLAGS_USE_PATH internal flag, which re-issue the input binary as a shell script if execve call return ENOEXEC (to execute shell scripts with an initial shebang). This is done only for compatibility mode and the generic case does not require the extra calculation plus the potential large mmap/munmap call. For default case, a pre-defined buffer is sufficed to use on the clone call instead. This patch optimizes Linux spawni by allocating a dynamic stack only for compatibility symbol (SPAWN_XFLAGS_USE_PATH). For generic case, an mmap allocated buffer is used along with a guard page, similar to what NPTL uses for thread stacks hardening. For default case, it is a fixed code path with fixed stack usage in helper process, so assuming a large enough stack buffer it would never overflow. It also does not prevent to adapt to the vfork-like to re-use process stack, once it is implemented. Checked x86_64-linux-gnu and i686-linux-gnu. * sysdeps/unix/sysv/linux/spawni.c (posix_spawn_args): Remove argc member. (maybe_script_execute): Remove function. (execve_compat, __spawni_clone, __spawnix_compat): New function. (__spawni_child): Remove maybe_script_execute call. (__spawnix): Remove magic stack slack constant with stack_slack identifier. (__spawni): Only allocates a variable stack when SPAWN_XFLAGS_TRY_SHELL is used. * posix/stackmap.h: New file. * sysdeps/ia64/nptl/pthreaddef.h (NEED_SEPARATE_REGISTER_STACK): Move to ... * sysdeps/ia64/stackinfo.h: ... here. --- posix/stackmap.h | 115 +++++++++++++ sysdeps/ia64/nptl/pthreaddef.h | 3 - sysdeps/ia64/stackinfo.h | 3 + sysdeps/unix/sysv/linux/spawni.c | 277 +++++++++++++++++++------------ 4 files changed, 285 insertions(+), 113 deletions(-) create mode 100644 posix/stackmap.h -- 2.17.1 diff --git a/posix/stackmap.h b/posix/stackmap.h new file mode 100644 index 0000000000..be500e378a --- /dev/null +++ b/posix/stackmap.h @@ -0,0 +1,115 @@ +/* Functions to create stack mappings for helper processes. + Copyright (C) 2019 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 _STACKMAP_H +#define _STACKMAP_H + +#include +#include +#include +#include + +static inline int +stack_prot (void) +{ + return (PROT_READ | PROT_WRITE + | ((GL(dl_stack_flags) & PF_X) ? PROT_EXEC : 0)); +} + +static inline size_t +stack_guard_size (void) +{ + return GLRO (dl_pagesize); +} + +/* Return a aligning mask based on system pagesize. */ +static inline size_t +stack_pagesize_m1_mask (void) +{ + size_t pagesize_m1 = __getpagesize () - 1; + return ~pagesize_m1; +} + +/* Return the guard page position on memory segment MEM with total size SIZE + and with a guard page of size GUARDIZE. */ +static inline void * +stack_guard_position (void *mem, size_t size, size_t guardsize) +{ +#ifdef NEED_SEPARATE_REGISTER_STACK + return mem + (((size - guardsize) / 2) & stack_pagesize_m1_mask ()); +#elif _STACK_GROWS_DOWN + return mem; +#elif _STACK_GROWS_UP + return (void *) (((uintptr_t)(mem + size)- guardsize) + & stack_pagesize_m1_mask ()); +#endif +} + +/* Setup the expected stack memory protection value (based on stack_prot) + for the memory segment MEM with size SIZE based on the guard page + GUARD with size GUARDSIZE. The memory segment is expected to be allocated + with PROT_NOTE. */ +static inline bool +stack_setup_prot (char *mem, size_t size, char *guard, size_t guardsize) +{ + const int prot = stack_prot (); + + char *guardend = guard + guardsize; +#if _STACK_GROWS_DOWN && !defined(NEED_SEPARATE_REGISTER_STACK) + /* As defined at guard_position, for architectures with downward stack + the guard page is always at start of the allocated area. */ + if (__mprotect (guardend, size - guardsize, prot) != 0) + return false; +#else + size_t mprots1 = (uintptr_t) guard - (uintptr_t) mem; + if (__mprotect (mem, mprots1, prot) != 0) + return false; + size_t mprots2 = ((uintptr_t) mem + size) - (uintptr_t) guardend; + if (__mprotect (guardend, mprots2, prot) != 0) + return false; +#endif + return true; +} + +/* Allocated a memory segment with size SIZE plus GUARSIZE with mmap and + setup the expected protection for both a guard page and the stack + itself. */ +static inline void * +stack_allocate (size_t size, size_t guardsize) +{ + const int prot = stack_prot (); + + /* If a guard page is required, avoid committing memory by first + allocate with PROT_NONE and then reserve with required permission + excluding the guard page. */ + void *mem = __mmap (NULL, size, (guardsize == 0) ? prot : PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + if (guardsize) + { + void *guard = stack_guard_position (mem, size, guardsize); + if (!stack_setup_prot (mem, size, guard, guardsize)) + { + __munmap (mem, size); + return MAP_FAILED; + } + } + + return mem; +} + +#endif /* _STACKMAP_H */ diff --git a/sysdeps/ia64/nptl/pthreaddef.h b/sysdeps/ia64/nptl/pthreaddef.h index bf52d5af62..11579f11b4 100644 --- a/sysdeps/ia64/nptl/pthreaddef.h +++ b/sysdeps/ia64/nptl/pthreaddef.h @@ -18,9 +18,6 @@ /* Default stack size. */ #define ARCH_STACK_DEFAULT_SIZE (32 * 1024 * 1024) -/* IA-64 uses a normal stack and a register stack. */ -#define NEED_SEPARATE_REGISTER_STACK - /* Required stack pointer alignment at beginning. */ #define STACK_ALIGN 16 diff --git a/sysdeps/ia64/stackinfo.h b/sysdeps/ia64/stackinfo.h index 6433a89945..d942426fcf 100644 --- a/sysdeps/ia64/stackinfo.h +++ b/sysdeps/ia64/stackinfo.h @@ -30,4 +30,7 @@ /* Default to a non-executable stack. */ #define DEFAULT_STACK_PERMS (PF_R|PF_W) +/* IA-64 uses a normal stack and a register stack. */ +#define NEED_SEPARATE_REGISTER_STACK + #endif /* stackinfo.h */ diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index ca7bf99825..0f7a8ca5df 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -23,10 +23,11 @@ #include #include #include -#include -#include -#include +#include #include +#include +#include +#include #include "spawn_int.h" /* The Linux implementation of posix_spawn{p} uses the clone syscall directly @@ -70,7 +71,6 @@ # define STACK(__stack, __stack_size) (__stack + __stack_size) #endif - struct posix_spawn_args { sigset_t oldmask; @@ -79,37 +79,11 @@ struct posix_spawn_args const posix_spawn_file_actions_t *fa; const posix_spawnattr_t *restrict attr; char *const *argv; - ptrdiff_t argc; char *const *envp; int xflags; int err; }; -/* Older version requires that shell script without shebang definition - to be called explicitly using /bin/sh (_PATH_BSHELL). */ -static void -maybe_script_execute (struct posix_spawn_args *args) -{ - if (SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15) - && (args->xflags & SPAWN_XFLAGS_TRY_SHELL) && errno == ENOEXEC) - { - char *const *argv = args->argv; - ptrdiff_t argc = args->argc; - - /* Construct an argument list for the shell. */ - char *new_argv[argc + 2]; - new_argv[0] = (char *) _PATH_BSHELL; - new_argv[1] = (char *) args->file; - if (argc > 1) - memcpy (new_argv + 2, argv + 1, argc * sizeof (char *)); - else - new_argv[2] = NULL; - - /* Execute the shell. */ - args->exec (new_argv[0], new_argv, args->envp); - } -} - /* Close all file descriptor up to FROM by interacting /proc/self/fd. */ static bool spawn_closefrom (int from) @@ -152,7 +126,7 @@ spawn_closefrom (int from) attributes, and file actions. It run on its own stack (provided by the posix_spawn call). */ static int -__spawni_child (void *arguments) +spawni_child (void *arguments) { struct posix_spawn_args *args = arguments; const posix_spawnattr_t *restrict attr = args->attr; @@ -330,11 +304,6 @@ __spawni_child (void *arguments) args->exec (args->file, args->argv, args->envp); - /* This is compatibility function required to enable posix_spawn run - script without shebang definition for older posix_spawn versions - (2.15). */ - maybe_script_execute (args); - fail: /* errno should have an appropriate non-zero value; otherwise, there's a bug in glibc or the kernel. For lack of an error code @@ -345,71 +314,12 @@ fail: _exit (SPAWN_ERROR); } -/* Spawn a new process executing PATH with the attributes describes in *ATTRP. - Before running the process perform the actions described in FILE-ACTIONS. */ static int -__spawnix (pid_t * pid, const char *file, - const posix_spawn_file_actions_t * file_actions, - const posix_spawnattr_t * attrp, char *const argv[], - char *const envp[], int xflags, - int (*exec) (const char *, char *const *, char *const *)) +spawni_clone (struct posix_spawn_args *args, void *stack, size_t stack_size, + pid_t *pid) { - pid_t new_pid; - struct posix_spawn_args args; int ec; - - /* To avoid imposing hard limits on posix_spawn{p} the total number of - arguments is first calculated to allocate a mmap to hold all possible - values. */ - ptrdiff_t argc = 0; - /* Linux allows at most max (0x7FFFFFFF, 1/4 stack size) arguments - to be used in a execve call. We limit to INT_MAX minus one due the - compatiblity code that may execute a shell script (maybe_script_execute) - where it will construct another argument list with an additional - argument. */ - ptrdiff_t limit = INT_MAX - 1; - while (argv[argc++] != NULL) - if (argc == limit) - { - errno = E2BIG; - return errno; - } - - int prot = (PROT_READ | PROT_WRITE - | ((GL (dl_stack_flags) & PF_X) ? PROT_EXEC : 0)); - - size_t argv_size = (argc * sizeof (void *)); - /* We need at least a few pages in case the compiler's stack checking is - enabled. In some configs, it is known to use at least 24KiB. We use - 32KiB to be "safe" from anything the compiler might do. Besides, the - extra pages won't actually be allocated unless they get used. - It also acts the slack for spawn_closefrom (including MIPS64 getdents64 - where it might use about 1k extra stack space. */ - argv_size += (32 * 1024); - size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize)); - void *stack = __mmap (NULL, stack_size, prot, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); - if (__glibc_unlikely (stack == MAP_FAILED)) - return errno; - - /* Disable asynchronous cancellation. */ - int state; - __libc_ptf_call (__pthread_setcancelstate, - (PTHREAD_CANCEL_DISABLE, &state), 0); - - /* Child must set args.err to something non-negative - we rely on - the parent and child sharing VM. */ - args.err = 0; - args.file = file; - args.exec = exec; - args.fa = file_actions; - args.attr = attrp ? attrp : &(const posix_spawnattr_t) { 0 }; - args.argv = argv; - args.argc = argc; - args.envp = envp; - args.xflags = xflags; - - __libc_signal_block_all (&args.oldmask); + pid_t new_pid; /* The clone flags used will create a new child that will run in the same memory space (CLONE_VM) and the execution of calling thread will be @@ -419,8 +329,8 @@ __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); + new_pid = CLONE (spawni_child, STACK (stack, stack_size), stack_size, + CLONE_VM | CLONE_VFORK | SIGCHLD, 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 @@ -433,7 +343,7 @@ __spawnix (pid_t * pid, const char *file, only in case of failure, so in case of premature termination due a signal args.err will remain zeroed and it will be up to caller to actually collect it. */ - ec = args.err; + ec = args->err; if (ec > 0) /* There still an unlikely case where the child is cancelled after setting args.err, due to a positive error value. Also there is @@ -446,14 +356,139 @@ __spawnix (pid_t * pid, const char *file, else ec = -new_pid; - __munmap (stack, stack_size); - if ((ec == 0) && (pid != NULL)) *pid = new_pid; - __libc_signal_restore_set (&args.oldmask); + return ec; +} - __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0); +#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15) +/* This is compatibility function required to enable posix_spawn run + script without shebang definition for older posix_spawn versions + (2.15). */ +static int +execve_compat (const char *filename, char *const argv[], char *const envp[]) +{ + __execve (filename, argv, envp); + + if (errno == ENOEXEC) + { + char *const *cargv = argv; + ptrdiff_t argc = 0; + while (cargv[argc++] != NULL); + + /* Construct an argument list for the shell. */ + char *new_argv[argc + 2]; + new_argv[0] = (char *) _PATH_BSHELL; + new_argv[1] = (char *) filename; + if (argc > 1) + memcpy (new_argv + 2, argv + 1, argc * sizeof (char *)); + else + new_argv[2] = NULL; + + /* Execute the shell. */ + __execve (new_argv[0], new_argv, envp); + } + + return -1; +} + +/* Allocates a stack using mmap to call clone. The stack size is based on + number of arguments since it would be used on compat mode which may call + execvpe/execve_compat. */ +static int +spawnix_compat (struct posix_spawn_args *args, pid_t *pid) +{ + char *const *argv = args->argv; + + /* To avoid imposing hard limits on posix_spawn{p} the total number of + arguments is first calculated to allocate a mmap to hold all possible + values. */ + ptrdiff_t argc = 0; + /* Linux allows at most max (0x7FFFFFFF, 1/4 stack size) arguments + to be used in a execve call. We limit to INT_MAX minus one due the + compatiblity code that may execute a shell script (maybe_script_execute) + where it will construct another argument list with an additional + argument. */ + ptrdiff_t limit = INT_MAX - 1; + while (argv[argc++] != NULL) + if (argc == limit) + { + errno = E2BIG; + return errno; + } + + size_t argv_size = (argc * sizeof (void *)); + /* We need at least a few pages in case the compiler's stack checking is + enabled. In some configs, it is known to use at least 24KiB. We use + 32KiB to be "safe" from anything the compiler might do. Besides, the + extra pages won't actually be allocated unless they get used. + It also acts the slack for spawn_closefrom (including MIPS64 getdents64 + where it might use about 1k extra stack space. */ + argv_size += (32 * 1024); + + /* Allocate a stack with an extra guard page. */ + size_t guard_size = stack_guard_size (); + size_t stack_size = guard_size + ALIGN_UP (argv_size, __getpagesize ()); + void *stack = stack_allocate (stack_size, guard_size); + if (__glibc_unlikely (stack == MAP_FAILED)) + return errno; + + int ec = spawni_clone (args, stack, stack_size, pid); + + __munmap (stack, stack_size); + + return ec; +} +#endif + +/* For SPAWN_XFLAGS_TRY_SHELL we need to execute a script even without + a shebang. To accomplish it we pass as callback to spawni_child + __execvpe (which call maybe_script_execute for such case) or + execve_compat (which mimics the semantic using execve). */ +static int +spawn_process (struct posix_spawn_args *args, pid_t *pid) +{ + int ec; + +#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15) + if (args->xflags & SPAWN_XFLAGS_TRY_SHELL) + { + args->exec = args->xflags & SPAWN_XFLAGS_USE_PATH + ? __execvpe : execve_compat; + ec = spawnix_compat (args, pid); + } + else +#endif + { + args->exec = args->xflags & SPAWN_XFLAGS_USE_PATH + ? __execvpex : __execve; + + /* spawni_clone stack usage need to take in consideration spawni_child + stack usage and subsequent functions called: + + - sigprocmask: might allocate an extra sigset_t (128 bytes). + - __libc_sigaction: allocate a struct kernel_sigaction (144 bytes on + 64-bit, 136 on 32-bit). + - __sched_setparam, __sched_setscheduler, __setsig, __setpgid, + local_seteuid, local_setegid, __close_nocancel, __getrlimit64, + __close_nocancel, __open_nocancel, __dup2, __chdir, __fchdir: + and direct syscall. + - __fcntl: wrapper only uses local variables. + - spawn_closefrom: uses up to 1024 bytes as local buffer + - __direntries_read + - __getdents64: MIPS64 uses up to buffer size used, 1024 in this + specific usage. + - __direntries_next: local variables. + - __close_nocancel: direct syscall. + - execvpe allocates at least (NAME_MAX + 1) + PATH_MAX to create the + combination of PATH entry and program name (1024 + 255 + 1). + + It allocates 2048 plus some stack for automatic variables and function + calls. */ + char stack[2560]; + ec = spawni_clone (args, stack, sizeof stack, pid); + } return ec; } @@ -462,12 +497,34 @@ __spawnix (pid_t * pid, const char *file, Before running the process perform the actions described in FILE-ACTIONS. */ int __spawni (pid_t * pid, const char *file, - const posix_spawn_file_actions_t * acts, + const posix_spawn_file_actions_t * file_actions, const posix_spawnattr_t * attrp, char *const argv[], char *const envp[], int xflags) { - /* It uses __execvpex to avoid run ENOEXEC in non compatibility mode (it - will be handled by maybe_script_execute). */ - return __spawnix (pid, file, acts, attrp, argv, envp, xflags, - xflags & SPAWN_XFLAGS_USE_PATH ? __execvpex :__execve); + /* Child must set args.err to something non-negative - we rely on + the parent and child sharing VM. */ + struct posix_spawn_args args = { + .err = 0, + .file = file, + .fa = file_actions, + .attr = attrp ? attrp : &(const posix_spawnattr_t) { 0 }, + .argv = argv, + .envp = envp, + .xflags = xflags + }; + + /* Disable asynchronous cancellation. */ + int state; + __libc_ptf_call (__pthread_setcancelstate, + (PTHREAD_CANCEL_DISABLE, &state), 0); + + __libc_signal_block_all (&args.oldmask); + + int ec = spawn_process (&args, pid); + + __libc_signal_restore_set (&args.oldmask); + + __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0); + + return ec; } From patchwork Wed Jul 31 18:31:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 170206 Delivered-To: patch@linaro.org Received: by 2002:ac9:2daa:0:0:0:0:0 with SMTP id g42csp6295000oce; Wed, 31 Jul 2019 11:32:12 -0700 (PDT) X-Google-Smtp-Source: APXvYqwdx23yoi0qNy9O86xbFI1r3BoiXYgbtvd+ZFZXCaL08sJcKpvgfb8ELlkkLA2G/K07pjTr X-Received: by 2002:a17:902:f01:: with SMTP id 1mr121416500ply.170.1564597932920; Wed, 31 Jul 2019 11:32:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1564597932; cv=none; d=google.com; s=arc-20160816; b=k98KhyrEnlbUzD5k/g6yr/+oVbRNg3I/4ocvNWaqBJWwvvr6ryvj+XXzPyJTBAssFZ 16Lz/XmqAPY8zuJYFDrlMdllIA577sMrqC76zjQTeiL6efbk7HYKgYj654mrg1q4LsaO Igek6qaNuMtfUHozvrN+fKSRj2FG5SbhzGP2KcHIcoSqYsMLLsGYnbSNV8BGjqyvKTDO a7dt29LT2Fvx9HHr7XF0jPI0y5Hs2pXd6BKnkm0ZZs1xb1PLRY927EpunPF1J46YfMb5 JdnI3Zb/GL5d6B7inrJMp9YjbPEnpsxdlQgho4YH6R2YgmfZYP4/jwqrCtjxmnPSJpye shBw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:to:from :dkim-signature:delivered-to:sender:list-help:list-post:list-archive :list-subscribe:list-unsubscribe:list-id:precedence:mailing-list :dkim-signature:domainkey-signature; bh=dsIklHcmbonLRctveIVB5yxaOgCqI9ZpW46MYXiXOkg=; b=OvQSM01AtvpsXp+JclabSDueVcwq5qsOe4F66UiMLks4AOA4bs0XALe2QJZYgGJl9R 7WSHIBUOXHpJr6U1xMIk92UmrCJri7QQmy6APfdlhQNyv+dSIAVfHlz9zIkdzisM9jSC Azh1iXXaW3D5hLRRMeH4/DlFo7SwCSVdp/w/trY+ws9yu1WI3bBNtw8AXFFLpn45trmB TnB+siCRD/KjDmdx+MllR0T8PwIb3Cq6Odn8VgnleBIPa/LJ75ytYfLeif93NUda/zeL ZZQMJ8I6FgRPyfkb7gjcjLCguyudvdZc2kc0RT8764l/A8PV8ayWDZUVVbfLepfL94qB eglA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=KWgap257; dkim=pass header.i=@linaro.org header.s=google header.b=rcch0DeC; spf=pass (google.com: domain of libc-alpha-return-104075-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-104075-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id c12si2900856pgl.252.2019.07.31.11.32.12 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 31 Jul 2019 11:32:12 -0700 (PDT) Received-SPF: pass (google.com: domain of libc-alpha-return-104075-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=KWgap257; dkim=pass header.i=@linaro.org header.s=google header.b=rcch0DeC; spf=pass (google.com: domain of libc-alpha-return-104075-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-104075-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; q=dns; s=default; b=F3Bg2i515qQD/0gAvditAnUSerMpqzx 6ojrONhwqtX0j8N60pljwbbe14xSNGGolFkNy1MqjuJ9jeF2n+lRfdPfw+H/+/Fs Z9GTjtciqw5Cvo4udFBLaBcZn0N/jwlTfRdcztBgSIqKeqGMmcuE3KnnwzJz2jSo D4tF0w7i8BVs= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; s=default; bh=GKmb/0ptq8fkf3k6VXcHwxoIgH8=; b=KWgap 257phPdR9ArBbT6Qlmhm54HNclVA143+VPbY9GwVFgYoMIzYLcVW/30zG5pzf66v oIZYnd0nZRpgt0WehxJR2u/Cq4dVhbWXdLmCmCRZYK+O36w6ayoPl5kYX8UkyLmj NafFL+pwWzUlvsNvBGcvSrs5MYZSurxsvrQMYM= Received: (qmail 122997 invoked by alias); 31 Jul 2019 18:31:51 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 122900 invoked by uid 89); 31 Jul 2019 18:31:51 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-15.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=Plus, disposition, *restrict X-HELO: mail-qk1-f196.google.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references; bh=dsIklHcmbonLRctveIVB5yxaOgCqI9ZpW46MYXiXOkg=; b=rcch0DeCyb4nDxyOfO4TUdlONPbqCbTGBQYdA1cN4dVO5HFCIxNT5QWh4Pclkn/LhX 4LS3JAVFsDGOqQaRsxsbVhV6bJjkQpTSO5xQOZaTGp39/kLQSuSVgE+7OphVW+Ub/Y4M //KB4DkjwZ91eDvrDgZqskjshBps6MHJdHN8HrxEn+3AbUw7WS3swla9nX6nzFkl7kB1 2luCiWOUmK8wmnYfq/yALIr+VGl/C2RMORxjDxTGfhg+XeWRiK5Bb7MoKGD2T9XzIUjg EOLVavxr/kbsxFTtF3d0SB/oWMFDw/14smDEJDVCB9mx6aE/TUALpPKatmYM9ebQD1LQ +AxQ== Return-Path: From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 4/5] linux: Optimize posix_spawn spurious sigaction calls Date: Wed, 31 Jul 2019 15:31:35 -0300 Message-Id: <20190731183136.21545-4-adhemerval.zanella@linaro.org> In-Reply-To: <20190731183136.21545-1-adhemerval.zanella@linaro.org> References: <20190731183136.21545-1-adhemerval.zanella@linaro.org> The child helper process on Linux posix_spawn child must ensure that no signal handler are enabled, so the signal disposition must be either SIG_DFL or SIG_IGN. However, it requires a sigprocmask to obtain the current signal mask and at least _NSIG sigaction calls to reset the signal handlers for each posix_spawn call. This patch optimizes it by tracking on sigaction implementation when a signal action is set different than SIG_DFL or SIG_IGN. It allows remove a sigprocmask call and isse sigaction to reset the disposition only the signals that has non-default actions set. It might incur in false positive, since it not easy to remove bits from the mask without race conditions, but it does not allow false negative since the mask is updated atomically prior the syscall. The false positive incur in just extra sigactions on posix_spawn. Checked on x86_64 and i686. * include/atomic.h (atomic_fetch_or_seq_cst, atomic_fetch_or_seq_cst): New macros. * posix/Makefile (tests): Add tst-spawn6. * posix/tst-spawn6.c: New file. * sysdeps/generic/sigsetops.h (__sigorset_atomic): New macro. * sysdeps/unix/sysv/linux/internal-signals.h (__get_sighandler_set): New prototype. * sysdeps/unix/sysv/linux/sigaction.c (__get_sighandler_set): New function. (__libc_sigaction): Set the internal handler_set for a new action. * sysdeps/unix/sysv/linux/sigsetops.h (__sigorset_atomic, __sigaddset_atomic): New macros. * sysdeps/unix/sysv/linux/spawni.c (spawni_child): Replace __sigprocmask with __get_sighandler_set. --- include/atomic.h | 10 + posix/Makefile | 4 +- posix/tst-spawn6.c | 220 +++++++++++++++++++++ sysdeps/generic/sigsetops.h | 7 + sysdeps/unix/sysv/linux/internal-signals.h | 3 + sysdeps/unix/sysv/linux/sigaction.c | 17 ++ sysdeps/unix/sysv/linux/sigsetops.h | 15 ++ sysdeps/unix/sysv/linux/spawni.c | 9 +- 8 files changed, 278 insertions(+), 7 deletions(-) create mode 100644 posix/tst-spawn6.c -- 2.17.1 diff --git a/include/atomic.h b/include/atomic.h index ee1978eb3b..72609efde9 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -646,6 +646,9 @@ void __atomic_link_error (void); # define atomic_fetch_or_release(mem, operand) \ ({ __atomic_check_size((mem)); \ __atomic_fetch_or ((mem), (operand), __ATOMIC_RELEASE); }) +# define atomic_fetch_or_seq_cst(mem, operand) \ + ({ __atomic_check_size((mem)); \ + __atomic_fetch_or ((mem), (operand), __ATOMIC_SEQ_CST); }) # define atomic_fetch_xor_release(mem, operand) \ ({ __atomic_check_size((mem)); \ @@ -791,6 +794,13 @@ void __atomic_link_error (void); ({ atomic_thread_fence_release (); \ atomic_fetch_or_acquire ((mem), (operand)); }) # endif +# ifndef atomic_fetch_or_seq_cst +# define atomic_fetch_or_seq_cst(mem, operand) \ + ({ atomic_thread_fence_acquire (); \ + atomic_fetch_or_relaxed ((mem), (operand)); \ + atomic_thread_fence_release (); }) +# endif + # ifndef atomic_fetch_xor_release /* Failing the atomic_compare_exchange_weak_release reloads the value in diff --git a/posix/Makefile b/posix/Makefile index 1ac41ad85a..131ae052fd 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -102,7 +102,8 @@ tests := test-errno tstgetopt testfnm runtests runptests \ tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \ tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \ bug-regex38 tst-regcomp-truncated tst-spawn-chdir \ - tst-spawn5 + tst-spawn5 \ + tst-spawn6 tests-internal := bug-regex5 bug-regex20 bug-regex33 \ tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \ tst-glob_lstat_compat tst-spawn4-compat @@ -255,6 +256,7 @@ tst-exec-ARGS = -- $(host-test-program-cmd) tst-exec-static-ARGS = $(tst-exec-ARGS) tst-execvpe5-ARGS = -- $(host-test-program-cmd) tst-spawn-ARGS = -- $(host-test-program-cmd) +tst-spawn6-ARGS = -- $(host-test-program-cmd) tst-spawn-static-ARGS = $(tst-spawn-ARGS) tst-spawn5-ARGS = -- $(host-test-program-cmd) tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); pwd` $(objpfx)tst-dir diff --git a/posix/tst-spawn6.c b/posix/tst-spawn6.c new file mode 100644 index 0000000000..466e66f104 --- /dev/null +++ b/posix/tst-spawn6.c @@ -0,0 +1,220 @@ +/* Tests for posix_spawn signal handling. + Copyright (C) 2019 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 +#include +#include +#include + +/* Nonzero if the program gets called via `exec'. */ +static int restart; +#define CMDLINE_OPTIONS \ + { "restart", no_argument, &restart, 1 }, + +enum spawn_test_t +{ + SPAWN_SETSIGMASK, + SPAWN_SETSIGDEF +}; + +static int signal_to_check[] = +{ + SIGHUP, SIGINT, SIGALRM, SIGUSR2 +}; + +/* Called on process re-execution. */ +static int +handle_restart (enum spawn_test_t test) +{ + switch (test) + { + case SPAWN_SETSIGMASK: + { + sigset_t mask; + sigprocmask (SIG_BLOCK, NULL, &mask); + for (int i = 0; i < array_length (signal_to_check); i++) + if (sigismember (&mask, signal_to_check[i]) != 1) + exit (EXIT_FAILURE); + } + break; + case SPAWN_SETSIGDEF: + { + for (int i = 0; i < array_length (signal_to_check); i++) + { + struct sigaction act; + if (sigaction (signal_to_check[i], NULL, &act) != 0) + exit (EXIT_FAILURE); + if (act.sa_handler != SIG_DFL) + exit (EXIT_FAILURE); + } + } + break; + } + + return 0; +} + +/* Common argument used for process re-execution. */ +static char *initial_spargv[5]; +static size_t initial_spargv_size; + +/* Re-execute the test process with both '--direct', '--restart', and the + TEST (as integer value) as arguments. */ +static void +reexecute (enum spawn_test_t test, const posix_spawnattr_t *attrp) +{ + char *spargv[8]; + int i; + + for (i = 0; i < initial_spargv_size; i++) + spargv[i] = initial_spargv[i]; + /* Three digits per byte plus null terminator. */ + char teststr[3 * sizeof (test) + 1]; + snprintf (teststr, array_length (teststr), "%d", test); + spargv[i++] = teststr; + spargv[i] = NULL; + TEST_VERIFY (i < 8); + + pid_t pid; + int status; + + TEST_COMPARE (posix_spawn (&pid, spargv[0], NULL, attrp, spargv, environ), + 0); + TEST_COMPARE (xwaitpid (pid, &status, 0), pid); + TEST_VERIFY (WIFEXITED (status)); + TEST_VERIFY (!WIFSIGNALED (status)); + TEST_COMPARE (WEXITSTATUS (status), 0); +} + +/* Test if POSIX_SPAWN_SETSIGMASK change the spawn process signal mask to + the value blocked signals defined by SIGNAL_TO_CHECK signals. */ +static void +do_test_setsigmask (void) +{ + posix_spawnattr_t attr; + /* posix_spawnattr_init does not fail. */ + posix_spawnattr_init (&attr); + + { + sigset_t mask; + TEST_COMPARE (sigemptyset (&mask), 0); + for (int i = 0; i < array_length (signal_to_check); i++) + TEST_COMPARE (sigaddset (&mask, signal_to_check[i]), 0); + TEST_COMPARE (posix_spawnattr_setsigmask (&attr, &mask), 0); + TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSIGMASK), 0); + } + + /* Change current mask to be different than the one asked for spawned + process. */ + { + sigset_t empty_mask, current_mask; + TEST_COMPARE (sigemptyset (&empty_mask), 0); + TEST_COMPARE (sigprocmask (SIG_BLOCK, &empty_mask, ¤t_mask), 0); + + reexecute (SPAWN_SETSIGMASK, &attr); + + TEST_COMPARE (sigprocmask (SIG_SETMASK, ¤t_mask, NULL), 0); + } +} + +/* Test if POSIX_SPAWN_SETSIGDEF change the spawn process signal actions + defined by SIGNAL_TO_CHECK signals to default actions. */ +static void +do_test_setsigdef (void) +{ + posix_spawnattr_t attr; + /* posix_spawnattr_init does not fail. */ + posix_spawnattr_init (&attr); + + { + sigset_t mask; + TEST_COMPARE (sigemptyset (&mask), 0); + for (int i = 0; i < array_length (signal_to_check); i++) + TEST_COMPARE (sigaddset (&mask, signal_to_check[i]), 0); + TEST_COMPARE (posix_spawnattr_setsigdefault (&attr, &mask), 0); + TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSIGDEF), 0); + } + + /* Change current signal disposition to be different than the one asked for + spawned process. */ + struct sigaction default_act[array_length (signal_to_check)]; + { + sigset_t empty_mask; + TEST_COMPARE (sigemptyset (&empty_mask), 0); + for (int i = 0; i < array_length (signal_to_check); i++) + TEST_COMPARE (sigaction (signal_to_check[i], + &((struct sigaction) { .sa_handler = SIG_IGN, + .sa_mask = empty_mask, + .sa_flags = 0 }), + &default_act[i]), + 0); + } + + reexecute (SPAWN_SETSIGDEF, &attr); + + /* Restore signal dispositions. */ + for (int i = 0; i < array_length (signal_to_check); i++) + TEST_COMPARE (sigaction (signal_to_check[i], &default_act[i], NULL), 0); +} + +static int +do_test (int argc, char *argv[]) +{ + /* We must have one or four parameters left if called initially: + + path for ld.so optional + + "--library-path" optional + + the library path optional + + the application name + + Plus one parameter to indicate which test to execute through + re-execution. + + So for default usage without --enable-hardcoded-path-in-tests, it + will be called initially with 5 arguments and later with 2. For + --enable-hardcoded-path-in-tests it will be called with 2 arguments + regardless. */ + + if (argc != (restart ? 2 : 5) && argc != 2) + FAIL_EXIT1 ("wrong number of arguments (%d)", argc); + + if (restart) + return handle_restart (atoi (argv[1])); + + { + int i; + for (i = 0; i < (argc == 5 ? 4 : 1); i++) + initial_spargv[i] = argv[i + 1]; + initial_spargv[i++] = (char *) "--direct"; + initial_spargv[i++] = (char *) "--restart"; + initial_spargv_size = i; + } + + do_test_setsigmask (); + do_test_setsigdef (); + + return 0; +} + +#define TEST_FUNCTION_ARGV do_test +#include diff --git a/sysdeps/generic/sigsetops.h b/sysdeps/generic/sigsetops.h index ddeeb0b0d5..9cae11771b 100644 --- a/sysdeps/generic/sigsetops.h +++ b/sysdeps/generic/sigsetops.h @@ -66,6 +66,13 @@ 0; \ })) +# define __sigorset_atomic(set) \ + (__extension__ ({ \ + __sigset_t __mask = __sigmask (sig); \ + atomic_fetch_or_seq_cst (set, mask); \ + 0; \ + })) + # define __sigdelset(set, sig) \ (__extension__ ({ \ __sigset_t __mask = __sigmask (sig); \ diff --git a/sysdeps/unix/sysv/linux/internal-signals.h b/sysdeps/unix/sysv/linux/internal-signals.h index 3562011d21..385442f81e 100644 --- a/sysdeps/unix/sysv/linux/internal-signals.h +++ b/sysdeps/unix/sysv/linux/internal-signals.h @@ -88,4 +88,7 @@ __libc_signal_restore_set (const sigset_t *set) /* Used to communicate with signal handler. */ extern struct xid_command *__xidcmd attribute_hidden; +/* Used to obtained the modified signal handlers. */ +extern void __get_sighandler_set (sigset_t *set) attribute_hidden; + #endif diff --git a/sysdeps/unix/sysv/linux/sigaction.c b/sysdeps/unix/sysv/linux/sigaction.c index 52722b08ae..3bcf3946ab 100644 --- a/sysdeps/unix/sysv/linux/sigaction.c +++ b/sysdeps/unix/sysv/linux/sigaction.c @@ -20,6 +20,7 @@ #include #include +#include #include /* New ports should not define the obsolete SA_RESTORER, however some @@ -36,6 +37,13 @@ # define STUB(act, sigsetsize) (sigsetsize) #endif +static sigset_t handler_set; + +void __get_sighandler_set (sigset_t *set) +{ + *set = handler_set; +} + /* If ACT is not NULL, change the action for SIG to *ACT. If OACT is not NULL, put the old action for SIG in *OACT. */ int @@ -47,6 +55,15 @@ __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact) if (act) { + /* Tracks which signal had a signal handler set different from default + (SIG_DFL/SIG_IGN). It allows optimize posix_spawn to reset only + those signals. It might incur in false positive, since it not easy + to remove bits from the mask without race conditions, but it does not + allow false negative since the mask is updated atomically prior the + syscall. The false positive incur in just extra sigactions on + posix_spawn. */ + if (act->sa_handler != SIG_DFL && act->sa_handler != SIG_IGN) + __sigaddset_atomic (&handler_set, sig); kact.k_sa_handler = act->sa_handler; memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t)); kact.sa_flags = act->sa_flags; diff --git a/sysdeps/unix/sysv/linux/sigsetops.h b/sysdeps/unix/sysv/linux/sigsetops.h index 713d4840d8..6c98c83e42 100644 --- a/sysdeps/unix/sysv/linux/sigsetops.h +++ b/sysdeps/unix/sysv/linux/sigsetops.h @@ -20,6 +20,7 @@ #define _SIGSETOPS_H 1 #include +#include /* Return a mask that includes the bit for SIG only. */ # define __sigmask(sig) \ @@ -80,6 +81,12 @@ (void)0; \ })) +# define __sigorset_atomic(dest, left, right) \ + (__extension__ ({ \ + atomic_fetch_or_seq_cst (dest, left, right); \ + 0; \ + })) + /* These macros needn't check for a bogus signal number; error checking is done in the non-__ versions. */ # define __sigismember(set, sig) \ @@ -97,6 +104,14 @@ (void)0; \ })) +# define __sigaddset_atomic(set, sig) \ + (__extension__ ({ \ + unsigned long int __mask = __sigmask (sig); \ + unsigned long int __word = __sigword (sig); \ + atomic_fetch_or_seq_cst (&((set)->__val[__word]), __mask); \ + (void)0; \ + })) + # define __sigdelset(set, sig) \ (__extension__ ({ \ unsigned long int __mask = __sigmask (sig); \ diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index 0f7a8ca5df..264edd09c6 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -132,17 +132,14 @@ spawni_child (void *arguments) const posix_spawnattr_t *restrict attr = args->attr; const posix_spawn_file_actions_t *file_actions = args->fa; - /* The child must ensure that no signal handler are enabled because it shared + /* The child must ensure that no signal handler are enabled because it share memory with parent, so the signal disposition must be either SIG_DFL or - SIG_IGN. It does by iterating over all signals and although it could - possibly be more optimized (by tracking which signal potentially have a - signal handler), it might requires system specific solutions (since the - sigset_t data type can be very different on different architectures). */ + SIG_IGN. */ struct sigaction sa; memset (&sa, '\0', sizeof (sa)); sigset_t hset; - __sigprocmask (SIG_BLOCK, 0, &hset); + __get_sighandler_set (&hset); for (int sig = 1; sig < _NSIG; ++sig) { if ((attr->__flags & POSIX_SPAWN_SETSIGDEF) From patchwork Wed Jul 31 18:31:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 170208 Delivered-To: patch@linaro.org Received: by 2002:ac9:2daa:0:0:0:0:0 with SMTP id g42csp6295305oce; Wed, 31 Jul 2019 11:32:35 -0700 (PDT) X-Google-Smtp-Source: APXvYqxIHwJnDzDcsucQpTHUKnPhl1HT6NuwrkvHlqTCZrMe8QZjuHVOPg8RpIv4NxYmRjuiZ65g X-Received: by 2002:a65:6448:: with SMTP id s8mr115609654pgv.223.1564597955470; Wed, 31 Jul 2019 11:32:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1564597955; cv=none; d=google.com; s=arc-20160816; b=fv8OPAbeHWjQKlezILcibsd9ac0NFXj7n5C7orcgHwHAavzHt68pUCl+0DyLQqAcKq 58LPuShu5HHlJfw251C3Zj7TYYt4toBTM9pTuWVRfr/MAZgRiWaHtJCxagLAN4bBxWjj HzEkD5vz7IGQFvOLcIBprKPdjaTjT0k9rx3pVSDm3jElNHgM2vHeL57xLaGxRdUxGacw WSSQLByks4sVuingV23hU/1Etnrwi/QvW5lV/S2FqWHGbuZqEwbeGT25DKlUmVhgp3qD pCCCqOk2iTA5nTs4TsCrZ4ZkOceM+g78c6XsR4wxsxILJIdeJtC32VgRFZFL1IrUXnO2 vL4Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:to:from :dkim-signature:delivered-to:sender:list-help:list-post:list-archive :list-subscribe:list-unsubscribe:list-id:precedence:mailing-list :dkim-signature:domainkey-signature; bh=ZGO+zPkgN+xCDW5A9XtVNZsEB1KOeOtWpXUTblkkQHc=; b=bJIXQ5tjqDNJ7p43h58xht07C6NF8JVbyEekvwl7GqODFrNs5VGmq6xMva9np2Fp86 cT423H9IuXeNsCIBfrXreitjl0biuAPIa94Qhn0wjfi0SfsZ1NWyTJUe9rfz0+U5U1oM oB6pge0V02YcYZogyyiFrHAYQB1Wb8cDjZCplaOHyBiqbM/opxJULBIETaoupa090omT Z0l8+GpsqNqBThBaTf66lGxNCPIaotuk2If6HX34JOHDugK105nDxQQxYR9C8kof1FIv eWRXMzvCyL+CPZeDOddAV/eg87Wr6JP2jpv7VsG5hKjTHvvKrlNpmKfHcvYxPu93ZAbn LHmA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=Y3OJ18Bm; dkim=pass header.i=@linaro.org header.s=google header.b=OU3rTdKq; spf=pass (google.com: domain of libc-alpha-return-104077-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-104077-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id o19si19191649pgv.497.2019.07.31.11.32.35 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 31 Jul 2019 11:32:35 -0700 (PDT) Received-SPF: pass (google.com: domain of libc-alpha-return-104077-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=Y3OJ18Bm; dkim=pass header.i=@linaro.org header.s=google header.b=OU3rTdKq; spf=pass (google.com: domain of libc-alpha-return-104077-patch=linaro.org@sourceware.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="libc-alpha-return-104077-patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; q=dns; s=default; b=aO3+8z69JPgz4HYa+OF4TFZ4Wl/5Z1s QkutBVMOH9yfhe4VpsXpHVO3JSVqKbOt7ciI+mKlbLt5E3qmLQGsRCY3vdqcxCQb snLgUOsIxWA50F2OrgeN0iLK6Tjkvevhy4PVBJEuQaqrI8HjMBFDDzUg608Aq3YA eamDnfmvgcDA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:in-reply-to :references; s=default; bh=hCh5HCtI9qOTqUyxqbGjRctqvHU=; b=Y3OJ1 8Bmm9ry+fUdMaz+AHy6thCUq5qQcmuWX3h6Wk8pVBm5ie8vnQpZysPfPLsHRJikr dijX5hB64992T1HmCriMpGmyWwi0+7bgQSAC2o9e2Z2xP9QEnGdnIelG+hVicleM /d5raPR9lFcjjYagxMm89tnNYGFxh/1A8yMKVk= Received: (qmail 123304 invoked by alias); 31 Jul 2019 18:31:53 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 123238 invoked by uid 89); 31 Jul 2019 18:31:53 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-15.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=HOME, puts X-HELO: mail-qt1-f194.google.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references; bh=ZGO+zPkgN+xCDW5A9XtVNZsEB1KOeOtWpXUTblkkQHc=; b=OU3rTdKq+b/oZlSMxXCmaDpIqLjOV/2LnPU+FAmM01Sn7gP97l0u9PGfgpE1nfyu1F TthO1hsoi5sC8wxic5ci1nK3mjzex+o2t2tmZOTbm4Ln2HLWCTCARSl1axlF+tA86tzD AXcRKKeJaOynIBgBR6BykxfY7ZJ0fZDtUyb04vt/0sfKZEJ5VrVARJWtW0w4YPxmU1uy E163yWKS7Z/QE9luEzVqvqobqcK2vdowIBM0dKo4RCyY+A5bSK+BzGnh6pi+kb1fEaQD ufV8dN7Dt1qh8xtxL6EsXGPUkghBg3QzAnF+sz7ZsxZ7etq0IjJKNcyR/M1oeeXeqUtL V+hg== Return-Path: From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH v2 5/5] posix: Use posix_spawn for wordexp Date: Wed, 31 Jul 2019 15:31:36 -0300 Message-Id: <20190731183136.21545-5-adhemerval.zanella@linaro.org> In-Reply-To: <20190731183136.21545-1-adhemerval.zanella@linaro.org> References: <20190731183136.21545-1-adhemerval.zanella@linaro.org> Change from previous version: - Use libsupport and remove atfork usage on posix/wordexp-test.c. -- This patch replaces the fork+exec by posix_spawn on wordexp, which allows a better scability on Linux and simplifies the thread cancellation handling. The only change which can not be implemented with posix_spawn the /dev/null check to certify it is indeed the expected device. I am not sure how effetive this check is since /dev/null tampering means something very wrong with the system and this is the least of the issues. My view is the tests is really out of the place and the hardening provided is minimum. If the idea is still to provide such check, I think a possibilty would be to open /dev/null, check it, add a dup2 file action, and close the file descriptor. Checked on powerpc64le-linux-gnu and x86_64-linux-gnu. * include/spawn.h (__posix_spawn_file_actions_addopen): New prototype. * posix/spawn_faction_addopen.c (posix_spawn_file_actions_addopen): Add internal alias. * posix/wordexp.c (create_environment, free_environment): New functions. (exec_comm_child, exec_comm): Use posix_spawn instead of fork+exec. * posix/wordexp-test.c: Use libsupport and remove atfork usage. --- include/spawn.h | 3 + posix/spawn_faction_addopen.c | 8 +- posix/wordexp-test.c | 142 +++++++++-------------------- posix/wordexp.c | 167 ++++++++++++++++------------------ 4 files changed, 129 insertions(+), 191 deletions(-) -- 2.17.1 diff --git a/include/spawn.h b/include/spawn.h index 7fdd965bd7..4a0b1849da 100644 --- a/include/spawn.h +++ b/include/spawn.h @@ -11,6 +11,9 @@ __typeof (posix_spawn_file_actions_addclose) __typeof (posix_spawn_file_actions_adddup2) __posix_spawn_file_actions_adddup2 attribute_hidden; +__typeof (posix_spawn_file_actions_addopen) + __posix_spawn_file_actions_addopen attribute_hidden; + __typeof (posix_spawn_file_actions_destroy) __posix_spawn_file_actions_destroy attribute_hidden; diff --git a/posix/spawn_faction_addopen.c b/posix/spawn_faction_addopen.c index 742eb9526d..2e598de300 100644 --- a/posix/spawn_faction_addopen.c +++ b/posix/spawn_faction_addopen.c @@ -25,9 +25,9 @@ /* Add an action to FILE-ACTIONS which tells the implementation to call `open' for the given file during the `spawn' call. */ int -posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions, - int fd, const char *path, int oflag, - mode_t mode) +__posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions, + int fd, const char *path, int oflag, + mode_t mode) { struct __spawn_action *rec; @@ -60,3 +60,5 @@ posix_spawn_file_actions_addopen (posix_spawn_file_actions_t *file_actions, return 0; } +weak_alias (__posix_spawn_file_actions_addopen, + posix_spawn_file_actions_addopen) diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c index 10a0768a6b..ef780b0a65 100644 --- a/posix/wordexp-test.c +++ b/posix/wordexp-test.c @@ -15,39 +15,21 @@ License along with the GNU C Library; if not, see . */ -#include -#include -#include +#include +#include #include -#include #include -#include -#include #include #include -#include +#include + #include -#include +#include +#include +#include #define IFS " \n\t" -extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *); - -static int __app_register_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void)) -{ - return __register_atfork (prepare, parent, child, __dso_handle); -} - -/* Number of forks seen. */ -static int registered_forks; - -/* For each fork increment the fork count. */ -static void -register_fork (void) -{ - registered_forks++; -} - struct test_case_struct { int retval; @@ -57,7 +39,7 @@ struct test_case_struct size_t wordc; const char *wordv[10]; const char *ifs; -} test_case[] = +} static test_case[] = { /* Simple word- and field-splitting */ { 0, NULL, "one", 0, 1, { "one", }, IFS }, @@ -238,8 +220,6 @@ struct test_case_struct { WRDE_SYNTAX, NULL, "${", 0, 0, { NULL, }, IFS }, /* BZ 18043 */ { WRDE_SYNTAX, NULL, "L${a:", 0, 0, { NULL, }, IFS }, /* BZ 18043#c4 */ { WRDE_SYNTAX, NULL, "$[1/0]", WRDE_NOCMD, 0, {NULL, }, IFS }, /* BZ 18100 */ - - { -1, NULL, NULL, 0, 0, { NULL, }, IFS }, }; static int testit (struct test_case_struct *tc); @@ -256,16 +236,14 @@ command_line_test (const char *words) printf ("we_wordv[%d] = \"%s\"\n", i, we.we_wordv[i]); } -int -main (int argc, char *argv[]) +static int +do_test (int argc, char *argv[]) { - const char *globfile[] = { "one", "two", "three", NULL }; + const char *globfile[] = { "one", "two", "three" }; char tmpdir[32]; struct passwd *pw; const char *cwd; int test; - int fail = 0; - int i; struct test_case_struct ts; if (argc > 1) @@ -278,30 +256,18 @@ main (int argc, char *argv[]) /* Set up arena for pathname expansion */ tmpnam (tmpdir); - if (mkdir (tmpdir, S_IRWXU) || chdir (tmpdir)) - return -1; - else - { - int fd; + xmkdir (tmpdir, S_IRWXU); + TEST_VERIFY_EXIT (chdir (tmpdir) == 0); - for (i = 0; globfile[i]; ++i) - if ((fd = creat (globfile[i], S_IRUSR | S_IWUSR)) == -1 - || close (fd)) - return -1; - } - - /* If we are not allowed to do command substitution, we install - fork handlers to verify that no forks happened. No forks should - happen at all if command substitution is disabled. */ - if (__app_register_atfork (register_fork, NULL, NULL) != 0) + for (int i = 0; i < array_length (globfile); ++i) { - printf ("Failed to register fork handler.\n"); - return -1; + int fd = xopen (globfile[i], O_WRONLY|O_CREAT|O_TRUNC, + S_IRUSR | S_IWUSR); + xclose (fd); } - for (test = 0; test_case[test].retval != -1; test++) - if (testit (&test_case[test])) - ++fail; + for (test = 0; test < array_length (test_case); test++) + TEST_COMPARE (testit (&test_case[test]), 0); /* Tilde-expansion tests. */ pw = getpwnam ("root"); @@ -315,8 +281,7 @@ main (int argc, char *argv[]) ts.wordv[0] = pw->pw_dir; ts.ifs = IFS; - if (testit (&ts)) - ++fail; + TEST_COMPARE (testit (&ts), 0); ts.retval = 0; ts.env = pw->pw_dir; @@ -326,8 +291,7 @@ main (int argc, char *argv[]) ts.wordv[0] = "x"; ts.ifs = IFS; - if (testit (&ts)) - ++fail; + TEST_COMPARE (testit (&ts), 0); } /* "~" expands to value of $HOME when HOME is set */ @@ -342,8 +306,7 @@ main (int argc, char *argv[]) ts.wordv[1] = "/dummy/home/foo"; ts.ifs = IFS; - if (testit (&ts)) - ++fail; + TEST_COMPARE (testit (&ts), 0); /* "~" expands to home dir from passwd file if HOME is not set */ @@ -359,8 +322,7 @@ main (int argc, char *argv[]) ts.wordv[0] = pw->pw_dir; ts.ifs = IFS; - if (testit (&ts)) - ++fail; + TEST_COMPARE (testit (&ts), 0); } /* Integer overflow in division. */ @@ -375,37 +337,32 @@ main (int argc, char *argv[]) "18446744073709551616", "170141183460469231731687303715884105728", "340282366920938463463374607431768211456", - NULL }; - for (const char *const *num = numbers; *num; ++num) + for (int i = 0; i < array_length (numbers); i++) { wordexp_t p; char pattern[256]; - snprintf (pattern, sizeof (pattern), "$[(-%s)/(-1)]", *num); + snprintf (pattern, sizeof (pattern), "$[(-%s)/(-1)]", numbers[i]); int ret = wordexp (pattern, &p, WRDE_NOCMD); if (ret == 0) { - if (p.we_wordc != 1 || strcmp (p.we_wordv[0], *num) != 0) - { - printf ("Integer overflow for \"%s\" failed", pattern); - ++fail; - } + TEST_COMPARE (p.we_wordc, 1); + TEST_COMPARE (strcmp (p.we_wordv[0], numbers[i]), 0); wordfree (&p); } - else if (ret != WRDE_SYNTAX) + else { - printf ("Integer overflow for \"%s\" failed with %d", - pattern, ret); - ++fail; + TEST_COMPARE (ret, WRDE_SYNTAX); + if (ret != WRDE_SYNTAX) + printf ("Integer overflow for \"%s\" failed with %d", + pattern, ret); } } } - puts ("tests completed, now cleaning up"); - /* Clean up */ - for (i = 0; globfile[i]; ++i) + for (int i = 0; i < array_length (globfile); ++i) remove (globfile[i]); if (cwd == NULL) @@ -414,26 +371,17 @@ main (int argc, char *argv[]) chdir (cwd); rmdir (tmpdir); - printf ("tests failed: %d\n", fail); - - return fail != 0; + return 0; } static const char * at_page_end (const char *words) { const int pagesize = getpagesize (); - char *start = mmap (0, 2 * pagesize, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + char *start = xmmap (0, 2 * pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1); - if (start == MAP_FAILED) - return start; - - if (mprotect (start + pagesize, pagesize, PROT_NONE)) - { - munmap (start, 2 * pagesize); - return MAP_FAILED; - } + xmprotect (start + pagesize, pagesize, PROT_NONE); /* Includes terminating NUL. */ const size_t words_size = strlen (words) + 1; @@ -472,9 +420,6 @@ testit (struct test_case_struct *tc) fflush (NULL); const char *words = at_page_end (tc->words); - if (tc->flags & WRDE_NOCMD) - registered_forks = 0; - if (tc->flags & WRDE_APPEND) { /* initial wordexp() call, to be appended to */ @@ -486,13 +431,6 @@ testit (struct test_case_struct *tc) } retval = wordexp (words, &we, tc->flags); - if ((tc->flags & WRDE_NOCMD) - && (registered_forks > 0)) - { - printf ("FAILED fork called for WRDE_NOCMD\n"); - return 1; - } - if (tc->flags & WRDE_DOOFFS) start_offs = sav_we.we_offs; @@ -551,9 +489,11 @@ testit (struct test_case_struct *tc) const int page_size = getpagesize (); char *start = (char *) PTR_ALIGN_DOWN (words, page_size); - if (munmap (start, 2 * page_size) != 0) - return 1; + xmunmap (start, 2 * page_size); fflush (NULL); return bzzzt; } + +#define TEST_FUNCTION_ARGV do_test +#include diff --git a/posix/wordexp.c b/posix/wordexp.c index 22c6d18a9c..e1aafcaceb 100644 --- a/posix/wordexp.c +++ b/posix/wordexp.c @@ -25,33 +25,18 @@ #include #include #include -#include #include #include -#include #include #include -#include -#include -#include -#include #include #include -#include #include -#include +#include #include - -#include #include <_itoa.h> - -/* Undefine the following line for the production version. */ -/* #define NDEBUG 1 */ #include -/* Get some device information. */ -#include - /* * This is a recursive-descent-style word expansion routine. */ @@ -812,61 +797,90 @@ parse_arith (char **word, size_t *word_length, size_t *max_length, return WRDE_SYNTAX; } +static char ** +create_environment (void) +{ + size_t s = 0; + + /* Calculate total environment size, including 'IFS' if is present. */ + for (char **ep = __environ; *ep != NULL; ep++, s++); + + /* Include final NULL pointer. */ + char **newenviron = malloc (s * sizeof (char*)); + if (newenviron == NULL) + return NULL; + + /* Copy current environment excluding 'IFS', to make sure the subshell + doesn't field-split on our behalf. */ + size_t i, j; + for (i = 0, j = 0; i < s; i++) + if (strncmp (__environ[i], "IFS=", sizeof ("IFS=")-1) != 0) + newenviron[j++] = __strdup (__environ[i]); + newenviron[j] = NULL; + + return newenviron; +} + +static void +free_environment (char **environ) +{ + for (char **ep = environ; *ep != NULL; ep++) + free (*ep); + free (environ); +} + /* Function called by child process in exec_comm() */ -static inline void -__attribute__ ((always_inline)) -exec_comm_child (char *comm, int *fildes, int showerr, int noexec) +static pid_t +exec_comm_child (char *comm, int *fildes, bool showerr, bool noexec) { - const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL }; + pid_t pid = -1; - /* Execute the command, or just check syntax? */ - if (noexec) - args[1] = "-nc"; + /* Execute the command, or just check syntax? */ + const char *args[] = { _PATH_BSHELL, noexec ? "-nc" : "-c", comm, NULL }; - /* Redirect output. */ - if (__glibc_likely (fildes[1] != STDOUT_FILENO)) - { - __dup2 (fildes[1], STDOUT_FILENO); - __close (fildes[1]); - } - else - /* Reset the close-on-exec flag (if necessary). */ - __fcntl (fildes[1], F_SETFD, 0); + posix_spawn_file_actions_t fa; + /* posix_spawn_file_actions_init does not fail. */ + __posix_spawn_file_actions_init (&fa); - /* Redirect stderr to /dev/null if we have to. */ - if (showerr == 0) + /* Redirect output. For check syntax only (noexec being true), exec_comm + explicits sets fildes[1] to -1, so check its value to avoid a failure in + __posix_spawn_file_actions_adddup2. */ + if (fildes[1] != -1) { - struct stat64 st; - int fd; - __close (STDERR_FILENO); - fd = __open (_PATH_DEVNULL, O_WRONLY); - if (fd >= 0 && fd != STDERR_FILENO) + if (__glibc_likely (fildes[1] != STDOUT_FILENO)) { - __dup2 (fd, STDERR_FILENO); - __close (fd); + if (__posix_spawn_file_actions_adddup2 (&fa, fildes[1], + STDOUT_FILENO) != 0 + || __posix_spawn_file_actions_addclose (&fa, fildes[1]) != 0) + goto out; } - /* Be paranoid. Check that we actually opened the /dev/null - device. */ - if (__builtin_expect (__fxstat64 (_STAT_VER, STDERR_FILENO, &st), 0) != 0 - || __builtin_expect (S_ISCHR (st.st_mode), 1) == 0 -#if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR - || st.st_rdev != __gnu_dev_makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR) -#endif - ) - /* It's not the /dev/null device. Stop right here. The - problem is: how do we stop? We use _exit() with an - hopefully unusual exit code. */ - _exit (90); + else + /* Reset the close-on-exec flag (if necessary). */ + if (__posix_spawn_file_actions_adddup2 (&fa, fildes[1], fildes[1]) + != 0) + goto out; } - /* Make sure the subshell doesn't field-split on our behalf. */ - __unsetenv ("IFS"); + /* Redirect stderr to /dev/null if we have to. */ + if (!showerr) + if (__posix_spawn_file_actions_addopen (&fa, STDERR_FILENO, _PATH_DEVNULL, + O_WRONLY, 0) != 0) + goto out; + + char **newenv = create_environment (); + if (newenv == NULL) + goto out; - __close (fildes[0]); - __execve (_PATH_BSHELL, (char *const *) args, __environ); + /* pid is unset if posix_spawn fails, so it keep the original value + of -1. */ + __posix_spawn (&pid, _PATH_BSHELL, &fa, NULL, (char *const *) args, newenv); - /* Bad. What now? */ - abort (); + free_environment (newenv); + +out: + __posix_spawn_file_actions_destroy (&fa); + + return pid; } /* Function to execute a command and retrieve the results */ @@ -884,13 +898,13 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length, size_t maxnewlines = 0; char buffer[bufsize]; pid_t pid; - int noexec = 0; + bool noexec = false; /* Do nothing if command substitution should not succeed. */ if (flags & WRDE_NOCMD) return WRDE_CMDSUB; - /* Don't fork() unless necessary */ + /* Don't posix_spawn() unless necessary */ if (!comm || !*comm) return 0; @@ -898,19 +912,15 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length, return WRDE_NOSPACE; again: - if ((pid = __fork ()) < 0) + pid = exec_comm_child (comm, fildes, noexec ? false : flags & WRDE_SHOWERR, + noexec); + if (pid < 0) { - /* Bad */ __close (fildes[0]); __close (fildes[1]); return WRDE_NOSPACE; } - if (pid == 0) - exec_comm_child (comm, fildes, noexec ? 0 : flags & WRDE_SHOWERR, noexec); - - /* Parent */ - /* If we are just testing the syntax, only wait. */ if (noexec) return (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) == pid @@ -1091,7 +1101,7 @@ exec_comm (char *comm, char **word, size_t *word_length, size_t *max_length, /* Check for syntax error (re-execute but with "-n" flag) */ if (buflen < 1 && status != 0) { - noexec = 1; + noexec = true; goto again; } @@ -1143,26 +1153,9 @@ parse_comm (char **word, size_t *word_length, size_t *max_length, /* Go -- give script to the shell */ if (comm) { -#ifdef __libc_ptf_call - /* We do not want the exec_comm call to be cut short - by a thread cancellation since cleanup is very - ugly. Therefore disable cancellation for - now. */ - // XXX Ideally we do want the thread being cancelable. - // XXX If demand is there we'll change it. - int state = PTHREAD_CANCEL_ENABLE; - __libc_ptf_call (__pthread_setcancelstate, - (PTHREAD_CANCEL_DISABLE, &state), 0); -#endif - + /* posix_spawn already handles thread cancellation. */ error = exec_comm (comm, word, word_length, max_length, flags, pwordexp, ifs, ifs_white); - -#ifdef __libc_ptf_call - __libc_ptf_call (__pthread_setcancelstate, - (state, NULL), 0); -#endif - free (comm); }