This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch master updated. glibc-2.26.9000-921-g446d22e


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  446d22e91d3113be57a4b0d1151cf337458c3bec (commit)
      from  da616c1496e2bd3022dbe4afdd162a80731c08ad (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=446d22e91d3113be57a4b0d1151cf337458c3bec

commit 446d22e91d3113be57a4b0d1151cf337458c3bec
Author: Florian Weimer <fweimer@redhat.com>
Date:   Tue Dec 5 15:20:30 2017 +0100

    Linux: Implement interfaces for memory protection keys
    
    This adds system call wrappers for pkey_alloc, pkey_free, pkey_mprotect,
    and x86-64 implementations of pkey_get and pkey_set, which abstract over
    the PKRU CPU register and hide the actual number of memory protection
    keys supported by the CPU.  pkey_mprotect with a -1 key is implemented
    using mprotect, so it will work even if the kernel does not support the
    pkey_mprotect system call.
    
    The system call wrapers use unsigned int instead of unsigned long for
    parameters, so that no special treatment for x32 is needed.  The flags
    argument is currently unused, and the access rights bit mask is limited
    to two bits by the current PKRU register layout anyway.
    
    Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>

diff --git a/ChangeLog b/ChangeLog
index 50ae82b..333012b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,39 @@
 2017-12-05  Florian Weimer  <fweimer@redhat.com>
 
+	Linux: Implement interfaces for memory protection keys
+	* support/Makefile (libsupport-routines): Add xraise, xsigaction,
+	xsignal, xsysconf.
+	* support/xsignal.h (xraise, xsignal, xsigaction): Declare.
+	* support/xunistd.h (xsysconf): Declare.
+	* support/xraise.c: New file.
+	* support/xsigaction.c: Likewise.
+	* support/xsignal.c: Likewise.
+	* support/xsysconf.c: Likewise.
+	* sysdeps/unix/sysv/linux/Makefile [misc] (routines): Add
+	pkey_set, pkey_get, pkey_mprotect.
+	[misc] (tests): Add tst-pkey.
+	(tst-pkey): Link with -lpthread.
+	* sysdeps/unix/sysv/linux/Versions (GLIBC_2.27): Add pkey_alloc,
+	pkey_free, pkey_set, pkey_get, pkey_mprotect.
+	* sysdeps/unix/sysv/linux/bits/mman-linux.h (PKEY_DISABLE_ACCESS)
+	(PKEY_DISABLE_WRITE): Define.
+	(pkey_alloc, pkey_free, pkey_set, pkey_get, pkey_mprotect):
+	Declare.
+	* sysdeps/unix/sysv/linux/bits/siginfo-consts.h (SEGV_BNDERR)
+	(SEGV_PKUERR): Add.
+	* sysdeps/unix/sysv/linux/pkey_get.c: New file.
+	* sysdeps/unix/sysv/linux/pkey_set.c: Likewise.
+	* sysdeps/unix/sysv/linux/pkey_mprotect.c: Likewise.
+	* sysdeps/unix/sysv/linux/syscalls.list (pkey_alloc, pkey_free):
+	Add.
+	* sysdeps/unix/sysv/linux/tst-pkey.c: New file.
+	* sysdeps/unix/sysv/linux/x86/arch-pkey.h: Likewise.
+	* sysdeps/unix/sysv/linux/x86/pkey_get.c: Likewise.
+	* sysdeps/unix/sysv/linux/x86/pkey_set.c: Likewise.
+	* sysdeps/unix/sysv/linux/**.abilist: Update.
+
+2017-12-05  Florian Weimer  <fweimer@redhat.com>
+
 	* support/tst-test_compare.c (subprocess): Use long long instead
 	of long argument for consistent type width across 32-bit and
 	64-bit architectures.
diff --git a/NEWS b/NEWS
index 10f695a..6b1a2f9 100644
--- a/NEWS
+++ b/NEWS
@@ -43,6 +43,10 @@ Major new features:
 
 * glibc now implements the memfd_create and mlock2 functions on Linux.
 
+* Support for memory protection keys was added.  The <sys/mman.h> header now
+  declares the functions pkey_alloc, pkey_free, pkey_mprotect, pkey_set,
+  pkey_get.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * On GNU/Linux, the obsolete Linux constant PTRACE_SEIZE_DEVEL is no longer
diff --git a/manual/memory.texi b/manual/memory.texi
index 1b431bf..b95f6aa 100644
--- a/manual/memory.texi
+++ b/manual/memory.texi
@@ -3171,6 +3171,238 @@ process memory, no matter how it was allocated.  However, portable use
 of the function requires that it is only used with memory regions
 returned by @code{mmap} or @code{mmap64}.
 
+@subsection Memory Protection Keys
+
+@cindex memory protection key
+@cindex protection key
+@cindex MPK
+On some systems, further restrictions can be added to specific pages
+using @dfn{memory protection keys}.  These restrictions work as follows:
+
+@itemize @bullet
+@item
+All memory pages are associated with a protection key.  The default
+protection key does not cause any additional protections to be applied
+during memory accesses.  New keys can be allocated with the
+@code{pkey_alloc} function, and applied to pages using
+@code{pkey_mprotect}.
+
+@item
+Each thread has a set of separate access right restriction for each
+protection key.  These access rights can be manipulated using the
+@code{pkey_set} and @code{pkey_get} functions.
+
+@item
+During a memory access, the system obtains the protection key for the
+accessed page and uses that to determine the applicable access rights,
+as configured for the current thread.  If the access is restricted, a
+segmentation fault is the result ((@pxref{Program Error Signals}).
+These checks happen in addition to the @code{PROT_}* protection flags
+set by @code{mprotect} or @code{pkey_mprotect}.
+@end itemize
+
+New threads and subprocesses inherit the access rights of the current
+thread.  If a protection key is allocated subsequently, existing threads
+(except the current) will use an unspecified system default for the
+access rights associated with newly allocated keys.
+
+Upon entering a signal handler, the system resets the access rights of
+the current thread so that pages with the default key can be accessed,
+but the access rights for other protection keys are unspecified.
+
+Applications are expected to allocate a key once using
+@code{pkey_alloc}, and apply the key to memory regions which need
+special protection with @code{pkey_mprotect}:
+
+@smallexample
+  int key = pkey_alloc (0, PKEY_DISABLE_ACCESS);
+  if (key < 0)
+    /* Perform error checking, including fallback for lack of support.  */
+    ...;
+
+  /* Apply the key to a special memory region used to store critical
+     data.  */
+  if (pkey_mprotect (region, region_length,
+                     PROT_READ | PROT_WRITE, key) < 0)
+    ...; /* Perform error checking (generally fatal).  */
+@end smallexample
+
+If the key allocation fails due to lack of support for memory protection
+keys, the @code{pkey_mprotect} call can usually be skipped.  In this
+case, the region will not be protected by default.  It is also possible
+to call @code{pkey_mprotect} with a key value of @math{-1}, in which
+case it will behave in the same way as @code{mprotect}.
+
+After key allocation assignment to memory pages, @code{pkey_set} can be
+used to temporarily acquire access to the memory region and relinquish
+it again:
+
+@smallexample
+  if (key >= 0 && pkey_set (key, 0) < 0)
+    ...; /* Perform error checking (generally fatal).  */
+  /* At this point, the current thread has read-write access to the
+     memory region.  */
+  ...
+  /* Revoke access again.  */
+  if (key >= 0 && pkey_set (key, PKEY_DISABLE_ACCESS) < 0)
+    ...; /* Perform error checking (generally fatal).  */
+@end smallexample
+
+In this example, a negative key value indicates that no key had been
+allocated, which means that the system lacks support for memory
+protection keys and it is not necessary to change the the access rights
+of the current thread (because it always has access).
+
+Compared to using @code{mprotect} to change the page protection flags,
+this approach has two advantages: It is thread-safe in the sense that
+the access rights are only changed for the current thread, so another
+thread which changes its own access rights concurrently to gain access
+to the mapping will not suddenly see its access rights revoked.  And
+@code{pkey_set} typically does not involve a call into the kernel and a
+context switch, so it is more efficient.
+
+@deftypefun int pkey_alloc (unsigned int @var{flags}, unsigned int @var{restrictions})
+@standards{Linux, sys/mman.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}}
+Allocate a new protection key.  The @var{flags} argument is reserved and
+must be zero.  The @var{restrictions} argument specifies access rights
+which are applied to the current thread (as if with @code{pkey_set}
+below).  Access rights of other threads are not changed.
+
+The function returns the new protection key, a non-negative number, or
+@math{-1} on error.
+
+The following @code{errno} error conditions are defined for this
+function:
+
+@table @code
+@item ENOSYS
+The system does not implement memory protection keys.
+
+@item EINVAL
+The @var{flags} argument is not zero.
+
+The @var{restrictions} argument is invalid.
+
+The system does not implement memory protection keys or runs in a mode
+in which memory protection keys are disabled.
+
+@item ENOSPC
+All available protection keys already have been allocated.
+@end table
+@end deftypefun
+
+@deftypefun int pkey_free (int @var{key})
+@standards{Linux, sys/mman.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Deallocate the protection key, so that it can be reused by
+@code{pkey_alloc}.
+
+Calling this function does not change the access rights of the freed
+protection key.  The calling thread and other threads may retain access
+to it, even if it is subsequently allocated again.  For this reason, it
+is not recommended to call the @code{pkey_free} function.
+
+@table @code
+@item ENOSYS
+The system does not implement memory protection keys.
+
+@item EINVAL
+The @var{key} argument is not a valid protection key.
+@end table
+@end deftypefun
+
+@deftypefun int pkey_mprotect (void *@var{address}, size_t @var{length}, int @var{protection}, int @var{key})
+@standards{Linux, sys/mman.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Similar to @code{mprotect}, but also set the memory protection key for
+the memory region to @code{key}.
+
+Some systems use memory protection keys to emulate certain combinations
+of @var{protection} flags.  Under such circumstances, specifying an
+explicit protection key may behave as if additional flags have been
+specified in @var{protection}, even though this does not happen with the
+default protection key.  For example, some systems can support
+@code{PROT_EXEC}-only mappings only with a default protection key, and
+memory with a key which was allocated using @code{pkey_alloc} will still
+be readable if @code{PROT_EXEC} is specified without @code{PROT_READ}.
+
+If @var{key} is @math{-1}, the default protection key is applied to the
+mapping, just as if @code{mprotect} had been called.
+
+The @code{pkey_mprotect} function returns @math{0} on success and
+@math{-1} on failure.  The same @code{errno} error conditions as for
+@code{mprotect} are defined for this function, with the following
+addition:
+
+@table @code
+@item EINVAL
+The @var{key} argument is not @math{-1} or a valid memory protection
+key allocated using @code{pkey_alloc}.
+
+@item ENOSYS
+The system does not implement memory protection keys, and @var{key} is
+not @math{-1}.
+@end table
+@end deftypefun
+
+@deftypefun int pkey_set (int @var{key}, unsigned int @var{rights})
+@standards{Linux, sys/mman.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Change the access rights of the current thread for memory pages with the
+protection key @var{key} to @var{rights}.  If @var{rights} is zero, no
+additional access restrictions on top of the page protection flags are
+applied.  Otherwise, @var{rights} is a combination of the following
+flags:
+
+@vtable @code
+@item PKEY_DISABLE_WRITE
+@standards{Linux, sys/mman.h}
+Subsequent attempts to write to memory with the specified protection
+key will fault.
+
+@item PKEY_DISABLE_ACCESS
+@standards{Linux, sys/mman.h}
+Subsequent attempts to write to or read from memory with the specified
+protection key will fault.
+@end vtable
+
+Operations not specified as flags are not restricted.  In particular,
+this means that the memory region will remain executable if it was
+mapped with the @code{PROT_EXEC} protection flag and
+@code{PKEY_DISABLE_ACCESS} has been specified.
+
+Calling the @code{pkey_set} function with a protection key which was not
+allocated by @code{pkey_alloc} results in undefined behavior.  This
+means that calling this function on systems which do not support memory
+protection keys is undefined.
+
+The @code{pkey_set} function returns @math{0} on success and @math{-1}
+on failure.
+
+The following @code{errno} error conditions are defined for this
+function:
+
+@table @code
+@item EINVAL
+The system does not support the access rights restrictions expressed in
+the @var{rights} argument.
+@end table
+@end deftypefun
+
+@deftypefun int pkey_get (int @var{key})
+@standards{Linux, sys/mman.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Return the access rights of the current thread for memory pages with
+protection key @var{key}.  The return value is zero or a combination of
+the @code{PKEY_DISABLE_}* flags; see the @code{pkey_set} function.
+
+Calling the @code{pkey_get} function with a protection key which was not
+allocated by @code{pkey_alloc} results in undefined behavior.  This
+means that calling this function on systems which do not support memory
+protection keys is undefined.
+@end deftypefun
+
 @node Locking Pages
 @section Locking Pages
 @cindex locking pages
diff --git a/support/Makefile b/support/Makefile
index bb81825..bfde793 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -87,8 +87,8 @@ libsupport-routines = \
   xpthread_attr_destroy \
   xpthread_attr_init \
   xpthread_attr_setdetachstate \
-  xpthread_attr_setstacksize \
   xpthread_attr_setguardsize \
+  xpthread_attr_setstacksize \
   xpthread_barrier_destroy \
   xpthread_barrier_init \
   xpthread_barrier_wait \
@@ -119,14 +119,18 @@ libsupport-routines = \
   xpthread_sigmask \
   xpthread_spin_lock \
   xpthread_spin_unlock \
+  xraise \
   xreadlink \
   xrealloc \
   xrecvfrom \
   xsendto \
   xsetsockopt \
+  xsigaction \
+  xsignal \
   xsocket \
   xstrdup \
   xstrndup \
+  xsysconf \
   xunlink \
   xwaitpid \
   xwrite \
diff --git a/support/xsignal.h b/support/xraise.c
similarity index 62%
copy from support/xsignal.h
copy to support/xraise.c
index 3dc0d9d..9126c6c 100644
--- a/support/xsignal.h
+++ b/support/xraise.c
@@ -1,5 +1,5 @@
-/* Support functionality for using signals.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+/* Error-checking wrapper for raise.
+   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
@@ -16,19 +16,12 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef SUPPORT_SIGNAL_H
-#define SUPPORT_SIGNAL_H
+#include <support/check.h>
+#include <support/xsignal.h>
 
-#include <signal.h>
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* The following functions call the corresponding libpthread functions
-   and terminate the process on error.  */
-
-void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
-
-__END_DECLS
-
-#endif /* SUPPORT_SIGNAL_H */
+void
+xraise (int sig)
+{
+  if (raise (sig) != 0)
+    FAIL_EXIT1 ("raise (%d): %m" , sig);
+}
diff --git a/support/xsignal.h b/support/xsigaction.c
similarity index 62%
copy from support/xsignal.h
copy to support/xsigaction.c
index 3dc0d9d..b74c69a 100644
--- a/support/xsignal.h
+++ b/support/xsigaction.c
@@ -1,5 +1,5 @@
-/* Support functionality for using signals.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+/* Error-checking wrapper for sigaction.
+   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
@@ -16,19 +16,12 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef SUPPORT_SIGNAL_H
-#define SUPPORT_SIGNAL_H
+#include <support/check.h>
+#include <support/xsignal.h>
 
-#include <signal.h>
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* The following functions call the corresponding libpthread functions
-   and terminate the process on error.  */
-
-void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
-
-__END_DECLS
-
-#endif /* SUPPORT_SIGNAL_H */
+void
+xsigaction (int sig, const struct sigaction *newact, struct sigaction *oldact)
+{
+  if (sigaction (sig, newact, oldact))
+    FAIL_EXIT1 ("sigaction (%d): %m" , sig);
+}
diff --git a/support/xsignal.h b/support/xsignal.c
similarity index 62%
copy from support/xsignal.h
copy to support/xsignal.c
index 3dc0d9d..22a1dd7 100644
--- a/support/xsignal.h
+++ b/support/xsignal.c
@@ -1,5 +1,5 @@
-/* Support functionality for using signals.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+/* Error-checking wrapper for signal.
+   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
@@ -16,19 +16,14 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef SUPPORT_SIGNAL_H
-#define SUPPORT_SIGNAL_H
-
-#include <signal.h>
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* The following functions call the corresponding libpthread functions
-   and terminate the process on error.  */
-
-void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
-
-__END_DECLS
-
-#endif /* SUPPORT_SIGNAL_H */
+#include <support/check.h>
+#include <support/xsignal.h>
+
+sighandler_t
+xsignal (int sig, sighandler_t handler)
+{
+  sighandler_t result = signal (sig, handler);
+  if (result == SIG_ERR)
+    FAIL_EXIT1 ("signal (%d, %p): %m", sig, handler);
+  return result;
+}
diff --git a/support/xsignal.h b/support/xsignal.h
index 3dc0d9d..3087ed0 100644
--- a/support/xsignal.h
+++ b/support/xsignal.h
@@ -24,6 +24,14 @@
 
 __BEGIN_DECLS
 
+/* The following functions call the corresponding libc functions and
+   terminate the process on error.  */
+
+void xraise (int sig);
+sighandler_t xsignal (int sig, sighandler_t handler);
+void xsigaction (int sig, const struct sigaction *newact,
+                 struct sigaction *oldact);
+
 /* The following functions call the corresponding libpthread functions
    and terminate the process on error.  */
 
diff --git a/support/xsignal.h b/support/xsysconf.c
similarity index 58%
copy from support/xsignal.h
copy to support/xsysconf.c
index 3dc0d9d..15ab1e2 100644
--- a/support/xsignal.h
+++ b/support/xsysconf.c
@@ -1,5 +1,5 @@
-/* Support functionality for using signals.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+/* Error-checking wrapper for sysconf.
+   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
@@ -16,19 +16,21 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef SUPPORT_SIGNAL_H
-#define SUPPORT_SIGNAL_H
-
-#include <signal.h>
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* The following functions call the corresponding libpthread functions
-   and terminate the process on error.  */
-
-void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
-
-__END_DECLS
-
-#endif /* SUPPORT_SIGNAL_H */
+#include <errno.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+
+long
+xsysconf (int name)
+{
+  /* Detect errors by a changed errno value, in case -1 is a valid
+     value.  Make sure that the caller does not see the zero value for
+     errno.  */
+  int old_errno = errno;
+  errno = 0;
+  long result = sysconf (name);
+  if (errno != 0)
+    FAIL_EXIT1 ("sysconf (%d): %m", name);
+  errno = old_errno;
+  return result;
+}
diff --git a/support/xunistd.h b/support/xunistd.h
index 05c2626..00376f7 100644
--- a/support/xunistd.h
+++ b/support/xunistd.h
@@ -39,6 +39,7 @@ void xstat (const char *path, struct stat64 *);
 void xmkdir (const char *path, mode_t);
 void xchroot (const char *path);
 void xunlink (const char *path);
+long xsysconf (int name);
 
 /* Read the link at PATH.  The caller should free the returned string
    with free.  */
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 478f7e3..8a17828 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -18,7 +18,7 @@ sysdep_routines += clone umount umount2 readahead \
 		   setfsuid setfsgid epoll_pwait signalfd \
 		   eventfd eventfd_read eventfd_write prlimit \
 		   personality epoll_wait tee vmsplice splice \
-		   open_by_handle_at mlock2
+		   open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get
 
 CFLAGS-gethostid.c = -fexceptions
 CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables
@@ -44,7 +44,7 @@ sysdep_headers += sys/mount.h sys/acct.h sys/sysctl.h \
 
 tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \
 	 tst-quota tst-sync_file_range tst-sysconf-iov_max tst-ttyname \
-	 test-errno-linux tst-memfd_create tst-mlock2
+	 test-errno-linux tst-memfd_create tst-mlock2 tst-pkey
 
 # Generate the list of SYS_* macros for the system calls (__NR_*
 # macros).  The file syscall-names.list contains all possible system
@@ -92,6 +92,8 @@ $(objpfx)tst-syscall-list.out: \
 # Separate object file for access to the constant from the UAPI header.
 $(objpfx)tst-sysconf-iov_max: $(objpfx)tst-sysconf-iov_max-uapi.o
 
+$(objpfx)tst-pkey: $(shared-thread-library)
+
 endif # $(subdir) == misc
 
 ifeq ($(subdir),time)
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index e799b62..336c13b 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -169,6 +169,7 @@ libc {
   GLIBC_2.27 {
     memfd_create;
     mlock2;
+    pkey_alloc; pkey_free; pkey_set; pkey_get; pkey_mprotect;
   }
   GLIBC_PRIVATE {
     # functions used in other libraries
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 3448d62..bae2ebc 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2108,6 +2108,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf128 F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof128 F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index d064f54..16c3c90 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2019,6 +2019,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf128 F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof128 F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index a5ce796..27ccdab 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -109,6 +109,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/bits/mman-shared.h b/sysdeps/unix/sysv/linux/bits/mman-shared.h
index bee99c2..9e532ad 100644
--- a/sysdeps/unix/sysv/linux/bits/mman-shared.h
+++ b/sysdeps/unix/sysv/linux/bits/mman-shared.h
@@ -33,6 +33,12 @@
 #  define MLOCK_ONFAULT 1U
 # endif
 
+/* Access rights for pkey_alloc.  */
+# ifndef PKEY_DISABLE_ACCESS
+#  define PKEY_DISABLE_ACCESS 0x1
+#  define PKEY_DISABLE_WRITE 0x2
+# endif
+
 __BEGIN_DECLS
 
 /* Create a new memory file descriptor.  NAME is a name for debugging.
@@ -43,6 +49,28 @@ int memfd_create (const char *__name, unsigned int __flags) __THROW;
    memory.  FLAGS is a combination of the MLOCK_* flags above.  */
 int mlock2 (const void *__addr, size_t __length, unsigned int __flags) __THROW;
 
+/* Allocate a new protection key, with the PKEY_DISABLE_* bits
+   specified in ACCESS_RIGHTS.  The protection key mask for the
+   current thread is updated to match the access privilege for the new
+   key.  */
+int pkey_alloc (unsigned int __flags, unsigned int __access_rights) __THROW;
+
+/* Update the access rights for the current thread for KEY, which must
+   have been allocated using pkey_alloc.  */
+int pkey_set (int __key, unsigned int __access_rights) __THROW;
+
+/* Return the access rights for the current thread for KEY, which must
+   have been allocated using pkey_alloc.  */
+int pkey_get (int _key) __THROW;
+
+/* Free an allocated protection key, which must have been allocated
+   using pkey_alloc.  */
+int pkey_free (int __key) __THROW;
+
+/* Apply memory protection flags for KEY to the specified address
+   range.  */
+int pkey_mprotect (void *__addr, size_t __len, int __prot, int __pkey) __THROW;
+
 __END_DECLS
 
 #endif /* __USE_GNU */
diff --git a/sysdeps/unix/sysv/linux/bits/siginfo-consts.h b/sysdeps/unix/sysv/linux/bits/siginfo-consts.h
index 525840c..e86b933 100644
--- a/sysdeps/unix/sysv/linux/bits/siginfo-consts.h
+++ b/sysdeps/unix/sysv/linux/bits/siginfo-consts.h
@@ -111,8 +111,12 @@ enum
 {
   SEGV_MAPERR = 1,		/* Address not mapped to object.  */
 #  define SEGV_MAPERR	SEGV_MAPERR
-  SEGV_ACCERR			/* Invalid permissions for mapped object.  */
+  SEGV_ACCERR,			/* Invalid permissions for mapped object.  */
 #  define SEGV_ACCERR	SEGV_ACCERR
+  SEGV_BNDERR,			/* Bounds checking failure.  */
+#  define SEGV_BNDERR	SEGV_BNDERR
+  SEGV_PKUERR			/* Protection key checking failure.  */
+#  define SEGV_PKUERR	SEGV_PKUERR
 };
 
 /* `si_code' values for SIGBUS signal.  */
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 69ddf15..d7e656b 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1873,6 +1873,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index a140edd..8e10641 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2038,6 +2038,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof64x F
 GLIBC_2.27 strtof64x_l F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 178c0a4..81ec4d6 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1902,6 +1902,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof64x F
 GLIBC_2.27 strtof64x_l F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 01d10d9..9655afe 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -110,6 +110,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 3ad08c2..2d9cd55 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1987,6 +1987,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 6bd7be1..256117b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2108,3 +2108,8 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 9b1e890..42e4770 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1962,6 +1962,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 3eb5b66..a28a21f 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1960,6 +1960,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 543a725..b725205 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1958,6 +1958,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf128 F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof128 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index a9198a3..373801d 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1953,6 +1953,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf128 F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof128 F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index afacf1f..7ff0420 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2149,3 +2149,8 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
diff --git a/support/xsignal.h b/sysdeps/unix/sysv/linux/pkey_get.c
similarity index 62%
copy from support/xsignal.h
copy to sysdeps/unix/sysv/linux/pkey_get.c
index 3dc0d9d..fc3204c 100644
--- a/support/xsignal.h
+++ b/sysdeps/unix/sysv/linux/pkey_get.c
@@ -1,5 +1,5 @@
-/* Support functionality for using signals.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+/* Obtaining the thread memory protection key, generic stub.
+   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
@@ -16,19 +16,11 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef SUPPORT_SIGNAL_H
-#define SUPPORT_SIGNAL_H
+#include <errno.h>
 
-#include <signal.h>
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* The following functions call the corresponding libpthread functions
-   and terminate the process on error.  */
-
-void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
-
-__END_DECLS
-
-#endif /* SUPPORT_SIGNAL_H */
+int
+pkey_get (int key)
+{
+  __set_errno (ENOSYS);
+  return -1;
+}
diff --git a/support/xsignal.h b/sysdeps/unix/sysv/linux/pkey_mprotect.c
similarity index 57%
copy from support/xsignal.h
copy to sysdeps/unix/sysv/linux/pkey_mprotect.c
index 3dc0d9d..a78fe29 100644
--- a/support/xsignal.h
+++ b/sysdeps/unix/sysv/linux/pkey_mprotect.c
@@ -1,5 +1,5 @@
-/* Support functionality for using signals.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+/* mprotect with a memory protection key.
+   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
@@ -16,19 +16,22 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef SUPPORT_SIGNAL_H
-#define SUPPORT_SIGNAL_H
-
-#include <signal.h>
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* The following functions call the corresponding libpthread functions
-   and terminate the process on error.  */
-
-void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
-
-__END_DECLS
-
-#endif /* SUPPORT_SIGNAL_H */
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sysdep.h>
+
+int
+pkey_mprotect (void *addr, size_t len, int prot, int pkey)
+{
+  if (pkey == -1)
+    /* If the key is -1, the system call is precisely equivalent to
+       mprotect.  */
+    return __mprotect (addr, len, prot);
+#ifdef __NR_pkey_mprotect
+  return INLINE_SYSCALL_CALL (pkey_mprotect, addr, len, prot, pkey);
+#else
+  __set_errno (ENOSYS);
+  return -1;
+#endif
+}
diff --git a/support/xsignal.h b/sysdeps/unix/sysv/linux/pkey_set.c
similarity index 62%
copy from support/xsignal.h
copy to sysdeps/unix/sysv/linux/pkey_set.c
index 3dc0d9d..f686c43 100644
--- a/support/xsignal.h
+++ b/sysdeps/unix/sysv/linux/pkey_set.c
@@ -1,5 +1,5 @@
-/* Support functionality for using signals.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+/* Changing the thread memory protection key, generic stub.
+   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
@@ -16,19 +16,11 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef SUPPORT_SIGNAL_H
-#define SUPPORT_SIGNAL_H
+#include <errno.h>
 
-#include <signal.h>
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* The following functions call the corresponding libpthread functions
-   and terminate the process on error.  */
-
-void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
-
-__END_DECLS
-
-#endif /* SUPPORT_SIGNAL_H */
+int
+pkey_set (int key, unsigned int access_rights)
+{
+  __set_errno (ENOSYS);
+  return -1;
+}
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 48af097..a074a05 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1991,6 +1991,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index e30535d..5271f6d 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1996,6 +1996,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index f522700..96cc6cd 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2203,6 +2203,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof64x F
 GLIBC_2.27 strtof64x_l F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index d3092af..3665895 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -110,6 +110,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 _Exit F
 GLIBC_2.3 _IO_2_1_stderr_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 7521761..1aa0994 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1991,6 +1991,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf128 F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof128 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index b6d4c73..538f7cc 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1892,6 +1892,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf128 F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof128 F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 1ee21fe..17d5c0c 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1877,6 +1877,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index e652191..e635f38 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1984,6 +1984,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf128 F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof128 F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 37cf871..8cea2c0 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1921,6 +1921,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf128 F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof128 F
diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
index 40c4fbb..e3dfd0c 100644
--- a/sysdeps/unix/sysv/linux/syscalls.list
+++ b/sysdeps/unix/sysv/linux/syscalls.list
@@ -110,3 +110,5 @@ setns		EXTRA	setns		i:ii	setns
 process_vm_readv EXTRA	process_vm_readv i:ipipii process_vm_readv
 process_vm_writev EXTRA	process_vm_writev i:ipipii process_vm_writev
 memfd_create    EXTRA	memfd_create	i:si    memfd_create
+pkey_alloc	EXTRA	pkey_alloc	i:ii	pkey_alloc
+pkey_free	EXTRA	pkey_free	i:i	pkey_free
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index 57427eb..d7b4933 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2115,3 +2115,8 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index 321f65c..e96a458 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2115,3 +2115,8 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index 57427eb..d7b4933 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2115,3 +2115,8 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
diff --git a/sysdeps/unix/sysv/linux/tst-pkey.c b/sysdeps/unix/sysv/linux/tst-pkey.c
new file mode 100644
index 0000000..e7205db
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-pkey.c
@@ -0,0 +1,399 @@
+/* Tests for memory protection keys.
+   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/>.  */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <support/xsignal.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+#include <sys/mman.h>
+
+/* Used to force threads to wait until the main thread has set up the
+   keys as intended.  */
+static pthread_barrier_t barrier;
+
+/* The keys used for testing.  These have been allocated with access
+   rights set based on their array index.  */
+enum { key_count = 4 };
+static int keys[key_count];
+static volatile int *pages[key_count];
+
+/* Used to report results from the signal handler.  */
+static volatile void *sigsegv_addr;
+static volatile int sigsegv_code;
+static volatile int sigsegv_pkey;
+static sigjmp_buf sigsegv_jmp;
+
+/* Used to handle expected read or write faults.  */
+static void
+sigsegv_handler (int signum, siginfo_t *info, void *context)
+{
+  sigsegv_addr = info->si_addr;
+  sigsegv_code = info->si_code;
+  sigsegv_pkey = info->si_pkey;
+  siglongjmp (sigsegv_jmp, 2);
+}
+
+static const struct sigaction sigsegv_sigaction =
+  {
+    .sa_flags = SA_RESETHAND | SA_SIGINFO,
+    .sa_sigaction = &sigsegv_handler,
+  };
+
+/* Check if PAGE is readable (if !WRITE) or writable (if WRITE).  */
+static bool
+check_page_access (int page, bool write)
+{
+  /* This is needed to work around bug 22396: On x86-64, siglongjmp
+     does not restore the protection key access rights for the current
+     thread.  We restore only the access rights for the keys under
+     test.  (This is not a general solution to this problem, but it
+     allows testing to proceed after a fault.)  */
+  unsigned saved_rights[key_count];
+  for (int i = 0; i < key_count; ++i)
+    saved_rights[i] = pkey_get (keys[i]);
+
+  volatile int *addr = pages[page];
+  if (test_verbose > 0)
+    {
+      printf ("info: checking access at %p (page %d) for %s\n",
+              addr, page, write ? "writing" : "reading");
+    }
+  int result = sigsetjmp (sigsegv_jmp, 1);
+  if (result == 0)
+    {
+      xsigaction (SIGSEGV, &sigsegv_sigaction, NULL);
+      if (write)
+        *addr = 3;
+      else
+        (void) *addr;
+      xsignal (SIGSEGV, SIG_DFL);
+      if (test_verbose > 0)
+        puts ("  --> access allowed");
+      return true;
+    }
+  else
+    {
+      xsignal (SIGSEGV, SIG_DFL);
+      if (test_verbose > 0)
+        puts ("  --> access denied");
+      TEST_COMPARE (result, 2);
+      TEST_COMPARE ((uintptr_t) sigsegv_addr, (uintptr_t) addr);
+      TEST_COMPARE (sigsegv_code, SEGV_PKUERR);
+      TEST_COMPARE (sigsegv_pkey, keys[page]);
+      for (int i = 0; i < key_count; ++i)
+        TEST_COMPARE (pkey_set (keys[i], saved_rights[i]), 0);
+      return false;
+    }
+}
+
+static volatile sig_atomic_t sigusr1_handler_ran;
+
+/* Used to check that access is revoked in signal handlers.  */
+static void
+sigusr1_handler (int signum)
+{
+  TEST_COMPARE (signum, SIGUSR1);
+  for (int i = 0; i < key_count; ++i)
+    TEST_COMPARE (pkey_get (keys[i]), PKEY_DISABLE_ACCESS);
+  sigusr1_handler_ran = 1;
+}
+
+/* Used to report results from other threads.  */
+struct thread_result
+{
+  int access_rights[key_count];
+  pthread_t next_thread;
+};
+
+/* Return the thread's access rights for the keys under test.  */
+static void *
+get_thread_func (void *closure)
+{
+  struct thread_result *result = xmalloc (sizeof (*result));
+  for (int i = 0; i < key_count; ++i)
+    result->access_rights[i] = pkey_get (keys[i]);
+  memset (&result->next_thread, 0, sizeof (result->next_thread));
+  return result;
+}
+
+/* Wait for initialization and then check that the current thread does
+   not have access through the keys under test.  */
+static void *
+delayed_thread_func (void *closure)
+{
+  bool check_access = *(bool *) closure;
+  pthread_barrier_wait (&barrier);
+  struct thread_result *result = get_thread_func (NULL);
+
+  if (check_access)
+    {
+      /* Also check directly.  This code should not run with other
+         threads in parallel because of the SIGSEGV handler which is
+         installed by check_page_access.  */
+      for (int i = 0; i < key_count; ++i)
+        {
+          TEST_VERIFY (!check_page_access (i, false));
+          TEST_VERIFY (!check_page_access (i, true));
+        }
+    }
+
+  result->next_thread = xpthread_create (NULL, get_thread_func, NULL);
+  return result;
+}
+
+static int
+do_test (void)
+{
+  long pagesize = xsysconf (_SC_PAGESIZE);
+
+  /* pkey_mprotect with key -1 should work even when there is no
+     protection key support.  */
+  {
+    int *page = xmmap (NULL, pagesize, PROT_NONE,
+                       MAP_ANONYMOUS | MAP_PRIVATE, -1);
+    TEST_COMPARE (pkey_mprotect (page, pagesize, PROT_READ | PROT_WRITE, -1),
+                  0);
+    volatile int *vpage = page;
+    *vpage = 5;
+    TEST_COMPARE (*vpage, 5);
+    xmunmap (page, pagesize);
+  }
+
+  xpthread_barrier_init (&barrier, NULL, 2);
+  bool delayed_thread_check_access = true;
+  pthread_t delayed_thread = xpthread_create
+    (NULL, &delayed_thread_func, &delayed_thread_check_access);
+
+  keys[0] = pkey_alloc (0, 0);
+  if (keys[0] < 0)
+    {
+      if (errno == ENOSYS)
+        FAIL_UNSUPPORTED
+          ("kernel does not support memory protection keys");
+      if (errno == EINVAL)
+        FAIL_UNSUPPORTED
+          ("CPU does not support memory protection keys: %m");
+      FAIL_EXIT1 ("pkey_alloc: %m");
+    }
+  TEST_COMPARE (pkey_get (keys[0]), 0);
+  for (int i = 1; i < key_count; ++i)
+    {
+      keys[i] = pkey_alloc (0, i);
+      if (keys[i] < 0)
+        FAIL_EXIT1 ("pkey_alloc (0, %d): %m", i);
+      /* pkey_alloc is supposed to change the current thread's access
+         rights for the new key.  */
+      TEST_COMPARE (pkey_get (keys[i]), i);
+    }
+  /* Check that all the keys have the expected access rights for the
+     current thread.  */
+  for (int i = 0; i < key_count; ++i)
+    TEST_COMPARE (pkey_get (keys[i]), i);
+
+  /* Allocate a test page for each key.  */
+  for (int i = 0; i < key_count; ++i)
+    {
+      pages[i] = xmmap (NULL, pagesize, PROT_READ | PROT_WRITE,
+                        MAP_ANONYMOUS | MAP_PRIVATE, -1);
+      TEST_COMPARE (pkey_mprotect ((void *) pages[i], pagesize,
+                                   PROT_READ | PROT_WRITE, keys[i]), 0);
+    }
+
+  /* Check that the initial thread does not have access to the new
+     keys.  */
+  {
+    pthread_barrier_wait (&barrier);
+    struct thread_result *result = xpthread_join (delayed_thread);
+    for (int i = 0; i < key_count; ++i)
+      TEST_COMPARE (result->access_rights[i],
+                    PKEY_DISABLE_ACCESS);
+    struct thread_result *result2 = xpthread_join (result->next_thread);
+    for (int i = 0; i < key_count; ++i)
+      TEST_COMPARE (result->access_rights[i],
+                    PKEY_DISABLE_ACCESS);
+    free (result);
+    free (result2);
+  }
+
+  /* Check that the current thread access rights are inherited by new
+     threads.  */
+  {
+    pthread_t get_thread = xpthread_create (NULL, get_thread_func, NULL);
+    struct thread_result *result = xpthread_join (get_thread);
+    for (int i = 0; i < key_count; ++i)
+      TEST_COMPARE (result->access_rights[i], i);
+    free (result);
+  }
+
+  for (int i = 0; i < key_count; ++i)
+    TEST_COMPARE (pkey_get (keys[i]), i);
+
+  /* Check that in a signal handler, there is no access.  */
+  xsignal (SIGUSR1, &sigusr1_handler);
+  xraise (SIGUSR1);
+  xsignal (SIGUSR1, SIG_DFL);
+  TEST_COMPARE (sigusr1_handler_ran, 1);
+
+  /* The first key results in a writable page.  */
+  TEST_VERIFY (check_page_access (0, false));
+  TEST_VERIFY (check_page_access (0, true));
+
+  /* The other keys do not.   */
+  for (int i = 1; i < key_count; ++i)
+    {
+      if (test_verbose)
+        printf ("info: checking access for key %d, bits 0x%x\n",
+                i, pkey_get (keys[i]));
+      for (int j = 0; j < key_count; ++j)
+        TEST_COMPARE (pkey_get (keys[j]), j);
+      if (i & PKEY_DISABLE_ACCESS)
+        {
+          TEST_VERIFY (!check_page_access (i, false));
+          TEST_VERIFY (!check_page_access (i, true));
+        }
+      else
+        {
+          TEST_VERIFY (i & PKEY_DISABLE_WRITE);
+          TEST_VERIFY (check_page_access (i, false));
+          TEST_VERIFY (!check_page_access (i, true));
+        }
+    }
+
+  /* But if we set the current thread's access rights, we gain
+     access.  */
+  for (int do_write = 0; do_write < 2; ++do_write)
+    for (int allowed_key = 0; allowed_key < key_count; ++allowed_key)
+      {
+        for (int i = 0; i < key_count; ++i)
+          if (i == allowed_key)
+            {
+              if (do_write)
+                TEST_COMPARE (pkey_set (keys[i], 0), 0);
+              else
+                TEST_COMPARE (pkey_set (keys[i], PKEY_DISABLE_WRITE), 0);
+            }
+          else
+            TEST_COMPARE (pkey_set (keys[i], PKEY_DISABLE_ACCESS), 0);
+
+        if (test_verbose)
+          printf ("info: key %d is allowed access for %s\n",
+                  allowed_key, do_write ? "writing" : "reading");
+        for (int i = 0; i < key_count; ++i)
+          if (i == allowed_key)
+            {
+              TEST_VERIFY (check_page_access (i, false));
+              TEST_VERIFY (check_page_access (i, true) == do_write);
+            }
+          else
+            {
+              TEST_VERIFY (!check_page_access (i, false));
+              TEST_VERIFY (!check_page_access (i, true));
+            }
+      }
+
+  /* Restore access to all keys, and launch a thread which should
+     inherit that access.  */
+  for (int i = 0; i < key_count; ++i)
+    {
+      TEST_COMPARE (pkey_set (keys[i], 0), 0);
+      TEST_VERIFY (check_page_access (i, false));
+      TEST_VERIFY (check_page_access (i, true));
+    }
+  delayed_thread_check_access = false;
+  delayed_thread = xpthread_create
+    (NULL, delayed_thread_func, &delayed_thread_check_access);
+
+  TEST_COMPARE (pkey_free (keys[0]), 0);
+  /* Second pkey_free will fail because the key has already been
+     freed.  */
+  TEST_COMPARE (pkey_free (keys[0]),-1);
+  TEST_COMPARE (errno, EINVAL);
+  for (int i = 1; i < key_count; ++i)
+    TEST_COMPARE (pkey_free (keys[i]), 0);
+
+  /* Check what happens to running threads which have access to
+     previously allocated protection keys.  The implemented behavior
+     is somewhat dubious: Ideally, pkey_free should revoke access to
+     that key and pkey_alloc of the same (numeric) key should not
+     implicitly confer access to already-running threads, but this is
+     not what happens in practice.  */
+  {
+    /* The limit is in place to avoid running indefinitely in case
+       there many keys available.  */
+    int *keys_array = xcalloc (100000, sizeof (*keys_array));
+    int keys_allocated = 0;
+    while (keys_allocated < 100000)
+      {
+        int new_key = pkey_alloc (0, PKEY_DISABLE_WRITE);
+        if (new_key < 0)
+          {
+            /* No key reuse observed before running out of keys.  */
+            TEST_COMPARE (errno, ENOSPC);
+            break;
+          }
+        for (int i = 0; i < key_count; ++i)
+          if (new_key == keys[i])
+            {
+              /* We allocated the key with disabled write access.
+                 This should affect the protection state of the
+                 existing page.  */
+              TEST_VERIFY (check_page_access (i, false));
+              TEST_VERIFY (!check_page_access (i, true));
+
+              xpthread_barrier_wait (&barrier);
+              struct thread_result *result = xpthread_join (delayed_thread);
+              /* The thread which was launched before should still have
+                 access to the key.  */
+              TEST_COMPARE (result->access_rights[i], 0);
+              struct thread_result *result2
+                = xpthread_join (result->next_thread);
+              /* Same for a thread which is launched afterwards from
+                 the old thread.  */
+              TEST_COMPARE (result2->access_rights[i], 0);
+              free (result);
+              free (result2);
+              keys_array[keys_allocated++] = new_key;
+              goto after_key_search;
+            }
+        /* Save key for later deallocation.  */
+        keys_array[keys_allocated++] = new_key;
+      }
+  after_key_search:
+    /* Deallocate the keys allocated for testing purposes.  */
+    for (int j = 0; j < keys_allocated; ++j)
+      TEST_COMPARE (pkey_free (keys_array[j]), 0);
+    free (keys_array);
+  }
+
+  for (int i = 0; i < key_count; ++i)
+    xmunmap ((void *) pages[i], pagesize);
+
+  xpthread_barrier_destroy (&barrier);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/support/xsignal.h b/sysdeps/unix/sysv/linux/x86/arch-pkey.h
similarity index 54%
copy from support/xsignal.h
copy to sysdeps/unix/sysv/linux/x86/arch-pkey.h
index 3dc0d9d..8e9bfda 100644
--- a/support/xsignal.h
+++ b/sysdeps/unix/sysv/linux/x86/arch-pkey.h
@@ -1,5 +1,5 @@
-/* Support functionality for using signals.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+/* Helper functions for manipulating memory protection keys.
+   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
@@ -16,19 +16,25 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef SUPPORT_SIGNAL_H
-#define SUPPORT_SIGNAL_H
-
-#include <signal.h>
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* The following functions call the corresponding libpthread functions
-   and terminate the process on error.  */
-
-void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
-
-__END_DECLS
-
-#endif /* SUPPORT_SIGNAL_H */
+#ifndef _ARCH_PKEY_H
+#define _ARCH_PKEY_H
+
+/* Return the value of the PKRU register.  */
+static inline unsigned int
+pkey_read (void)
+{
+  unsigned int result;
+  __asm__ volatile (".byte 0x0f, 0x01, 0xee"
+                    : "=a" (result) : "c" (0) : "rdx");
+  return result;
+}
+
+/* Overwrite the PKRU register with VALUE.  */
+static inline void
+pkey_write (unsigned int value)
+{
+  __asm__ volatile (".byte 0x0f, 0x01, 0xef"
+                    : : "a" (value), "c" (0), "d" (0));
+}
+
+#endif /* _ARCH_PKEY_H */
diff --git a/support/xsignal.h b/sysdeps/unix/sysv/linux/x86/pkey_get.c
similarity index 62%
copy from support/xsignal.h
copy to sysdeps/unix/sysv/linux/x86/pkey_get.c
index 3dc0d9d..3a9bfbe 100644
--- a/support/xsignal.h
+++ b/sysdeps/unix/sysv/linux/x86/pkey_get.c
@@ -1,5 +1,5 @@
-/* Support functionality for using signals.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+/* Reading the per-thread memory protection key, x86_64 version.
+   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
@@ -16,19 +16,18 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef SUPPORT_SIGNAL_H
-#define SUPPORT_SIGNAL_H
-
-#include <signal.h>
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* The following functions call the corresponding libpthread functions
-   and terminate the process on error.  */
-
-void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
-
-__END_DECLS
-
-#endif /* SUPPORT_SIGNAL_H */
+#include <arch-pkey.h>
+#include <errno.h>
+
+int
+pkey_get (int key)
+{
+  if (key < 0 || key > 15)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+  unsigned int pkru = pkey_read ();
+  return (pkru >> (2 * key)) & 3;
+  return 0;
+}
diff --git a/support/xsignal.h b/sysdeps/unix/sysv/linux/x86/pkey_set.c
similarity index 61%
copy from support/xsignal.h
copy to sysdeps/unix/sysv/linux/x86/pkey_set.c
index 3dc0d9d..91dffd2 100644
--- a/support/xsignal.h
+++ b/sysdeps/unix/sysv/linux/x86/pkey_set.c
@@ -1,5 +1,5 @@
-/* Support functionality for using signals.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+/* Changing the per-thread memory protection key, x86_64 version.
+   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
@@ -16,19 +16,20 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef SUPPORT_SIGNAL_H
-#define SUPPORT_SIGNAL_H
-
-#include <signal.h>
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-/* The following functions call the corresponding libpthread functions
-   and terminate the process on error.  */
-
-void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset);
-
-__END_DECLS
-
-#endif /* SUPPORT_SIGNAL_H */
+#include <arch-pkey.h>
+#include <errno.h>
+
+int
+pkey_set (int key, unsigned int rights)
+{
+  if (key < 0 || key > 15 || rights > 3)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+  unsigned int mask = 3 << (2 * key);
+  unsigned int pkru = pkey_read ();
+  pkru = (pkru & ~mask) | (rights << (2 * key));
+  pkey_write (pkru);
+  return 0;
+}
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index f26c8b9..7317d17 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1879,6 +1879,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof64x F
 GLIBC_2.27 strtof64x_l F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 2a60571..0a9334f 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2122,6 +2122,11 @@ GLIBC_2.27 glob F
 GLIBC_2.27 glob64 F
 GLIBC_2.27 memfd_create F
 GLIBC_2.27 mlock2 F
+GLIBC_2.27 pkey_alloc F
+GLIBC_2.27 pkey_free F
+GLIBC_2.27 pkey_get F
+GLIBC_2.27 pkey_mprotect F
+GLIBC_2.27 pkey_set F
 GLIBC_2.27 strfromf64x F
 GLIBC_2.27 strtof64x F
 GLIBC_2.27 strtof64x_l F

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                          |   34 ++
 NEWS                                               |    4 +
 manual/memory.texi                                 |  232 ++++++++++++
 support/Makefile                                   |    6 +-
 support/xraise.c                                   |   27 ++
 support/xsigaction.c                               |   27 ++
 support/xsignal.c                                  |   29 ++
 support/xsignal.h                                  |    8 +
 support/xsysconf.c                                 |   36 ++
 support/xunistd.h                                  |    1 +
 sysdeps/unix/sysv/linux/Makefile                   |    6 +-
 sysdeps/unix/sysv/linux/Versions                   |    1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |    5 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |    5 +
 sysdeps/unix/sysv/linux/arm/libc.abilist           |    5 +
 sysdeps/unix/sysv/linux/bits/mman-shared.h         |   28 ++
 sysdeps/unix/sysv/linux/bits/siginfo-consts.h      |    6 +-
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |    5 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |    5 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |    5 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |    5 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |    5 +
 sysdeps/unix/sysv/linux/microblaze/libc.abilist    |    5 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |    5 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |    5 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |    5 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |    5 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |    5 +
 sysdeps/unix/sysv/linux/pkey_get.c                 |   26 ++
 sysdeps/unix/sysv/linux/pkey_mprotect.c            |   37 ++
 sysdeps/unix/sysv/linux/pkey_set.c                 |   26 ++
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |    5 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |    5 +
 .../sysv/linux/powerpc/powerpc64/libc-le.abilist   |    5 +
 .../unix/sysv/linux/powerpc/powerpc64/libc.abilist |    5 +
 sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist  |    5 +
 sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist  |    5 +
 sysdeps/unix/sysv/linux/sh/libc.abilist            |    5 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |    5 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |    5 +
 sysdeps/unix/sysv/linux/syscalls.list              |    2 +
 .../sysv/linux/tile/tilegx/tilegx32/libc.abilist   |    5 +
 .../sysv/linux/tile/tilegx/tilegx64/libc.abilist   |    5 +
 sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist  |    5 +
 sysdeps/unix/sysv/linux/tst-pkey.c                 |  399 ++++++++++++++++++++
 sysdeps/unix/sysv/linux/x86/arch-pkey.h            |   40 ++
 sysdeps/unix/sysv/linux/x86/pkey_get.c             |   33 ++
 sysdeps/unix/sysv/linux/x86/pkey_set.c             |   35 ++
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |    5 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |    5 +
 50 files changed, 1179 insertions(+), 4 deletions(-)
 create mode 100644 support/xraise.c
 create mode 100644 support/xsigaction.c
 create mode 100644 support/xsignal.c
 create mode 100644 support/xsysconf.c
 create mode 100644 sysdeps/unix/sysv/linux/pkey_get.c
 create mode 100644 sysdeps/unix/sysv/linux/pkey_mprotect.c
 create mode 100644 sysdeps/unix/sysv/linux/pkey_set.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-pkey.c
 create mode 100644 sysdeps/unix/sysv/linux/x86/arch-pkey.h
 create mode 100644 sysdeps/unix/sysv/linux/x86/pkey_get.c
 create mode 100644 sysdeps/unix/sysv/linux/x86/pkey_set.c


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]