public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 2/2] i386: Fix i386 sigaction sa_restorer initialization (BZ#21269)
  2017-11-17 20:35 [PATCH 1/2] linux: Consolidate sigaction implementation Adhemerval Zanella
@ 2017-11-17 20:34 ` Adhemerval Zanella
  2018-12-10 17:01 ` [PATCH 1/2] linux: Consolidate sigaction implementation Andreas Schwab
  1 sibling, 0 replies; 4+ messages in thread
From: Adhemerval Zanella @ 2017-11-17 20:34 UTC (permalink / raw)
  To: libc-alpha

This patch fixes the i386 sa_restorer field initialization for sigaction
syscall for kernel with vDSO.  As described in bug report, x86_32 Linux
(and compat on x86_64) interprets SA_RESTORER clear with nonzero
sa_restorer as a request for stack switching if the SS segment is 'funny'
This means that anything that tries to mix glibc's signal handling with
segmentation (for instance through modify_ldt syscall) is randomly broken
depending on what values lands in sa_restorer.

The testcase added  is based on Linux test tools/testing/selftests/x86/ldt_gdt.c,
more specifically in do_multicpu_tests function.  The main changes are:

  - C11 atomics instead of plain access.

  - Remove x86_64 support which simplifies the syscall handling and fallbacks.

  - Replicate only the test required to trigger the issue.

(I added some comments of my understanding of how the testcase is triggering
the issue, so if someone with more x86 knowledge could check if I get this
right I will be grateful)

Checked on i686-linux-gnu.

	[BZ #21269]
	* sysdeps/unix/sysv/linux/i386/Makefile (tests): Add tst-bz21269.
	* sysdeps/unix/sysv/linux/i386/sigaction.c (SET_SA_RESTORER): Clear
	sa_restorer for vDSO case.
	* sysdeps/unix/sysv/linux/i386/tst-bz21269.c: New file.

Signed-off-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
---
 ChangeLog                                  |   6 +
 sysdeps/unix/sysv/linux/i386/Makefile      |   3 +
 sysdeps/unix/sysv/linux/i386/sigaction.c   |   2 +
 sysdeps/unix/sysv/linux/i386/tst-bz21269.c | 233 +++++++++++++++++++++++++++++
 4 files changed, 244 insertions(+)
 create mode 100644 sysdeps/unix/sysv/linux/i386/tst-bz21269.c

diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile
index 4080b8c..da716e2 100644
--- a/sysdeps/unix/sysv/linux/i386/Makefile
+++ b/sysdeps/unix/sysv/linux/i386/Makefile
@@ -3,6 +3,9 @@ default-abi := 32
 
 ifeq ($(subdir),misc)
 sysdep_routines += ioperm iopl vm86
+
+tests += tst-bz21269
+$(objpfx)tst-bz21269: $(shared-thread-library)
 endif
 
 ifeq ($(subdir),elf)
diff --git a/sysdeps/unix/sysv/linux/i386/sigaction.c b/sysdeps/unix/sysv/linux/i386/sigaction.c
index 041b094..4a149ce 100644
--- a/sysdeps/unix/sysv/linux/i386/sigaction.c
+++ b/sysdeps/unix/sysv/linux/i386/sigaction.c
@@ -32,6 +32,8 @@ extern void restore (void) asm ("__restore") attribute_hidden;
          (kact)->sa_restorer = (((act)->sa_flags & SA_SIGINFO)	\
 			       ? &restore_rt : &restore);	\
        }							\
+     else							\
+       (kact)->sa_restorer = NULL;				\
   })
 
 #define RESET_SA_RESTORER(act, kact) \
diff --git a/sysdeps/unix/sysv/linux/i386/tst-bz21269.c b/sysdeps/unix/sysv/linux/i386/tst-bz21269.c
new file mode 100644
index 0000000..353e365
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/tst-bz21269.c
@@ -0,0 +1,233 @@
+/* Test for i386 sigaction sa_restorer handling (BZ#21269)
+   Copyright (C) 2017 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
+   <http://www.gnu.org/licenses/>.  */
+
+/* This is based on Linux test tools/testing/selftests/x86/ldt_gdt.c,
+   more specifically in do_multicpu_tests function.  The main changes
+   are:
+
+   - C11 atomics instead of plain access.
+   - Remove x86_64 support which simplifies the syscall handling
+     and fallbacks.
+   - Replicate only the test required to trigger the issue for the
+     BZ#21269.  */
+
+#include <stdatomic.h>
+
+#include <asm/ldt.h>
+#include <linux/futex.h>
+
+#include <setjmp.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+
+#include <support/xunistd.h>
+#include <support/check.h>
+#include <support/xthread.h>
+
+static int
+xset_thread_area (struct user_desc *u_info)
+{
+  long ret = syscall (SYS_set_thread_area, u_info);
+  TEST_VERIFY_EXIT (ret == 0);
+  return ret;
+}
+
+static void
+xmodify_ldt (int func, const void *ptr, unsigned long bytecount)
+{
+  TEST_VERIFY_EXIT (syscall (SYS_modify_ldt, 1, ptr, bytecount) == 0);
+}
+
+static int
+futex (int *uaddr, int futex_op, int val, void *timeout, int *uaddr2,
+	int val3)
+{
+  return syscall (SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3);
+}
+
+static void
+xsethandler (int sig, void (*handler)(int, siginfo_t *, void *), int flags)
+{
+  struct sigaction sa = { 0 };
+  sa.sa_sigaction = handler;
+  sa.sa_flags = SA_SIGINFO | flags;
+  TEST_VERIFY_EXIT (sigemptyset (&sa.sa_mask) == 0);
+  TEST_VERIFY_EXIT (sigaction (sig, &sa, 0) == 0);
+}
+
+static jmp_buf jmpbuf;
+
+static void
+sigsegv_handler (int sig, siginfo_t *info, void *ctx_void)
+{
+  siglongjmp (jmpbuf, 1);
+}
+
+/* Points to an array of 1024 ints, each holding its own index.  */
+static const unsigned int *counter_page;
+static struct user_desc *low_user_desc;
+static struct user_desc *low_user_desc_clear; /* Used to delete GDT entry.  */
+static int gdt_entry_num;
+
+static void
+setup_counter_page (void)
+{
+  long page_size = sysconf (_SC_PAGE_SIZE);
+  TEST_VERIFY_EXIT (page_size > 0);
+  unsigned int *page = xmmap (NULL, page_size, PROT_READ | PROT_WRITE,
+			      MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1);
+  for (int i = 0; i < (page_size / sizeof (unsigned int)); i++)
+    page[i] = i;
+  counter_page = page;
+}
+
+static void
+setup_low_user_desc (void)
+{
+  low_user_desc = xmmap (NULL, 2 * sizeof (struct user_desc),
+			 PROT_READ | PROT_WRITE,
+			 MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1);
+
+  low_user_desc->entry_number    = -1;
+  low_user_desc->base_addr       = (unsigned long) &counter_page[1];
+  low_user_desc->limit           = 0xffff;
+  low_user_desc->seg_32bit       = 1;
+  low_user_desc->contents        = 0;
+  low_user_desc->read_exec_only  = 0;
+  low_user_desc->limit_in_pages  = 1;
+  low_user_desc->seg_not_present = 0;
+  low_user_desc->useable         = 0;
+
+  xset_thread_area (low_user_desc);
+
+  low_user_desc_clear = low_user_desc + 1;
+  low_user_desc_clear->entry_number = gdt_entry_num;
+  low_user_desc_clear->read_exec_only = 1;
+  low_user_desc_clear->seg_not_present = 1;
+}
+
+/* Possible values of futex:
+   0: thread is idle.
+   1: thread armed.
+   2: thread should clear LDT entry 0.
+   3: thread should exit.  */
+static atomic_uint ftx;
+
+static void *
+threadproc (void *ctx)
+{
+  while (1)
+    {
+      futex ((int *) &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
+      while (atomic_load (&ftx) != 2)
+	{
+	  if (atomic_load (&ftx) >= 3)
+	    return NULL;
+	}
+
+      /* clear LDT entry 0.  */
+      const struct user_desc desc = { 0 };
+      xmodify_ldt (1, &desc, sizeof (desc));
+
+      /* If ftx == 2, set it to zero,  If ftx == 100, quit.  */
+      if (atomic_fetch_add (&ftx, -2) != 2)
+	return NULL;
+    }
+}
+
+
+/* As described in testcase, for historical reasons x86_32 Linux (and compat
+   on x86_64) interprets SA_RESTORER clear with nonzero sa_restorer as a
+   request for stack switching if the SS segment is 'funny' (this is default
+   scenario for vDSO system).  This means that anything that tries to mix
+   signal handling with segmentation should explicit clear the sa_restorer.
+
+   This testcase check if sigaction in fact does it by changing the local
+   descriptor table (LDT) through the modify_ldt syscall and triggering
+   a synchronous segfault on iret fault by trying to install an invalid
+   segment.  With a correct zeroed sa_restorer it should not trigger an
+   'real' SEGSEGV and allows the siglongjmp in signal handler.  */
+
+static int
+do_test (void)
+{
+  setup_counter_page ();
+  setup_low_user_desc ();
+
+  pthread_t thread;
+  unsigned short orig_ss;
+
+  xsethandler (SIGSEGV, sigsegv_handler, 0);
+  /* 32-bit kernels send SIGILL instead of SIGSEGV on IRET faults.  */
+  xsethandler (SIGILL, sigsegv_handler, 0);
+
+  thread = xpthread_create (0, threadproc, 0);
+
+  asm volatile ("mov %%ss, %0" : "=rm" (orig_ss));
+
+  for (int i = 0; i < 5; i++)
+    {
+      if (sigsetjmp (jmpbuf, 1) != 0)
+	continue;
+
+      /* Make sure the thread is ready after the last test. */
+      while (atomic_load (&ftx) != 0)
+	;
+
+      struct user_desc desc = {
+	.entry_number       = 0,
+	.base_addr          = 0,
+	.limit              = 0xffff,
+	.seg_32bit          = 1,
+	.contents           = 0,
+	.read_exec_only     = 0,
+	.limit_in_pages     = 1,
+	.seg_not_present    = 0,
+	.useable            = 0
+      };
+
+      xmodify_ldt (0x11, &desc, sizeof (desc));
+
+      /* Arm the thread.  */
+      ftx = 1;
+      futex ((int*) &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
+
+      asm volatile ("mov %0, %%ss" : : "r" (0x7));
+
+      /* Fire up thread modify_ldt call.  */
+      atomic_store (&ftx, 2);
+
+      while (atomic_load (&ftx) != 0)
+	;
+
+      /* On success, modify_ldt will segfault us synchronously and we will
+	 escape via siglongjmp.  */
+      support_record_failure ();
+    }
+
+  atomic_store (&ftx, 100);
+  futex ((int*) &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
+
+  xpthread_join (thread);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
2.7.4

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] linux: Consolidate sigaction implementation
@ 2017-11-17 20:35 Adhemerval Zanella
  2017-11-17 20:34 ` [PATCH 2/2] i386: Fix i386 sigaction sa_restorer initialization (BZ#21269) Adhemerval Zanella
  2018-12-10 17:01 ` [PATCH 1/2] linux: Consolidate sigaction implementation Andreas Schwab
  0 siblings, 2 replies; 4+ messages in thread
From: Adhemerval Zanella @ 2017-11-17 20:35 UTC (permalink / raw)
  To: libc-alpha

This patch consolidates all Linux sigaction implementation on a default
one at sysdeps/unix/sysv/linux/sigaction.c.  The idea is remove redundant
code and simplify new ports addition by following the current generic
Linux User API (UAPI).

The UAPI for new ports defines a generic extensible sigaction struct as:

  struct sigaction
  {
    __sighandler_t sa_handler;
    unsigned long sa_flags;
  #ifdef SA_RESTORER
    void (*sa_restorer) (void);
  #endif
    sigset_t sa_mask;
  };

Where SA_RESTORER is just placed to compatibility reasons, news ports
should not add it.  A similar definition is used on generic
kernel_sigaction.h.

The user exported sigaction definition is not changed, so for most
architectures it requires an adjustment to kernel expected one for the
syscall.

The main changes are:

  - All architectures now define and use a kernel_sigaction struct meant
    for the syscall, even for the architectures where the user sigaction
    has the same layout of the kernel expected one (s390-64 and ia64).
    Although it requires more work for these architectures, it simplifies
    the generic implementation. Also, sigaction is hardly a hotspot where
    micro optimization would play an important role.

  - The generic kernel_sigaction definition is now aligned with expected
    UAPI one for newer ports, where SA_RESTORER and sa_restorer is not
    expected to be defined.  This means adding kernel_sigaction for
    current architectures that does define it (m68k, nios2, powerpc, s390,
    sh, sparc, and tile) and which rely on previous generic definition.

  - Remove old MIPS usage of sa_restorer.  This was removed since 2.6.27
    (2957c9e61ee9c - "[MIPS] IRIX: Goodbye and thanks for all the fish").

So for new ports the generic implementation should work if its uses
Linux UAPI.  If SA_RESTORER is still required (due some architecture
limitation), it should define its own kernel_sigaction.h, define it and
include generic header (assuming it still uses the default generic kernel
layout).

Checked on x86_64-linux-gnu, i686-linux-gnu, arm-linux-gnueabihf,
aarch64-linux-gnu, sparc64-linux-gnu, sparcv9-linux-gnu, powerpc-linux-gnu,
and powerpc64-linux-gnu.  I also check the build on all remaining affected
ABIs.

	* sysdeps/unix/sysv/linux/aarch64/sigaction.c: Use default Linux version
	as base implementation.
	* sysdeps/unix/sysv/linux/arm/sigaction.c: Likewise.
	* sysdeps/unix/sysv/linux/i386/sigaction.c: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/sigaction.c: Likewise.
	* sysdeps/unix/sysv/linux/alpha/kernel_sigaction.h: Add include guards,
	remove unrequired definitions and update comments.
	* sysdeps/unix/sysv/linux/kernel_sigaction.h: Likewise.
	* sysdeps/unix/sysv/linux/mips/kernel_sigaction.h: Likewise.
	* sysdeps/unix/sysv/linux/ia64/kernel_sigaction.h: New file.
	* sysdeps/unix/sysv/linux/m68k/kernel_sigaction.h: Likewise.
	* sysdeps/unix/sysv/linux/nios2/kernel_sigaction.h: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/kernel_sigaction: Likewise.
	* sysdeps/unix/sysv/linux/s390/kernel_sigaction.h: Likewise.
	* sysdeps/unix/sysv/linux/sh/kernel_sigaction.h: Likewise.
	* sysdeps/unix/sysv/linux/sparc/kernel_sigaction.h: Likewise.
	* sysdeps/unix/sysv/linux/tile/kernel_sigaction.h: Likewise.
	* sysdeps/unix/sysv/linux/ia64/sigaction.c: Remove file.
	* sysdeps/unix/sysv/linux/mips/sigaction.c: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/sigaction.c: Likewise.
	* sysdeps/unix/sysv/linux/sigaction.c: Add STUB, SET_SA_RESTORER,
	and RESET_SA_RESTORER hooks.

Signed-off-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
---
 ChangeLog                                          |  27 +++++
 sysdeps/unix/sysv/linux/aarch64/sigaction.c        |  58 ++---------
 sysdeps/unix/sysv/linux/alpha/kernel_sigaction.h   |  21 ++--
 sysdeps/unix/sysv/linux/arm/sigaction.c            |  79 +++-----------
 sysdeps/unix/sysv/linux/i386/sigaction.c           |  76 +++-----------
 sysdeps/unix/sysv/linux/ia64/kernel_sigaction.h    |   6 ++
 sysdeps/unix/sysv/linux/ia64/sigaction.c           |  45 --------
 sysdeps/unix/sysv/linux/kernel_sigaction.h         |  31 +++---
 sysdeps/unix/sysv/linux/m68k/kernel_sigaction.h    |  22 ++++
 sysdeps/unix/sysv/linux/mips/kernel_sigaction.h    |  48 ++-------
 sysdeps/unix/sysv/linux/mips/sigaction.c           | 116 ---------------------
 sysdeps/unix/sysv/linux/nios2/kernel_sigaction.h   |   8 ++
 sysdeps/unix/sysv/linux/powerpc/kernel_sigaction.h |   8 ++
 sysdeps/unix/sysv/linux/s390/kernel_sigaction.h    |  28 +++++
 sysdeps/unix/sysv/linux/s390/s390-64/sigaction.c   |  43 --------
 sysdeps/unix/sysv/linux/sh/kernel_sigaction.h      |   8 ++
 sysdeps/unix/sysv/linux/sigaction.c                |  28 ++---
 sysdeps/unix/sysv/linux/sparc/kernel_sigaction.h   |  10 ++
 sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c  |  41 +-------
 sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c  |  43 +-------
 sysdeps/unix/sysv/linux/tile/kernel_sigaction.h    |   9 ++
 sysdeps/unix/sysv/linux/x86_64/sigaction.c         |  61 ++---------
 22 files changed, 232 insertions(+), 584 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/ia64/kernel_sigaction.h
 delete mode 100644 sysdeps/unix/sysv/linux/ia64/sigaction.c
 create mode 100644 sysdeps/unix/sysv/linux/m68k/kernel_sigaction.h
 delete mode 100644 sysdeps/unix/sysv/linux/mips/sigaction.c
 create mode 100644 sysdeps/unix/sysv/linux/nios2/kernel_sigaction.h
 create mode 100644 sysdeps/unix/sysv/linux/powerpc/kernel_sigaction.h
 create mode 100644 sysdeps/unix/sysv/linux/s390/kernel_sigaction.h
 delete mode 100644 sysdeps/unix/sysv/linux/s390/s390-64/sigaction.c
 create mode 100644 sysdeps/unix/sysv/linux/sh/kernel_sigaction.h
 create mode 100644 sysdeps/unix/sysv/linux/sparc/kernel_sigaction.h
 create mode 100644 sysdeps/unix/sysv/linux/tile/kernel_sigaction.h

diff --git a/sysdeps/unix/sysv/linux/aarch64/sigaction.c b/sysdeps/unix/sysv/linux/aarch64/sigaction.c
index 7cbb056..1eaf1d0 100644
--- a/sysdeps/unix/sysv/linux/aarch64/sigaction.c
+++ b/sysdeps/unix/sysv/linux/aarch64/sigaction.c
@@ -1,5 +1,4 @@
 /* Copyright (C) 1997-2017 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
@@ -16,55 +15,16 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-
-#include <sysdep.h>
-#include <sys/syscall.h>
-
+/* Required for AArch32 compatibility. */
 #define SA_RESTORER	0x04000000
 
-/* The difference here is that the sigaction structure used in the
-   kernel is not the same as we use in the libc.  Therefore we must
-   translate it here.  */
-#include <kernel_sigaction.h>
-
-int
-__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
-{
-  int result;
-  struct kernel_sigaction kact;
-  struct kernel_sigaction koact;
-
-  if (act)
-    {
-      kact.k_sa_handler = act->sa_handler;
-      memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
-      kact.sa_flags = act->sa_flags;
-#ifdef HAVE_SA_RESTORER
-      if (kact.sa_flags & SA_RESTORER)
-	kact.sa_restorer = act->sa_restorer;
-#endif
-    }
+#define SET_SA_RESTORER(kact, act)				\
+ ({								\
+    if ((kact)->sa_flags & SA_RESTORER)				\
+      (kact)->sa_restorer = (act)->sa_restorer;			\
+ })
 
-  result = INLINE_SYSCALL (rt_sigaction, 4, sig,
-			   act ? &kact : NULL,
-			   oact ? &koact : NULL, _NSIG / 8);
-  if (result >= 0 || errno != ENOSYS)
-    {
-      if (oact && result >= 0)
-	{
-	  oact->sa_handler = koact.k_sa_handler;
-	  memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
-	  oact->sa_flags = koact.sa_flags;
-#ifdef HAVE_SA_RESTORER
-	  oact->sa_restorer = koact.sa_restorer;
-#endif
-	}
-    }
-  return result;
-}
-libc_hidden_def (__libc_sigaction)
+#define RESET_SA_RESTORER(act, kact)				\
+  (act)->sa_restorer = (kact)->sa_restorer;
 
-#include <nptl/sigaction.c>
+#include <sysdeps/unix/sysv/linux/sigaction.c>
diff --git a/sysdeps/unix/sysv/linux/alpha/kernel_sigaction.h b/sysdeps/unix/sysv/linux/alpha/kernel_sigaction.h
index 4c35d96..25180ff 100644
--- a/sysdeps/unix/sysv/linux/alpha/kernel_sigaction.h
+++ b/sysdeps/unix/sysv/linux/alpha/kernel_sigaction.h
@@ -1,15 +1,12 @@
-/* This is the sigaction struction from the Linux 2.1.20 kernel.  */
+#ifndef _KERNEL_SIGACTION_H
+# define _KERNEL_SIGACTION_H
 
-struct old_kernel_sigaction {
-	__sighandler_t k_sa_handler;
-	unsigned long sa_mask;
-	unsigned int sa_flags;
+/* This is the sigaction structure from the Linux 3.2 kernel.  */
+struct kernel_sigaction
+{
+  __sighandler_t k_sa_handler;
+  unsigned int sa_flags;
+  sigset_t sa_mask;
 };
 
-/* This is the sigaction structure from the Linux 2.1.68 kernel.  */
-
-struct kernel_sigaction {
-	__sighandler_t k_sa_handler;
-	unsigned int sa_flags;
-	sigset_t sa_mask;
-};
+#endif
diff --git a/sysdeps/unix/sysv/linux/arm/sigaction.c b/sysdeps/unix/sysv/linux/arm/sigaction.c
index e4c0d97..b7b141a 100644
--- a/sysdeps/unix/sysv/linux/arm/sigaction.c
+++ b/sysdeps/unix/sysv/linux/arm/sigaction.c
@@ -15,70 +15,25 @@
    License along with the GNU C Library.  If not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-
-#include <sysdep.h>
-#include <sys/syscall.h>
-
-/* The difference here is that the sigaction structure used in the
-   kernel is not the same as we use in the libc.  Therefore we must
-   translate it here.  */
-#include <kernel_sigaction.h>
-
 #define SA_RESTORER	0x04000000
 
 extern void __default_sa_restorer (void);
 extern void __default_rt_sa_restorer (void);
 
-/* When RT signals are in use we need to use a different return stub.  */
-#define choose_restorer(flags)					\
-  (flags & SA_SIGINFO) ? __default_rt_sa_restorer		\
-  : __default_sa_restorer
-
-/* 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
-__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
-{
-  int result;
-
-  struct kernel_sigaction kact, koact;
-
-  if (act)
-    {
-      kact.k_sa_handler = act->sa_handler;
-      memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
-      kact.sa_flags = act->sa_flags;
-#ifdef HAVE_SA_RESTORER
-      if (kact.sa_flags & SA_RESTORER)
-	kact.sa_restorer = act->sa_restorer;
-      else
-	{
-	  kact.sa_restorer = choose_restorer (kact.sa_flags);
-	  kact.sa_flags |= SA_RESTORER;
-	}
-#endif
-    }
-
-  /* XXX The size argument hopefully will have to be changed to the
-     real size of the user-level sigset_t.  */
-  result = INLINE_SYSCALL (rt_sigaction, 4, sig,
-			   act ? &kact : NULL,
-			   oact ? &koact : NULL, _NSIG / 8);
-
-  if (oact && result >= 0)
-    {
-      oact->sa_handler = koact.k_sa_handler;
-      memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
-      oact->sa_flags = koact.sa_flags;
-#ifdef HAVE_SA_RESTORER
-      oact->sa_restorer = koact.sa_restorer;
-#endif
-    }
-  return result;
-}
-libc_hidden_def (__libc_sigaction)
-
-#include <nptl/sigaction.c>
+#define SET_SA_RESTORER(kact, act)				\
+ ({								\
+   if ((kact)->sa_flags & SA_RESTORER)				\
+     (kact)->sa_restorer = (act)->sa_restorer;			\
+   else								\
+     {								\
+       (kact)->sa_restorer = ((kact)->sa_flags & SA_SIGINFO)	\
+			     ? __default_rt_sa_restorer		\
+			     : __default_sa_restorer;		\
+       (kact)->sa_flags |= SA_RESTORER;				\
+     }								\
+ })
+
+#define RESET_SA_RESTORER(act, kact)				\
+  (act)->sa_restorer = (kact)->sa_restorer;
+
+#include <sysdeps/unix/sysv/linux/sigaction.c>
diff --git a/sysdeps/unix/sysv/linux/i386/sigaction.c b/sysdeps/unix/sysv/linux/i386/sigaction.c
index 0cc9d67..041b094 100644
--- a/sysdeps/unix/sysv/linux/i386/sigaction.c
+++ b/sysdeps/unix/sysv/linux/i386/sigaction.c
@@ -16,78 +16,28 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <sysdep.h>
-#include <errno.h>
-#include <stddef.h>
 #include <signal.h>
-#include <string.h>
-
-#include <sysdep.h>
-#include <sys/syscall.h>
 #include <ldsodefs.h>
 
-/* The difference here is that the sigaction structure used in the
-   kernel is not the same as we use in the libc.  Therefore we must
-   translate it here.  */
-#include <kernel_sigaction.h>
-
-/* We do not globally define the SA_RESTORER flag so do it here.  */
 #define SA_RESTORER 0x04000000
 
-
-/* Using the hidden attribute here does not change the code but it
-   helps to avoid warnings.  */
-#ifdef __NR_rt_sigaction
 extern void restore_rt (void) asm ("__restore_rt") attribute_hidden;
-#endif
 extern void restore (void) asm ("__restore") attribute_hidden;
 
+#define SET_SA_RESTORER(kact, act)				\
+  ({								\
+     if (GLRO(dl_sysinfo_dso) == NULL)				\
+       {							\
+	 (kact)->sa_flags |= SA_RESTORER;			\
+         (kact)->sa_restorer = (((act)->sa_flags & SA_SIGINFO)	\
+			       ? &restore_rt : &restore);	\
+       }							\
+  })
 
-/* 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
-__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
-{
-  int result;
-
-  struct kernel_sigaction kact, koact;
-
-  if (act)
-    {
-      kact.k_sa_handler = act->sa_handler;
-      kact.sa_flags = act->sa_flags;
-      memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
-
-      if (GLRO(dl_sysinfo_dso) == NULL)
-	{
-	  kact.sa_flags |= SA_RESTORER;
-
-	  kact.sa_restorer = ((act->sa_flags & SA_SIGINFO)
-			      ? &restore_rt : &restore);
-	}
-    }
-
-  /* XXX The size argument hopefully will have to be changed to the
-     real size of the user-level sigset_t.  */
-  INTERNAL_SYSCALL_DECL (err);
-  result = INTERNAL_SYSCALL (rt_sigaction, err, 4,
-			     sig, act ? &kact : NULL,
-			     oact ? &koact : NULL, _NSIG / 8);
-  if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (result, err)))
-     return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (result,
-								       err));
-  else if (oact && result >= 0)
-    {
-      oact->sa_handler = koact.k_sa_handler;
-      memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
-      oact->sa_flags = koact.sa_flags;
-      oact->sa_restorer = koact.sa_restorer;
-    }
-  return result;
-}
-libc_hidden_def (__libc_sigaction)
+#define RESET_SA_RESTORER(act, kact) \
+  (act)->sa_restorer = (kact)->sa_restorer
 
-#include <nptl/sigaction.c>
+#include <sysdeps/unix/sysv/linux/sigaction.c>
 
 /* NOTE: Please think twice before making any changes to the bits of
    code below.  GDB needs some intimate knowledge about it to
@@ -108,10 +58,8 @@ asm						\
    "	int  $0x80"				\
    );
 
-#ifdef __NR_rt_sigaction
 /* The return code for realtime-signals.  */
 RESTORE (restore_rt, __NR_rt_sigreturn)
-#endif
 
 /* For the boring old signals.  */
 #undef RESTORE2
diff --git a/sysdeps/unix/sysv/linux/ia64/kernel_sigaction.h b/sysdeps/unix/sysv/linux/ia64/kernel_sigaction.h
new file mode 100644
index 0000000..05813db
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/ia64/kernel_sigaction.h
@@ -0,0 +1,6 @@
+/* This is the sigaction structure from the Linux 3.2 kernel.  */
+struct kernel_sigaction {
+        __sighandler_t k_sa_handler;
+        unsigned long sa_flags;
+        sigset_t sa_mask;               /* mask last for extensibility */
+};
diff --git a/sysdeps/unix/sysv/linux/ia64/sigaction.c b/sysdeps/unix/sysv/linux/ia64/sigaction.c
deleted file mode 100644
index 125ce44..0000000
--- a/sysdeps/unix/sysv/linux/ia64/sigaction.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright (C) 1997-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Linux/IA64 specific sigaction
-   Written by Jes Sorensen, <Jes.Sorensen@cern.ch>, April 1999.
-
-   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
-   <http://www.gnu.org/licenses/>.  */
-
-/* Linux/ia64 only has rt signals, thus we do not even want to try falling
-   back to the old style signals as the default Linux handler does. */
-
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-
-#include <sysdep.h>
-#include <sys/syscall.h>
-
-/* The variable is shared between all wrappers around signal handling
-   functions which have RT equivalents.  This is the definition.  */
-
-
-/* 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
-__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
-{
-  /* XXX The size argument hopefully will have to be changed to the
-     real size of the user-level sigset_t.  */
-  return INLINE_SYSCALL (rt_sigaction, 4, sig, act, oact, _NSIG / 8);
-}
-libc_hidden_def (__libc_sigaction)
-
-#include <nptl/sigaction.c>
diff --git a/sysdeps/unix/sysv/linux/kernel_sigaction.h b/sysdeps/unix/sysv/linux/kernel_sigaction.h
index d005cbc..2dbec08 100644
--- a/sysdeps/unix/sysv/linux/kernel_sigaction.h
+++ b/sysdeps/unix/sysv/linux/kernel_sigaction.h
@@ -1,19 +1,20 @@
-/* This is the sigaction structure from the Linux 2.1.20 kernel.  */
+#ifndef _KERNEL_SIGACTION_H
+# define _KERNEL_SIGACTION_H
 
-#define HAVE_SA_RESTORER
-
-struct old_kernel_sigaction {
-	__sighandler_t k_sa_handler;
-	unsigned long sa_mask;
-	unsigned long sa_flags;
-	void (*sa_restorer) (void);
+/* This is the sigaction structure from the Linux 3.2 kernel.  */
+struct kernel_sigaction
+{
+  __sighandler_t k_sa_handler;
+  unsigned long sa_flags;
+#ifdef SA_RESTORER
+  void (*sa_restorer) (void);
+#endif
+  sigset_t sa_mask;
 };
 
-/* This is the sigaction structure from the Linux 2.1.68 kernel.  */
+#ifndef SA_RESTORER
+# define SET_SA_RESTORER(kact, act)
+# define RESET_SA_RESTORER(act, kact)
+#endif
 
-struct kernel_sigaction {
-	__sighandler_t k_sa_handler;
-	unsigned long sa_flags;
-	void (*sa_restorer) (void);
-	sigset_t sa_mask;
-};
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/kernel_sigaction.h b/sysdeps/unix/sysv/linux/m68k/kernel_sigaction.h
new file mode 100644
index 0000000..54972fe
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/m68k/kernel_sigaction.h
@@ -0,0 +1,22 @@
+#ifndef _KERNEL_SIGACTION_H
+# define _KERNEL_SIGACTION_H
+
+#include <signal.h>
+
+#define SA_RESTORER 0x04000000
+
+/* This is the sigaction structure from the Linux 3.2 kernel.  */
+struct kernel_sigaction
+{
+  __sighandler_t k_sa_handler;
+  sigset_t sa_mask;
+  unsigned long sa_flags;
+  void (*sa_restorer) (void);
+};
+
+#define SET_SA_RESTORER(kact, act)			\
+  (kact)->sa_restorer = (act)->sa_restorer
+#define RESET_SA_RESTORER(act, kact)			\
+  (act)->sa_restorer = (kact)->sa_restorer
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/mips/kernel_sigaction.h b/sysdeps/unix/sysv/linux/mips/kernel_sigaction.h
index b6f52cc..beef976 100644
--- a/sysdeps/unix/sysv/linux/mips/kernel_sigaction.h
+++ b/sysdeps/unix/sysv/linux/mips/kernel_sigaction.h
@@ -1,40 +1,12 @@
-/* This is the sigaction structure from the Linux 2.1.24 kernel.  */
-
-#include <sgidefs.h>
-
-#define HAVE_SA_RESTORER
-
-struct old_kernel_sigaction {
-	unsigned int	sa_flags;
-	__sighandler_t	k_sa_handler;
-	unsigned long	sa_mask;
-	unsigned int    __pad0[3]; /* reserved, keep size constant */
-
-	/* Abi says here follows reserved int[2] */
-	void		(*sa_restorer)(void);
-#if (_MIPS_SZPTR < 64)
-	/*
-	 * For 32 bit code we have to pad struct sigaction to get
-	 * constant size for the ABI
-	 */
-	int		pad1[1]; /* reserved */
-#endif
+#ifndef _KERNEL_SIGACTION_H
+# define _KERNEL_SIGACTION_H
+
+/* This is the sigaction structure from the Linux 3.2 kernel.  */
+struct kernel_sigaction
+{
+  unsigned int    sa_flags;
+  __sighandler_t  k_sa_handler;
+  sigset_t        sa_mask;
 };
 
-
-#define _KERNEL_NSIG	       128
-#define _KERNEL_NSIG_BPW       _MIPS_SZLONG
-#define _KERNEL_NSIG_WORDS     (_KERNEL_NSIG / _KERNEL_NSIG_BPW)
-
-typedef struct {
-	unsigned long sig[_KERNEL_NSIG_WORDS];
-} kernel_sigset_t;
-
-/* This is the sigaction structure from the Linux 2.1.68 kernel.  */
-struct kernel_sigaction {
-	unsigned int	sa_flags;
-	__sighandler_t	k_sa_handler;
-	kernel_sigset_t	sa_mask;
-	void		(*sa_restorer)(void);
-	int		s_resv[1]; /* reserved */
-};
+#endif
diff --git a/sysdeps/unix/sysv/linux/mips/sigaction.c b/sysdeps/unix/sysv/linux/mips/sigaction.c
deleted file mode 100644
index f6be3f2..0000000
--- a/sysdeps/unix/sysv/linux/mips/sigaction.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* Copyright (C) 1997-2017 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
-   <http://www.gnu.org/licenses/>.  */
-
-#include <errno.h>
-#include <sgidefs.h>
-#include <signal.h>
-#include <string.h>
-
-#include <sysdep.h>
-#include <sys/syscall.h>
-
-#include <sgidefs.h>
-
-/* The difference here is that the sigaction structure used in the
-   kernel is not the same as we use in the libc.  Therefore we must
-   translate it here.  */
-#include <kernel_sigaction.h>
-
-#if _MIPS_SIM != _ABIO32
-
-# ifdef __NR_rt_sigreturn
-static void restore_rt (void) asm ("__restore_rt");
-# endif
-# ifdef __NR_sigreturn
-static void restore (void) asm ("__restore");
-# endif
-#endif
-
-/* 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
-__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
-{
-  int result;
-
-  struct kernel_sigaction kact, koact;
-
-  if (act)
-    {
-      kact.k_sa_handler = act->sa_handler;
-      memcpy (&kact.sa_mask, &act->sa_mask, sizeof (kernel_sigset_t));
-      kact.sa_flags = act->sa_flags;
-#ifdef HAVE_SA_RESTORER
-# if _MIPS_SIM == _ABIO32
-      kact.sa_restorer = act->sa_restorer;
-# else
-      kact.sa_restorer = &restore_rt;
-# endif
-#endif
-    }
-
-  /* XXX The size argument hopefully will have to be changed to the
-     real size of the user-level sigset_t.	*/
-  result = INLINE_SYSCALL (rt_sigaction, 4, sig,
-			   act ? &kact : NULL,
-			   oact ? &koact : NULL,
-			   sizeof (kernel_sigset_t));
-
-  if (oact && result >= 0)
-    {
-      oact->sa_handler = koact.k_sa_handler;
-      memcpy (&oact->sa_mask, &koact.sa_mask,
-	      sizeof (kernel_sigset_t));
-      oact->sa_flags = koact.sa_flags;
-#ifdef HAVE_SA_RESTORER
-      oact->sa_restorer = koact.sa_restorer;
-#endif
-    }
-  return result;
-}
-libc_hidden_def (__libc_sigaction)
-
-#include <nptl/sigaction.c>
-
-
-/* NOTE: Please think twice before making any changes to the bits of
-   code below.  GDB needs some intimate knowledge about it to
-   recognize them as signal trampolines, and make backtraces through
-   signal handlers work right.  Important are both the names
-   (__restore_rt) and the exact instruction sequence.
-   If you ever feel the need to make any changes, please notify the
-   appropriate GDB maintainer.  */
-
-#define RESTORE(name, syscall) RESTORE2 (name, syscall)
-#define RESTORE2(name, syscall) \
-asm						\
-  (						\
-   ".align 4\n"					\
-   "__" #name ":\n"				\
-   "	li $2, " #syscall "\n"			\
-   "	syscall\n"				\
-   );
-
-/* The return code for realtime-signals.  */
-#if _MIPS_SIM != _ABIO32
-# ifdef __NR_rt_sigreturn
-RESTORE (restore_rt, __NR_rt_sigreturn)
-# endif
-# ifdef __NR_sigreturn
-RESTORE (restore, __NR_sigreturn)
-# endif
-#endif
diff --git a/sysdeps/unix/sysv/linux/nios2/kernel_sigaction.h b/sysdeps/unix/sysv/linux/nios2/kernel_sigaction.h
new file mode 100644
index 0000000..4ada322
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/nios2/kernel_sigaction.h
@@ -0,0 +1,8 @@
+/* NIOS2 uses the generic Linux UAPI but defines SA_RESTORER.  */
+#define SA_RESTORER 0x04000000
+#include <sysdeps/unix/sysv/linux/kernel_sigaction.h>
+
+#define SET_SA_RESTORER(kact, act)             \
+  (kact)->sa_restorer = (act)->sa_restorer
+#define RESET_SA_RESTORER(act, kact)           \
+  (act)->sa_restorer = (kact)->sa_restorer
diff --git a/sysdeps/unix/sysv/linux/powerpc/kernel_sigaction.h b/sysdeps/unix/sysv/linux/powerpc/kernel_sigaction.h
new file mode 100644
index 0000000..c5213f2
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/kernel_sigaction.h
@@ -0,0 +1,8 @@
+/* powerpc kernel sigaction is similar to generic Linux UAPI one.  */
+#define SA_RESTORER 0x04000000
+#include <sysdeps/unix/sysv/linux/kernel_sigaction.h>
+
+#define SET_SA_RESTORER(kact, act)             \
+  (kact)->sa_restorer = (act)->sa_restorer
+#define RESET_SA_RESTORER(act, kact)           \
+  (act)->sa_restorer = (kact)->sa_restorer
diff --git a/sysdeps/unix/sysv/linux/s390/kernel_sigaction.h b/sysdeps/unix/sysv/linux/s390/kernel_sigaction.h
new file mode 100644
index 0000000..a8beaf7
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/kernel_sigaction.h
@@ -0,0 +1,28 @@
+#include <bits/types/siginfo_t.h>
+
+#define SA_RESTORER	0x04000000
+
+/* This is the sigaction structure from the Linux 3.2 kernel.  */
+struct kernel_sigaction
+{
+  union
+  {
+    __sighandler_t _sa_handler;
+    void (*_sa_sigaction)(int, siginfo_t *, void *);
+  } _u;
+#define k_sa_handler _u._sa_handler
+#ifndef __s390x__
+  sigset_t sa_mask;
+  unsigned long sa_flags;
+  void (*sa_restorer)(void);
+#else
+  unsigned long sa_flags;
+  void (*sa_restorer)(void);
+  sigset_t sa_mask;
+#endif
+};
+
+#define SET_SA_RESTORER(kact, act)             \
+  (kact)->sa_restorer = (act)->sa_restorer
+#define RESET_SA_RESTORER(act, kact)           \
+  (act)->sa_restorer = (kact)->sa_restorer
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/sigaction.c b/sysdeps/unix/sysv/linux/s390/s390-64/sigaction.c
deleted file mode 100644
index a3de0ea..0000000
--- a/sysdeps/unix/sysv/linux/s390/s390-64/sigaction.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Copyright (C) 2001-2017 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
-   <http://www.gnu.org/licenses/>.  */
-
-/* 64 bit Linux for S/390 only has rt signals, thus we do not even want to try
-   falling back to the old style signals as the default Linux handler does. */
-
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-
-#include <sysdep.h>
-#include <sys/syscall.h>
-
-/* The variable is shared between all wrappers around signal handling
-   functions which have RT equivalents.  This is the definition.  */
-
-
-/* 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
-__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
-{
-  /* XXX The size argument hopefully will have to be changed to the
-     real size of the user-level sigset_t.  */
-  return INLINE_SYSCALL (rt_sigaction, 4, sig, act, oact, _NSIG / 8);
-}
-libc_hidden_def (__libc_sigaction)
-
-#include <nptl/sigaction.c>
diff --git a/sysdeps/unix/sysv/linux/sh/kernel_sigaction.h b/sysdeps/unix/sysv/linux/sh/kernel_sigaction.h
new file mode 100644
index 0000000..7ebcd08
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sh/kernel_sigaction.h
@@ -0,0 +1,8 @@
+/* SH uses the generic Linux UAPI but defines SA_RESTORER.  */
+#define SA_RESTORER 0x04000000
+#include <sysdeps/unix/sysv/linux/kernel_sigaction.h>
+
+#define SET_SA_RESTORER(kact, act)             \
+  (kact)->sa_restorer = (act)->sa_restorer
+#define RESET_SA_RESTORER(act, kact)           \
+  (act)->sa_restorer = (kact)->sa_restorer
diff --git a/sysdeps/unix/sysv/linux/sigaction.c b/sysdeps/unix/sysv/linux/sigaction.c
index c76c937..fb84394 100644
--- a/sysdeps/unix/sysv/linux/sigaction.c
+++ b/sysdeps/unix/sysv/linux/sigaction.c
@@ -22,11 +22,19 @@
 #include <sysdep.h>
 #include <sys/syscall.h>
 
-/* The difference here is that the sigaction structure used in the
-   kernel is not the same as we use in the libc.  Therefore we must
-   translate it here.  */
+/* New ports should not define the obsolete SA_RESTORER, however some
+   architecture requires for compat mode and/or due old ABI.  */
 #include <kernel_sigaction.h>
 
+#ifndef SA_RESTORER
+# define SET_SA_RESTORER(kact, act)
+# define RESET_SA_RESTORER(act, kact)
+#endif
+
+/* SPARC passes the restore function as an argument to rt_sigaction.  */
+#ifndef STUB
+# define STUB(act)
+#endif
 
 /* 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.  */
@@ -42,25 +50,21 @@ __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
       kact.k_sa_handler = act->sa_handler;
       memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
       kact.sa_flags = act->sa_flags;
-#ifdef HAVE_SA_RESTORER
-      kact.sa_restorer = act->sa_restorer;
-#endif
+      SET_SA_RESTORER (&kact, act);
     }
 
   /* XXX The size argument hopefully will have to be changed to the
      real size of the user-level sigset_t.  */
-  result = INLINE_SYSCALL (rt_sigaction, 4, sig,
-			   act ? &kact : NULL,
-			   oact ? &koact : NULL, _NSIG / 8);
+  result = INLINE_SYSCALL_CALL (rt_sigaction, sig,
+				act ? &kact : NULL,
+				oact ? &koact : NULL, STUB(act) _NSIG / 8);
 
   if (oact && result >= 0)
     {
       oact->sa_handler = koact.k_sa_handler;
       memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
       oact->sa_flags = koact.sa_flags;
-#ifdef HAVE_SA_RESTORER
-      oact->sa_restorer = koact.sa_restorer;
-#endif
+      RESET_SA_RESTORER (oact, &koact);
     }
   return result;
 }
diff --git a/sysdeps/unix/sysv/linux/sparc/kernel_sigaction.h b/sysdeps/unix/sysv/linux/sparc/kernel_sigaction.h
new file mode 100644
index 0000000..bee7e9c
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/kernel_sigaction.h
@@ -0,0 +1,10 @@
+/* SPARC 'struct __new_sigaction' is similar to generic Linux UAPI with
+   a sa_restorer field, even though function is passed as an argument
+   to rt_sigaction syscall.  */
+#define SA_RESTORER 0x04000000
+#include <sysdeps/unix/sysv/linux/kernel_sigaction.h>
+
+#define SET_SA_RESTORER(kact, act)             \
+  (kact)->sa_restorer = NULL
+#define RESET_SA_RESTORER(act, kact)           \
+  (act)->sa_restorer = (kact)->sa_restorer
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c b/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c
index 295bfb2..59d06a4 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/sigaction.c
@@ -27,43 +27,12 @@
 static void __rt_sigreturn_stub (void);
 static void __sigreturn_stub (void);
 
-int
-__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
-{
-  struct kernel_sigaction kact, koact;
-  unsigned long stub = 0;
-  int ret;
-
-  if (act)
-    {
-      kact.k_sa_handler = act->sa_handler;
-      memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
-      if (((kact.sa_flags = act->sa_flags) & SA_SIGINFO) != 0)
-	stub = (unsigned long) &__rt_sigreturn_stub;
-      else
-	stub = (unsigned long) &__sigreturn_stub;
-      stub -= 8;
-      kact.sa_restorer = NULL;
-    }
-
-  /* XXX The size argument hopefully will have to be changed to the
-     real size of the user-level sigset_t.  */
-  ret = INLINE_SYSCALL (rt_sigaction, 5, sig, act ? &kact : 0,
-			oact ? &koact : 0, stub, _NSIG / 8);
-
-  if (oact && ret >= 0)
-    {
-      oact->sa_handler = koact.k_sa_handler;
-      memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
-      oact->sa_flags = koact.sa_flags;
-      oact->sa_restorer = koact.sa_restorer;
-    }
-  return ret;
-}
-libc_hidden_def (__libc_sigaction)
-
-#include <nptl/sigaction.c>
+#define STUB(act) \
+  ((unsigned long)((act->sa_flags & SA_SIGINFO)		\
+		    ? &__rt_sigreturn_stub		\
+		    : &__sigreturn_stub) - 8),
 
+#include <sysdeps/unix/sysv/linux/sigaction.c>
 
 static
 inhibit_stack_protector
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c b/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c
index 78f8a18..c3c3451 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/sigaction.c
@@ -21,50 +21,13 @@
 #include <string.h>
 #include <syscall.h>
 #include <sysdep.h>
-#include <sys/signal.h>
-#include <errno.h>
-
-#include <kernel_sigaction.h>
-
-/* SPARC 64bit userland requires a kernel that has rt signals anyway. */
 
 static void __rt_sigreturn_stub (void);
 
-int
-__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
-{
-  int ret;
-  struct kernel_sigaction kact, koact;
-  unsigned long stub = ((unsigned long) &__rt_sigreturn_stub) - 8;
-
-  if (act)
-    {
-      kact.k_sa_handler = act->sa_handler;
-      memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
-      kact.sa_flags = act->sa_flags;
-      kact.sa_restorer = NULL;
-    }
-
-  /* XXX The size argument hopefully will have to be changed to the
-     real size of the user-level sigset_t.  */
-  ret = INLINE_SYSCALL (rt_sigaction, 5, sig,
-			act ? &kact : 0,
-			oact ? &koact : 0, stub, _NSIG / 8);
-
-  if (oact && ret >= 0)
-    {
-      oact->sa_handler = koact.k_sa_handler;
-      memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
-      oact->sa_flags = koact.sa_flags;
-      oact->sa_restorer = koact.sa_restorer;
-    }
-
-  return ret;
-}
-libc_hidden_def (__libc_sigaction)
-
-#include <nptl/sigaction.c>
+#define STUB(act) \
+  (((unsigned long) &__rt_sigreturn_stub) - 8),
 
+#include <sysdeps/unix/sysv/linux/sigaction.c>
 
 static
 inhibit_stack_protector
diff --git a/sysdeps/unix/sysv/linux/tile/kernel_sigaction.h b/sysdeps/unix/sysv/linux/tile/kernel_sigaction.h
new file mode 100644
index 0000000..a943d52
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tile/kernel_sigaction.h
@@ -0,0 +1,9 @@
+/* tile kernel sigaction is similar to generic Linux UAPI one
+   and SA_RESTORER is used only for binary compatibility.  */
+#define SA_RESTORER 0x04000000
+#include <sysdeps/unix/sysv/linux/kernel_sigaction.h>
+
+#define SET_SA_RESTORER(kact, act)             \
+  (kact)->sa_restorer = (act)->sa_restorer
+#define RESET_SA_RESTORER(act, kact)           \
+  (act)->sa_restorer = (kact)->sa_restorer
diff --git a/sysdeps/unix/sysv/linux/x86_64/sigaction.c b/sysdeps/unix/sysv/linux/x86_64/sigaction.c
index be058ba..7924c10 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sigaction.c
+++ b/sysdeps/unix/sysv/linux/x86_64/sigaction.c
@@ -16,65 +16,20 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <sysdep.h>
-#include <errno.h>
-#include <stddef.h>
 #include <signal.h>
-#include <string.h>
-
-#include <sysdep.h>
-#include <sys/syscall.h>
-
-/* The difference here is that the sigaction structure used in the
-   kernel is not the same as we use in the libc.  Therefore we must
-   translate it here.  */
-#include <kernel_sigaction.h>
-
-#include "ucontext_i.h"
-
-/* We do not globally define the SA_RESTORER flag so do it here.  */
 #define SA_RESTORER 0x04000000
+#include <kernel_sigaction.h>
 
-/* Using the hidden attribute here does not change the code but it
-   helps to avoid warnings.  */
 extern void restore_rt (void) asm ("__restore_rt") attribute_hidden;
 
+#define SET_SA_RESTORER(kact, act)			\
+  (kact)->sa_flags = (act)->sa_flags | SA_RESTORER;	\
+  (kact)->sa_restorer = &restore_rt
 
-/* 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
-__libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
-{
-  int result;
-  struct kernel_sigaction kact, koact;
-
-  if (act)
-    {
-      kact.k_sa_handler = act->sa_handler;
-      memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
-      kact.sa_flags = act->sa_flags | SA_RESTORER;
-
-      kact.sa_restorer = &restore_rt;
-    }
-
-  /* XXX The size argument hopefully will have to be changed to the
-     real size of the user-level sigset_t.  */
-  result = INLINE_SYSCALL (rt_sigaction, 4,
-			   sig, act ? &kact : NULL,
-			   oact ? &koact : NULL, _NSIG / 8);
-  if (oact && result >= 0)
-    {
-      oact->sa_handler = koact.k_sa_handler;
-      memcpy (&oact->sa_mask, &koact.sa_mask, sizeof (sigset_t));
-      oact->sa_flags = koact.sa_flags;
-      oact->sa_restorer = koact.sa_restorer;
-    }
-  return result;
-}
-libc_hidden_def (__libc_sigaction)
-
-#include <nptl/sigaction.c>
+#define RESET_SA_RESTORER(act, kact) 			\
+  (act)->sa_restorer = (kact)->sa_restorer
 
+#include <sysdeps/unix/sysv/linux/sigaction.c>
 
 /* NOTE: Please think twice before making any changes to the bits of
    code below.  GDB needs some intimate knowledge about it to
@@ -93,6 +48,8 @@ libc_hidden_def (__libc_sigaction)
    a bit tricky.  We don't use the gas cfi directives, so that we can
    reliably add .cfi_signal_frame.  */
 
+#include "ucontext_i.h"
+
 #define do_cfa_expr						\
   "	.byte 0x0f\n"		/* DW_CFA_def_cfa_expression */	\
   "	.uleb128 2f-1f\n"	/* length */			\
-- 
2.7.4

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] linux: Consolidate sigaction implementation
  2017-11-17 20:35 [PATCH 1/2] linux: Consolidate sigaction implementation Adhemerval Zanella
  2017-11-17 20:34 ` [PATCH 2/2] i386: Fix i386 sigaction sa_restorer initialization (BZ#21269) Adhemerval Zanella
@ 2018-12-10 17:01 ` Andreas Schwab
  2018-12-11 17:49   ` Adhemerval Zanella
  1 sibling, 1 reply; 4+ messages in thread
From: Andreas Schwab @ 2018-12-10 17:01 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

On Nov 17 2017, Adhemerval Zanella <adhemerval.zanella@linaro.org> wrote:

>   - All architectures now define and use a kernel_sigaction struct meant
>     for the syscall, even for the architectures where the user sigaction
>     has the same layout of the kernel expected one (s390-64 and ia64).
>     Although it requires more work for these architectures, it simplifies
>     the generic implementation. Also, sigaction is hardly a hotspot where
>     micro optimization would play an important role.
>
>   - The generic kernel_sigaction definition is now aligned with expected
>     UAPI one for newer ports, where SA_RESTORER and sa_restorer is not
>     expected to be defined.  This means adding kernel_sigaction for
>     current architectures that does define it (m68k, nios2, powerpc, s390,
>     sh, sparc, and tile) and which rely on previous generic definition.

There is no need to define kernel_sigaction in more than one file, since
it is the same (except for the presense of sa_restorer) for all
architectures.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] linux: Consolidate sigaction implementation
  2018-12-10 17:01 ` [PATCH 1/2] linux: Consolidate sigaction implementation Andreas Schwab
@ 2018-12-11 17:49   ` Adhemerval Zanella
  0 siblings, 0 replies; 4+ messages in thread
From: Adhemerval Zanella @ 2018-12-11 17:49 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: libc-alpha



On 10/12/2018 14:28, Andreas Schwab wrote:
> On Nov 17 2017, Adhemerval Zanella <adhemerval.zanella@linaro.org> wrote:
> 
>>   - All architectures now define and use a kernel_sigaction struct meant
>>     for the syscall, even for the architectures where the user sigaction
>>     has the same layout of the kernel expected one (s390-64 and ia64).
>>     Although it requires more work for these architectures, it simplifies
>>     the generic implementation. Also, sigaction is hardly a hotspot where
>>     micro optimization would play an important role.
>>
>>   - The generic kernel_sigaction definition is now aligned with expected
>>     UAPI one for newer ports, where SA_RESTORER and sa_restorer is not
>>     expected to be defined.  This means adding kernel_sigaction for
>>     current architectures that does define it (m68k, nios2, powerpc, s390,
>>     sh, sparc, and tile) and which rely on previous generic definition.
> 
> There is no need to define kernel_sigaction in more than one file, since
> it is the same (except for the presense of sa_restorer) for all
> architectures.

Indeed currently we have some architectures with duplicated definition 
(alpha, s390, ia64, and hppa), however mips still requires its own
definition (__ARCH_HAS_IRIX_SIGACTION).

I am working on a fix for BZ#23960 along with a cleanup for
kernel_sigaction.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2018-12-11 17:43 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-17 20:35 [PATCH 1/2] linux: Consolidate sigaction implementation Adhemerval Zanella
2017-11-17 20:34 ` [PATCH 2/2] i386: Fix i386 sigaction sa_restorer initialization (BZ#21269) Adhemerval Zanella
2018-12-10 17:01 ` [PATCH 1/2] linux: Consolidate sigaction implementation Andreas Schwab
2018-12-11 17:49   ` Adhemerval Zanella

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).