Blame SOURCES/0003-Backport-of-Tests-for-minimal-signal-handler.patch

3c8a07
From fbbc9a4e347dabb2d1662744e6a2e83b569ea3a4 Mon Sep 17 00:00:00 2001
3c8a07
From: Zack Weinberg <zackw@panix.com>
3c8a07
Date: Tue, 15 Jan 2019 14:58:15 -0500
3c8a07
Subject: [PATCH] Tests for minimal signal handler functionality in MINSIGSTKSZ
3c8a07
 space.
3c8a07
3c8a07
There is general agreement that the very short list of things that ISO
3c8a07
C says you can do in an async signal handler should all work when the
3c8a07
handler is running on an alternate signal stack with only MINSIGSTKSZ
3c8a07
space.  This patch adds tests to make sure those things do work.
3c8a07
3c8a07
To facilitate this, there is a new set of test support routines for
3c8a07
setting up alternate signal stacks; see support/xsignal.h for the API.
3c8a07
3c8a07
         * support/xsignal.h (xalloc_sigstack, xfree_sigstack)
3c8a07
         (xget_sigstack_location): New test support functions.
3c8a07
         * support/xsigstack.c: New file, implementing them.
3c8a07
         * support/tst-xsigstack.c: New test for them.
3c8a07
         * support/Makefile: Update.
3c8a07
3c8a07
         * signal/tst-minsigstksz-1.c
3c8a07
         * signal/tst-minsigstksz-2.c
3c8a07
         * signal/tst-minsigstksz-3.c
3c8a07
         * signal/tst-minsigstksz-3a.c
3c8a07
         * signal/tst-minsigstksz-4.c: New tests.
3c8a07
         * signal/Makefile: Run them.
3c8a07
3c8a07
UPDATE:
3c8a07
3c8a07
Backported to glibc 2.28
3c8a07
3c8a07
Signed-off-by: Jair Gonzalez <jair.de.jesus.gonzalez.plascencia@intel.com>
3c8a07
---
3c8a07
 ChangeLog                   |  15 +++++
3c8a07
 signal/Makefile             |   2 +
3c8a07
 signal/tst-minsigstksz-1.c  | 131 ++++++++++++++++++++++++++++++++++++
3c8a07
 signal/tst-minsigstksz-2.c  |  66 ++++++++++++++++++
3c8a07
 signal/tst-minsigstksz-3.c  |  64 ++++++++++++++++++
3c8a07
 signal/tst-minsigstksz-3a.c |  69 +++++++++++++++++++
3c8a07
 signal/tst-minsigstksz-4.c  |  65 ++++++++++++++++++
3c8a07
 support/Makefile            |   2 +
3c8a07
 support/tst-xsigstack.c     |  64 ++++++++++++++++++
3c8a07
 support/xsignal.h           |  17 +++++
3c8a07
 support/xsigstack.c         | 107 +++++++++++++++++++++++++++++
3c8a07
 11 files changed, 602 insertions(+)
3c8a07
 create mode 100644 signal/tst-minsigstksz-1.c
3c8a07
 create mode 100644 signal/tst-minsigstksz-2.c
3c8a07
 create mode 100644 signal/tst-minsigstksz-3.c
3c8a07
 create mode 100644 signal/tst-minsigstksz-3a.c
3c8a07
 create mode 100644 signal/tst-minsigstksz-4.c
3c8a07
 create mode 100644 support/tst-xsigstack.c
3c8a07
 create mode 100644 support/xsigstack.c
3c8a07
3c8a07
diff --git a/ChangeLog b/ChangeLog
3c8a07
index 305a772b..9e33b6cb 100644
3c8a07
--- a/ChangeLog
3c8a07
+++ b/ChangeLog
3c8a07
@@ -1,3 +1,18 @@
3c8a07
+2019-01-16  Zack Weinberg  <zackw@panix.com>
3c8a07
+
3c8a07
+	 * support/xsignal.h (xalloc_sigstack, xfree_sigstack)
3c8a07
+	 (xget_sigstack_location): New test support functions.
3c8a07
+	 * support/xsigstack.c: New file, implementing them.
3c8a07
+	 * support/tst-xsigstack.c: New test for them.
3c8a07
+	 * support/Makefile: Update.
3c8a07
+
3c8a07
+	 * signal/tst-minsigstksz-1.c
3c8a07
+	 * signal/tst-minsigstksz-2.c
3c8a07
+	 * signal/tst-minsigstksz-3.c
3c8a07
+	 * signal/tst-minsigstksz-3a.c
3c8a07
+	 * signal/tst-minsigstksz-4.c: New tests.
3c8a07
+	 * signal/Makefile: Run them.
3c8a07
+
3c8a07
 2018-12-19  Tulio Magno Quites Machado Filho  <tuliom@linux.ibm.com>
3c8a07
 
3c8a07
 	* elf/dl-sysdep.c (auxvars): Add AT_L1I_CACHESIZE,
3c8a07
diff --git a/signal/Makefile b/signal/Makefile
3c8a07
index aa63434f..d5a10d59 100644
3c8a07
--- a/signal/Makefile
3c8a07
+++ b/signal/Makefile
3c8a07
@@ -47,6 +47,8 @@ routines	:= signal raise killpg \
3c8a07
 
3c8a07
 tests		:= tst-signal tst-sigset tst-sigsimple tst-raise tst-sigset2 \
3c8a07
 		   tst-sigwait-eintr tst-sigaction \
3c8a07
+		   tst-minsigstksz-1 tst-minsigstksz-2 tst-minsigstksz-3 \
3c8a07
+		   tst-minsigstksz-3a tst-minsigstksz-4 \
3c8a07
 
3c8a07
 include ../Rules
3c8a07
 
3c8a07
diff --git a/signal/tst-minsigstksz-1.c b/signal/tst-minsigstksz-1.c
3c8a07
new file mode 100644
3c8a07
index 00000000..00344d5f
3c8a07
--- /dev/null
3c8a07
+++ b/signal/tst-minsigstksz-1.c
3c8a07
@@ -0,0 +1,131 @@
3c8a07
+/* Tests of signal delivery on an alternate stack (nonlethal).
3c8a07
+   Copyright (C) 2019 Free Software Foundation, Inc.
3c8a07
+   This file is part of the GNU C Library.
3c8a07
+
3c8a07
+   The GNU C Library is free software; you can redistribute it and/or
3c8a07
+   modify it under the terms of the GNU Lesser General Public
3c8a07
+   License as published by the Free Software Foundation; either
3c8a07
+   version 2.1 of the License, or (at your option) any later version.
3c8a07
+
3c8a07
+   The GNU C Library is distributed in the hope that it will be useful,
3c8a07
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
3c8a07
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
3c8a07
+   Lesser General Public License for more details.
3c8a07
+
3c8a07
+   You should have received a copy of the GNU Lesser General Public
3c8a07
+   License along with the GNU C Library; if not, see
3c8a07
+   <http://www.gnu.org/licenses/>.  */
3c8a07
+
3c8a07
+#include <support/xsignal.h>
3c8a07
+#include <support/support.h>
3c8a07
+#include <support/check.h>
3c8a07
+
3c8a07
+/* C2011 7.4.1.1p5 specifies that only the following operations are
3c8a07
+   guaranteed to be well-defined inside an asynchronous signal handler:
3c8a07
+     * any operation on a lock-free atomic object
3c8a07
+     * assigning a value to an object declared as volatile sig_atomic_t
3c8a07
+     * calling abort, _Exit, quick_exit, or signal
3c8a07
+       * signal may only be called with its first argument equal to the
3c8a07
+         number of the signal that caused the handler to be called
3c8a07
+
3c8a07
+   We use this list as a guideline for the set of operations that ought
3c8a07
+   also to be safe in a _synchronous_ signal delivered on an alternate
3c8a07
+   signal stack with only MINSIGSTKSZ bytes of space.
3c8a07
+
3c8a07
+   This test program tests all of the above operations that do not,
3c8a07
+   one way or another, cause the program to be terminated.  */
3c8a07
+
3c8a07
+/* We do not try to test atomic operations exhaustively, only a simple
3c8a07
+   atomic counter increment.  This is only safe if atomic_[u]int is
3c8a07
+   unconditionally lock-free.  */
3c8a07
+#ifdef __STDC_NO_ATOMICS__
3c8a07
+# define TEST_ATOMIC_OPS 0
3c8a07
+#else
3c8a07
+# include <stdatomic.h>
3c8a07
+# if ATOMIC_INT_LOCK_FREE != 2
3c8a07
+#  define TEST_ATOMIC_OPS 0
3c8a07
+# else
3c8a07
+#  define TEST_ATOMIC_OPS 1
3c8a07
+# endif
3c8a07
+#endif
3c8a07
+
3c8a07
+static volatile sig_atomic_t signal_flag = 0;
3c8a07
+static volatile sig_atomic_t signal_err = 0;
3c8a07
+static void
3c8a07
+handler_set_flag (int unused)
3c8a07
+{
3c8a07
+  signal_flag = 1;
3c8a07
+}
3c8a07
+
3c8a07
+static void
3c8a07
+handler_set_flag_once (int sig)
3c8a07
+{
3c8a07
+  signal_flag = 1;
3c8a07
+  if (signal (sig, SIG_IGN) == SIG_ERR)
3c8a07
+    /* It is not safe to call FAIL_EXIT1 here.  Set another flag instead.  */
3c8a07
+    signal_err = 1;
3c8a07
+}
3c8a07
+
3c8a07
+#if TEST_ATOMIC_OPS
3c8a07
+static atomic_uint signal_count = 0;
3c8a07
+static void
3c8a07
+handler_count_up_1 (int unused)
3c8a07
+{
3c8a07
+  atomic_fetch_add (&signal_count, 1);
3c8a07
+}
3c8a07
+#endif
3c8a07
+
3c8a07
+int
3c8a07
+do_test (void)
3c8a07
+{
3c8a07
+  void *sstk = xalloc_sigstack (0);
3c8a07
+  struct sigaction sa;
3c8a07
+
3c8a07
+  /* Test 1: setting a volatile sig_atomic_t flag.  */
3c8a07
+  sa.sa_handler = handler_set_flag;
3c8a07
+  sa.sa_flags   = SA_RESTART | SA_ONSTACK;
3c8a07
+  sigfillset (&sa.sa_mask);
3c8a07
+  if (sigaction (SIGUSR1, &sa, 0))
3c8a07
+    FAIL_EXIT1 ("sigaction (SIGUSR1, handler_set_flag): %m\n");
3c8a07
+
3c8a07
+  TEST_VERIFY_EXIT (signal_flag == 0);
3c8a07
+  raise (SIGUSR1);
3c8a07
+  TEST_VERIFY_EXIT (signal_flag == 1);
3c8a07
+  signal_flag = 0;
3c8a07
+  raise (SIGUSR1);
3c8a07
+  TEST_VERIFY_EXIT (signal_flag == 1);
3c8a07
+  signal_flag = 0;
3c8a07
+
3c8a07
+  /* Test 1: setting a volatile sig_atomic_t flag and then ignoring
3c8a07
+     further delivery of the signal. */
3c8a07
+  sa.sa_handler = handler_set_flag_once;
3c8a07
+  if (sigaction (SIGUSR1, &sa, 0))
3c8a07
+    FAIL_EXIT1 ("sigaction (SIGUSR1, handler_set_flag_once): %m\n");
3c8a07
+
3c8a07
+  raise (SIGUSR1);
3c8a07
+  TEST_VERIFY_EXIT (signal_flag == 1);
3c8a07
+  /* Note: if signal_err is 1, a system call failed, but we can't
3c8a07
+     report the error code because errno is indeterminate.  */
3c8a07
+  TEST_VERIFY_EXIT (signal_err == 0);
3c8a07
+
3c8a07
+  signal_flag = 0;
3c8a07
+  raise (SIGUSR1);
3c8a07
+  TEST_VERIFY_EXIT (signal_flag == 0);
3c8a07
+  TEST_VERIFY_EXIT (signal_err == 0);
3c8a07
+
3c8a07
+#if TEST_ATOMIC_OPS
3c8a07
+  sa.sa_handler = handler_count_up_1;
3c8a07
+  if (sigaction (SIGUSR1, &sa, 0))
3c8a07
+    FAIL_EXIT1 ("sigaction (SIGUSR1, handler_count_up_1): %m\n");
3c8a07
+
3c8a07
+  raise (SIGUSR1);
3c8a07
+  TEST_VERIFY_EXIT (atomic_load (&signal_count) == 1);
3c8a07
+  raise (SIGUSR1);
3c8a07
+  TEST_VERIFY_EXIT (atomic_load (&signal_count) == 2);
3c8a07
+#endif
3c8a07
+
3c8a07
+  xfree_sigstack (sstk);
3c8a07
+  return 0;
3c8a07
+}
3c8a07
+
3c8a07
+#include <support/test-driver.c>
3c8a07
diff --git a/signal/tst-minsigstksz-2.c b/signal/tst-minsigstksz-2.c
3c8a07
new file mode 100644
3c8a07
index 00000000..3368dde6
3c8a07
--- /dev/null
3c8a07
+++ b/signal/tst-minsigstksz-2.c
3c8a07
@@ -0,0 +1,66 @@
3c8a07
+/* Tests of signal delivery on an alternate stack (abort).
3c8a07
+   Copyright (C) 2019 Free Software Foundation, Inc.
3c8a07
+   This file is part of the GNU C Library.
3c8a07
+
3c8a07
+   The GNU C Library is free software; you can redistribute it and/or
3c8a07
+   modify it under the terms of the GNU Lesser General Public
3c8a07
+   License as published by the Free Software Foundation; either
3c8a07
+   version 2.1 of the License, or (at your option) any later version.
3c8a07
+
3c8a07
+   The GNU C Library is distributed in the hope that it will be useful,
3c8a07
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
3c8a07
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
3c8a07
+   Lesser General Public License for more details.
3c8a07
+
3c8a07
+   You should have received a copy of the GNU Lesser General Public
3c8a07
+   License along with the GNU C Library; if not, see
3c8a07
+   <http://www.gnu.org/licenses/>.  */
3c8a07
+
3c8a07
+#include <support/xsignal.h>
3c8a07
+#include <support/support.h>
3c8a07
+#include <support/check.h>
3c8a07
+#include <stdlib.h>
3c8a07
+
3c8a07
+/* C2011 7.4.1.1p5 specifies that only the following operations are
3c8a07
+   guaranteed to be well-defined inside an asynchronous signal handler:
3c8a07
+     * any operation on a lock-free atomic object
3c8a07
+     * assigning a value to an object declared as volatile sig_atomic_t
3c8a07
+     * calling abort, _Exit, quick_exit, or signal
3c8a07
+       * signal may only be called with its first argument equal to the
3c8a07
+         number of the signal that caused the handler to be called
3c8a07
+
3c8a07
+   We use this list as a guideline for the set of operations that ought
3c8a07
+   also to be safe in a _synchronous_ signal delivered on an alternate
3c8a07
+   signal stack with only MINSIGSTKSZ bytes of space.
3c8a07
+
3c8a07
+   This test program tests calls to abort.  Note that it does _not_
3c8a07
+   install a handler for SIGABRT, because that signal would also be
3c8a07
+   delivered on the alternate stack and MINSIGSTKSZ does not provide
3c8a07
+   enough space for delivery of nested signals.  */
3c8a07
+
3c8a07
+static void
3c8a07
+handler (int unused)
3c8a07
+{
3c8a07
+  abort ();
3c8a07
+}
3c8a07
+
3c8a07
+int
3c8a07
+do_test (void)
3c8a07
+{
3c8a07
+  void *sstk = xalloc_sigstack (0);
3c8a07
+  struct sigaction sa;
3c8a07
+
3c8a07
+  sa.sa_handler = handler;
3c8a07
+  sa.sa_flags   = SA_RESTART | SA_ONSTACK;
3c8a07
+  sigfillset (&sa.sa_mask);
3c8a07
+  if (sigaction (SIGUSR1, &sa, 0))
3c8a07
+    FAIL_RET ("sigaction (SIGUSR1, handler): %m\n");
3c8a07
+
3c8a07
+  raise (SIGUSR1);
3c8a07
+
3c8a07
+  xfree_sigstack (sstk);
3c8a07
+  FAIL_RET ("test process was not terminated by abort in signal handler");
3c8a07
+}
3c8a07
+
3c8a07
+#define EXPECTED_SIGNAL SIGABRT
3c8a07
+#include <support/test-driver.c>
3c8a07
diff --git a/signal/tst-minsigstksz-3.c b/signal/tst-minsigstksz-3.c
3c8a07
new file mode 100644
3c8a07
index 00000000..a8d9a636
3c8a07
--- /dev/null
3c8a07
+++ b/signal/tst-minsigstksz-3.c
3c8a07
@@ -0,0 +1,64 @@
3c8a07
+/* Tests of signal delivery on an alternate stack (_Exit).
3c8a07
+   Copyright (C) 2019 Free Software Foundation, Inc.
3c8a07
+   This file is part of the GNU C Library.
3c8a07
+
3c8a07
+   The GNU C Library is free software; you can redistribute it and/or
3c8a07
+   modify it under the terms of the GNU Lesser General Public
3c8a07
+   License as published by the Free Software Foundation; either
3c8a07
+   version 2.1 of the License, or (at your option) any later version.
3c8a07
+
3c8a07
+   The GNU C Library is distributed in the hope that it will be useful,
3c8a07
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
3c8a07
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
3c8a07
+   Lesser General Public License for more details.
3c8a07
+
3c8a07
+   You should have received a copy of the GNU Lesser General Public
3c8a07
+   License along with the GNU C Library; if not, see
3c8a07
+   <http://www.gnu.org/licenses/>.  */
3c8a07
+
3c8a07
+#include <support/xsignal.h>
3c8a07
+#include <support/support.h>
3c8a07
+#include <support/check.h>
3c8a07
+#include <stdlib.h>
3c8a07
+
3c8a07
+/* C2011 7.4.1.1p5 specifies that only the following operations are
3c8a07
+   guaranteed to be well-defined inside an asynchronous signal handler:
3c8a07
+     * any operation on a lock-free atomic object
3c8a07
+     * assigning a value to an object declared as volatile sig_atomic_t
3c8a07
+     * calling abort, _Exit, quick_exit, or signal
3c8a07
+       * signal may only be called with its first argument equal to the
3c8a07
+         number of the signal that caused the handler to be called
3c8a07
+
3c8a07
+   We use this list as a guideline for the set of operations that ought
3c8a07
+   also to be safe in a _synchronous_ signal delivered on an alternate
3c8a07
+   signal stack with only MINSIGSTKSZ bytes of space.
3c8a07
+
3c8a07
+   This test program tests calls to _Exit.  */
3c8a07
+
3c8a07
+#define EXPECTED_STATUS 3
3c8a07
+
3c8a07
+static void
3c8a07
+handler (int unused)
3c8a07
+{
3c8a07
+  _Exit (EXPECTED_STATUS);
3c8a07
+}
3c8a07
+
3c8a07
+int
3c8a07
+do_test (void)
3c8a07
+{
3c8a07
+  void *sstk = xalloc_sigstack (0);
3c8a07
+  struct sigaction sa;
3c8a07
+
3c8a07
+  sa.sa_handler = handler;
3c8a07
+  sa.sa_flags   = SA_RESTART | SA_ONSTACK;
3c8a07
+  sigfillset (&sa.sa_mask);
3c8a07
+  if (sigaction (SIGUSR1, &sa, 0))
3c8a07
+    FAIL_RET ("sigaction (SIGUSR1, handler): %m\n");
3c8a07
+
3c8a07
+  raise (SIGUSR1);
3c8a07
+
3c8a07
+  xfree_sigstack (sstk);
3c8a07
+  FAIL_RET ("test process was not terminated by _Exit in signal handler");
3c8a07
+}
3c8a07
+
3c8a07
+#include <support/test-driver.c>
3c8a07
diff --git a/signal/tst-minsigstksz-3a.c b/signal/tst-minsigstksz-3a.c
3c8a07
new file mode 100644
3c8a07
index 00000000..b58b8d01
3c8a07
--- /dev/null
3c8a07
+++ b/signal/tst-minsigstksz-3a.c
3c8a07
@@ -0,0 +1,69 @@
3c8a07
+/* Tests of signal delivery on an alternate stack (_exit).
3c8a07
+   Copyright (C) 2019 Free Software Foundation, Inc.
3c8a07
+   This file is part of the GNU C Library.
3c8a07
+
3c8a07
+   The GNU C Library is free software; you can redistribute it and/or
3c8a07
+   modify it under the terms of the GNU Lesser General Public
3c8a07
+   License as published by the Free Software Foundation; either
3c8a07
+   version 2.1 of the License, or (at your option) any later version.
3c8a07
+
3c8a07
+   The GNU C Library is distributed in the hope that it will be useful,
3c8a07
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
3c8a07
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
3c8a07
+   Lesser General Public License for more details.
3c8a07
+
3c8a07
+   You should have received a copy of the GNU Lesser General Public
3c8a07
+   License along with the GNU C Library; if not, see
3c8a07
+   <http://www.gnu.org/licenses/>.  */
3c8a07
+
3c8a07
+#include <support/xsignal.h>
3c8a07
+#include <support/support.h>
3c8a07
+#include <support/check.h>
3c8a07
+#include <unistd.h>
3c8a07
+
3c8a07
+/* C2011 7.4.1.1p5 specifies that only the following operations are
3c8a07
+   guaranteed to be well-defined inside an asynchronous signal handler:
3c8a07
+     * any operation on a lock-free atomic object
3c8a07
+     * assigning a value to an object declared as volatile sig_atomic_t
3c8a07
+     * calling abort, _Exit, quick_exit, or signal
3c8a07
+       * signal may only be called with its first argument equal to the
3c8a07
+         number of the signal that caused the handler to be called
3c8a07
+
3c8a07
+   We use this list as a guideline for the set of operations that ought
3c8a07
+   also to be safe in a _synchronous_ signal delivered on an alternate
3c8a07
+   signal stack with only MINSIGSTKSZ bytes of space.
3c8a07
+
3c8a07
+   This test program tests calls to _exit, which is the same function
3c8a07
+   as _Exit, but specified by POSIX rather than ISO C.  For reasons
3c8a07
+   unknown to the author of this program, the C committee did not
3c8a07
+   think it could standardize _exit under that name; regardless, in a
3c8a07
+   POSIX-conformant environment, they should be completely
3c8a07
+   interchangeable.  */
3c8a07
+
3c8a07
+#define EXPECTED_STATUS 3
3c8a07
+
3c8a07
+static void
3c8a07
+handler (int unused)
3c8a07
+{
3c8a07
+  _exit (EXPECTED_STATUS);
3c8a07
+}
3c8a07
+
3c8a07
+int
3c8a07
+do_test (void)
3c8a07
+{
3c8a07
+  void *sstk = xalloc_sigstack (0);
3c8a07
+  struct sigaction sa;
3c8a07
+
3c8a07
+  sa.sa_handler = handler;
3c8a07
+  sa.sa_flags   = SA_RESTART | SA_ONSTACK;
3c8a07
+  sigfillset (&sa.sa_mask);
3c8a07
+  if (sigaction (SIGUSR1, &sa, 0))
3c8a07
+    FAIL_RET ("sigaction (SIGUSR1, handler): %m\n");
3c8a07
+
3c8a07
+  raise (SIGUSR1);
3c8a07
+
3c8a07
+  xfree_sigstack (sstk);
3c8a07
+  FAIL_RET ("test process was not terminated by _exit in signal handler");
3c8a07
+}
3c8a07
+
3c8a07
+#include <support/test-driver.c>
3c8a07
diff --git a/signal/tst-minsigstksz-4.c b/signal/tst-minsigstksz-4.c
3c8a07
new file mode 100644
3c8a07
index 00000000..0dc63b4d
3c8a07
--- /dev/null
3c8a07
+++ b/signal/tst-minsigstksz-4.c
3c8a07
@@ -0,0 +1,65 @@
3c8a07
+/* Tests of signal delivery on an alternate stack (quick_exit).
3c8a07
+   Copyright (C) 2019 Free Software Foundation, Inc.
3c8a07
+   This file is part of the GNU C Library.
3c8a07
+
3c8a07
+   The GNU C Library is free software; you can redistribute it and/or
3c8a07
+   modify it under the terms of the GNU Lesser General Public
3c8a07
+   License as published by the Free Software Foundation; either
3c8a07
+   version 2.1 of the License, or (at your option) any later version.
3c8a07
+
3c8a07
+   The GNU C Library is distributed in the hope that it will be useful,
3c8a07
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
3c8a07
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
3c8a07
+   Lesser General Public License for more details.
3c8a07
+
3c8a07
+   You should have received a copy of the GNU Lesser General Public
3c8a07
+   License along with the GNU C Library; if not, see
3c8a07
+   <http://www.gnu.org/licenses/>.  */
3c8a07
+
3c8a07
+#include <support/xsignal.h>
3c8a07
+#include <support/support.h>
3c8a07
+#include <support/check.h>
3c8a07
+#include <stdlib.h>
3c8a07
+
3c8a07
+/* C2011 7.4.1.1p5 specifies that only the following operations are
3c8a07
+   guaranteed to be well-defined inside an asynchronous signal handler:
3c8a07
+     * any operation on a lock-free atomic object
3c8a07
+     * assigning a value to an object declared as volatile sig_atomic_t
3c8a07
+     * calling abort, _Exit, quick_exit, or signal
3c8a07
+       * signal may only be called with its first argument equal to the
3c8a07
+         number of the signal that caused the handler to be called
3c8a07
+
3c8a07
+   We use this list as a guideline for the set of operations that ought
3c8a07
+   also to be safe in a _synchronous_ signal delivered on an alternate
3c8a07
+   signal stack with only MINSIGSTKSZ bytes of space.
3c8a07
+
3c8a07
+   This test program tests calls to quick_exit.  Note that this is only
3c8a07
+   safe when there are no at_quick_exit callbacks.  */
3c8a07
+
3c8a07
+#define EXPECTED_STATUS 3
3c8a07
+
3c8a07
+static void
3c8a07
+handler (int unused)
3c8a07
+{
3c8a07
+  quick_exit (EXPECTED_STATUS);
3c8a07
+}
3c8a07
+
3c8a07
+int
3c8a07
+do_test (void)
3c8a07
+{
3c8a07
+  void *sstk = xalloc_sigstack (0);
3c8a07
+  struct sigaction sa;
3c8a07
+
3c8a07
+  sa.sa_handler = handler;
3c8a07
+  sa.sa_flags   = SA_RESTART | SA_ONSTACK;
3c8a07
+  sigfillset (&sa.sa_mask);
3c8a07
+  if (sigaction (SIGUSR1, &sa, 0))
3c8a07
+    FAIL_RET ("sigaction (SIGUSR1, handler): %m\n");
3c8a07
+
3c8a07
+  raise (SIGUSR1);
3c8a07
+
3c8a07
+  xfree_sigstack (sstk);
3c8a07
+  FAIL_RET ("test process was not terminated by quick_exit in signal handler");
3c8a07
+}
3c8a07
+
3c8a07
+#include <support/test-driver.c>
3c8a07
diff --git a/support/Makefile b/support/Makefile
3c8a07
index dcf3c4ba..619b6d44 100644
3c8a07
--- a/support/Makefile
3c8a07
+++ b/support/Makefile
3c8a07
@@ -157,6 +157,7 @@ libsupport-routines = \
3c8a07
   xsetsockopt \
3c8a07
   xsigaction \
3c8a07
   xsignal \
3c8a07
+  xsigstack \
3c8a07
   xsocket \
3c8a07
   xposix_spawn \
3c8a07
   xposix_spawn_file_actions_addclose \
3c8a07
@@ -231,6 +232,7 @@ tests = \
3c8a07
   tst-test_compare_blob \
3c8a07
   tst-test_compare_string \
3c8a07
   tst-xreadlink \
3c8a07
+  tst-xsigstack \
3c8a07
 
3c8a07
 ifeq ($(run-built-tests),yes)
3c8a07
 tests-special = \
3c8a07
diff --git a/support/tst-xsigstack.c b/support/tst-xsigstack.c
3c8a07
new file mode 100644
3c8a07
index 00000000..42859c79
3c8a07
--- /dev/null
3c8a07
+++ b/support/tst-xsigstack.c
3c8a07
@@ -0,0 +1,64 @@
3c8a07
+/* Test of sigaltstack wrappers.
3c8a07
+   Copyright (C) 2019 Free Software Foundation, Inc.
3c8a07
+   This file is part of the GNU C Library.
3c8a07
+
3c8a07
+   The GNU C Library is free software; you can redistribute it and/or
3c8a07
+   modify it under the terms of the GNU Lesser General Public
3c8a07
+   License as published by the Free Software Foundation; either
3c8a07
+   version 2.1 of the License, or (at your option) any later version.
3c8a07
+
3c8a07
+   The GNU C Library is distributed in the hope that it will be useful,
3c8a07
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
3c8a07
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
3c8a07
+   Lesser General Public License for more details.
3c8a07
+
3c8a07
+   You should have received a copy of the GNU Lesser General Public
3c8a07
+   License along with the GNU C Library; if not, see
3c8a07
+   <http://www.gnu.org/licenses/>.  */
3c8a07
+
3c8a07
+#include <support/xsignal.h>
3c8a07
+#include <support/support.h>
3c8a07
+#include <support/xunistd.h>
3c8a07
+#include <support/check.h>
3c8a07
+
3c8a07
+#include <stdint.h>
3c8a07
+#include <stdio.h>
3c8a07
+
3c8a07
+static volatile uintptr_t handler_stackaddr;
3c8a07
+
3c8a07
+static void
3c8a07
+handler (int unused)
3c8a07
+{
3c8a07
+  int var;
3c8a07
+  handler_stackaddr = (uintptr_t) &var;
3c8a07
+}
3c8a07
+
3c8a07
+int
3c8a07
+do_test (void)
3c8a07
+{
3c8a07
+  void *sstk = xalloc_sigstack (0);
3c8a07
+
3c8a07
+  unsigned char *sp;
3c8a07
+  size_t size;
3c8a07
+  xget_sigstack_location (sstk, &sp, &size);
3c8a07
+  printf ("signal stack installed: sp=%p size=%zu\n", sp, size);
3c8a07
+
3c8a07
+  struct sigaction sa;
3c8a07
+  sa.sa_handler = handler;
3c8a07
+  sa.sa_flags   = SA_RESTART | SA_ONSTACK;
3c8a07
+  sigfillset (&sa.sa_mask);
3c8a07
+  if (sigaction (SIGUSR1, &sa, 0))
3c8a07
+    FAIL_RET ("sigaction (SIGUSR1, handler): %m\n");
3c8a07
+
3c8a07
+  raise (SIGUSR1);
3c8a07
+
3c8a07
+  uintptr_t haddr = handler_stackaddr;
3c8a07
+  printf ("address of handler local variable: %p\n", (void *)haddr);
3c8a07
+  TEST_VERIFY ((uintptr_t)sp < haddr);
3c8a07
+  TEST_VERIFY (haddr < (uintptr_t)sp + size);
3c8a07
+
3c8a07
+  xfree_sigstack (sstk);
3c8a07
+  return 0;
3c8a07
+}
3c8a07
+
3c8a07
+#include <support/test-driver.c>
3c8a07
diff --git a/support/xsignal.h b/support/xsignal.h
3c8a07
index 9ab8d1bf..9d68558f 100644
3c8a07
--- a/support/xsignal.h
3c8a07
+++ b/support/xsignal.h
3c8a07
@@ -37,6 +37,23 @@ void xsigaction (int sig, const struct sigaction *newact,
3c8a07
 
3c8a07
 void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
3c8a07
 
3c8a07
+/* Allocate and activate an alternate signal stack.  This stack will
3c8a07
+   have SIZE + MINSIGSTKSZ bytes of space, rounded up to a whole
3c8a07
+   number of pages.  There will be large (at least 1 MiB) inaccessible
3c8a07
+   guard bands on either side of it.  The return value is a cookie
3c8a07
+   that can be passed to xfree_sigstack to deactivate and deallocate
3c8a07
+   the stack again.  It is not necessary to call sigaltstack after
3c8a07
+   calling this function.  Terminates the process on error.  */
3c8a07
+void *xalloc_sigstack (size_t size);
3c8a07
+
3c8a07
+/* Deactivate and deallocate a signal stack created by xalloc_sigstack.  */
3c8a07
+void xfree_sigstack (void *stack);
3c8a07
+
3c8a07
+/* Extract the actual address and size of the alternate signal stack from
3c8a07
+   the cookie returned by xalloc_sigstack.  */
3c8a07
+void xget_sigstack_location (const void *stack, unsigned char **addrp,
3c8a07
+                             size_t *sizep);
3c8a07
+
3c8a07
 __END_DECLS
3c8a07
 
3c8a07
 #endif /* SUPPORT_SIGNAL_H */
3c8a07
diff --git a/support/xsigstack.c b/support/xsigstack.c
3c8a07
new file mode 100644
3c8a07
index 00000000..cebfa19a
3c8a07
--- /dev/null
3c8a07
+++ b/support/xsigstack.c
3c8a07
@@ -0,0 +1,107 @@
3c8a07
+/* sigaltstack wrappers.
3c8a07
+   Copyright (C) 2019 Free Software Foundation, Inc.
3c8a07
+   This file is part of the GNU C Library.
3c8a07
+
3c8a07
+   The GNU C Library is free software; you can redistribute it and/or
3c8a07
+   modify it under the terms of the GNU Lesser General Public
3c8a07
+   License as published by the Free Software Foundation; either
3c8a07
+   version 2.1 of the License, or (at your option) any later version.
3c8a07
+
3c8a07
+   The GNU C Library is distributed in the hope that it will be useful,
3c8a07
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
3c8a07
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
3c8a07
+   Lesser General Public License for more details.
3c8a07
+
3c8a07
+   You should have received a copy of the GNU Lesser General Public
3c8a07
+   License along with the GNU C Library; if not, see
3c8a07
+   <http://www.gnu.org/licenses/>.  */
3c8a07
+
3c8a07
+#include <support/xsignal.h>
3c8a07
+#include <support/support.h>
3c8a07
+#include <support/xunistd.h>
3c8a07
+#include <support/check.h>
3c8a07
+
3c8a07
+#include <stdlib.h>
3c8a07
+#include <string.h>
3c8a07
+#include <sys/mman.h>
3c8a07
+#include <sys/param.h> /* roundup, MAX */
3c8a07
+
3c8a07
+/* The "cookie" returned by xalloc_sigstack points to one of these
3c8a07
+   structures.  */
3c8a07
+struct sigstack_desc
3c8a07
+{
3c8a07
+  void *alloc_base;  /* Base address of the complete allocation.  */
3c8a07
+  size_t alloc_size; /* Size of the complete allocation.  */
3c8a07
+  stack_t alt_stack; /* The address and size of the stack itself.  */
3c8a07
+  stack_t old_stack; /* The previous signal stack.  */
3c8a07
+};
3c8a07
+
3c8a07
+void *
3c8a07
+xalloc_sigstack (size_t size)
3c8a07
+{
3c8a07
+  size_t pagesize = sysconf (_SC_PAGESIZE);
3c8a07
+  if (pagesize == -1)
3c8a07
+    FAIL_EXIT1 ("sysconf (_SC_PAGESIZE): %m\n");
3c8a07
+
3c8a07
+  /* Always supply at least MINSIGSTKSZ space; passing 0 as size means
3c8a07
+     only that much space.  No matter what the number is, round it up
3c8a07
+     to a whole number of pages.  */
3c8a07
+  size_t stacksize = roundup (size + MINSIGSTKSZ, pagesize);
3c8a07
+
3c8a07
+  /* The guard bands need to be large enough to intercept offset
3c8a07
+     accesses from a stack address that might otherwise hit another
3c8a07
+     mapping.  Make them at least twice as big as the stack itself, to
3c8a07
+     defend against an offset by the entire size of a large
3c8a07
+     stack-allocated array.  The minimum is 1MiB, which is arbitrarily
3c8a07
+     chosen to be larger than any "typical" wild pointer offset.
3c8a07
+     Again, no matter what the number is, round it up to a whole
3c8a07
+     number of pages.  */
3c8a07
+  size_t guardsize = roundup (MAX (2 * stacksize, 1024 * 1024), pagesize);
3c8a07
+
3c8a07
+  struct sigstack_desc *desc = xmalloc (sizeof (struct sigstack_desc));
3c8a07
+  desc->alloc_size = guardsize + stacksize + guardsize;
3c8a07
+  /* Use MAP_NORESERVE so that RAM will not be wasted on the guard
3c8a07
+     bands; touch all the pages of the actual stack before returning,
3c8a07
+     so we know they are allocated.  */
3c8a07
+  desc->alloc_base = xmmap (0,
3c8a07
+                            desc->alloc_size,
3c8a07
+                            PROT_READ|PROT_WRITE,
3c8a07
+                            MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE|MAP_STACK,
3c8a07
+                            -1);
3c8a07
+
3c8a07
+  xmprotect (desc->alloc_base, guardsize, PROT_NONE);
3c8a07
+  xmprotect (desc->alloc_base + guardsize + stacksize, guardsize, PROT_NONE);
3c8a07
+  memset (desc->alloc_base + guardsize, 0xA5, stacksize);
3c8a07
+
3c8a07
+  desc->alt_stack.ss_sp    = desc->alloc_base + guardsize;
3c8a07
+  desc->alt_stack.ss_flags = 0;
3c8a07
+  desc->alt_stack.ss_size  = stacksize;
3c8a07
+
3c8a07
+  if (sigaltstack (&desc->alt_stack, &desc->old_stack))
3c8a07
+    FAIL_EXIT1 ("sigaltstack (new stack: sp=%p, size=%zu, flags=%u): %m\n",
3c8a07
+                desc->alt_stack.ss_sp, desc->alt_stack.ss_size,
3c8a07
+                desc->alt_stack.ss_flags);
3c8a07
+
3c8a07
+  return desc;
3c8a07
+}
3c8a07
+
3c8a07
+void
3c8a07
+xfree_sigstack (void *stack)
3c8a07
+{
3c8a07
+  struct sigstack_desc *desc = stack;
3c8a07
+
3c8a07
+  if (sigaltstack (&desc->old_stack, 0))
3c8a07
+    FAIL_EXIT1 ("sigaltstack (restore old stack: sp=%p, size=%zu, flags=%u): "
3c8a07
+                "%m\n", desc->old_stack.ss_sp, desc->old_stack.ss_size,
3c8a07
+                desc->old_stack.ss_flags);
3c8a07
+  xmunmap (desc->alloc_base, desc->alloc_size);
3c8a07
+  free (desc);
3c8a07
+}
3c8a07
+
3c8a07
+void
3c8a07
+xget_sigstack_location (const void *stack, unsigned char **addrp, size_t *sizep)
3c8a07
+{
3c8a07
+  const struct sigstack_desc *desc = stack;
3c8a07
+  *addrp = desc->alt_stack.ss_sp;
3c8a07
+  *sizep = desc->alt_stack.ss_size;
3c8a07
+}
3c8a07
-- 
3c8a07
2.27.0
3c8a07