]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
posix_spawn: use a larger min stack for -fstack-check [BZ #21253]
authorMike Frysinger <vapier@gentoo.org>
Thu, 16 Mar 2017 06:59:31 +0000 (23:59 -0700)
committerMike Frysinger <vapier@gentoo.org>
Mon, 3 Apr 2017 19:15:41 +0000 (15:15 -0400)
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

ChangeLog
sysdeps/unix/sysv/linux/spawni.c

index 0c95ed93b01d92dd2f63930031cc8d8a51f27221..2ca0348a5205b2dd784968155be4ebb86de001a6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2017-04-03  Mike Frysinger  <vapier@gentoo.org>
+
+       [BZ #21253]
+       * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Increase argv_size
+       slack space by 32KiB.
+
 2017-04-01  Wladimir van der Laan  <laanwj@gmail.com>
 
        [BZ# 21338]
index b82a5e8f3c850d7b6e051d54ceba0c8960a7554d..d7f9e835751521249cb6bf66cceaa70c6e33ab8c 100644 (file)
@@ -319,6 +319,11 @@ __spawnix (pid_t * pid, const char *file,
 
   /* Add a slack area for child's stack.  */
   size_t argv_size = (argc * sizeof (void *)) + 512;
+  /* 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);