From patchwork Fri Mar 17 19:09:39 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Frysinger X-Patchwork-Id: 19644 Received: (qmail 109250 invoked by alias); 17 Mar 2017 19:09: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 108217 invoked by uid 89); 17 Mar 2017 19:09:45 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 spammy= X-HELO: smtp.gentoo.org From: Mike Frysinger To: libc-alpha@sourceware.org Subject: [PATCH v2] posix_spawn: use a larger min stack for -fstack-check [BZ #21253] Date: Fri, 17 Mar 2017 12:09:39 -0700 Message-Id: <20170317190939.8707-1-vapier@gentoo.org> In-Reply-To: <20170316073012.22763-1-vapier@gentoo.org> References: <20170316073012.22763-1-vapier@gentoo.org> When glibc is built with -fstack-check, trying to use posix_spawn can lead to segfaults due to gcc internally probing stack memory too far. The new spawn API will allocate a minimum of 1 page, but the stack checking logic might probe a couple of pages. When it tries to walk them, everything falls apart. The gcc internal docs [1] state the default interval checking is one page. Which means we need two pages (the current one, and the next probed). No target currently defines it larger. Further, it mentions that the default minimum stack size needed to recover from an overflow is 4/8KiB for sjlj or 8/12KiB for others. But some Linux targets (like mips and ppc) go up to 16KiB (and some non-Linux targets go up to 24KiB). Let's create each child with a minimum of 32KiB slack space to support them all, and give us future breathing room. No test is added as existing ones crash. Even a simple call is enough to trigger the problem: char *argv[] = { "/bin/ls", NULL }; posix_spawn(NULL, "/bin/ls", NULL, NULL, argv, NULL); [1] https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gccint/Stack-Checking.html --- v2 - rework stack padding logic so we always round up to the page size sysdeps/unix/sysv/linux/spawni.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index 24f75dbd9c78..6862bee34024 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -318,7 +318,12 @@ __spawnix (pid_t * pid, const char *file, /* Add a slack area for child's stack. */ size_t argv_size = (argc * sizeof (void *)) + 512; - size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize)); + /* 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. */ + 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))