diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux')
40 files changed, 776 insertions, 3 deletions
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 478f7e3d4d..8a17828d9d 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 e799b62285..336c13b57d 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 3448d62cee..bae2ebc087 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 d064f5445e..16c3c905cb 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 a5ce7964d0..27ccdabc0c 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 bee99c2384..9e532adb23 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 525840cea1..e86b933040 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 69ddf15361..d7e656b13b 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 a140edd4a3..8e10641162 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 178c0a45ec..81ec4d6761 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 01d10d907c..9655afe395 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 3ad08c20bf..2d9cd557ad 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 6bd7be1929..256117b3a0 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 9b1e890eda..42e4770341 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 3eb5b66f8b..a28a21f842 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 543a725114..b725205f4f 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 a9198a3936..373801d4f3 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 afacf1ff2d..7ff042045f 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/sysdeps/unix/sysv/linux/pkey_get.c b/sysdeps/unix/sysv/linux/pkey_get.c new file mode 100644 index 0000000000..fc3204c82f --- /dev/null +++ b/sysdeps/unix/sysv/linux/pkey_get.c @@ -0,0 +1,26 @@ +/* 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 + 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> + +int +pkey_get (int key) +{ + __set_errno (ENOSYS); + return -1; +} diff --git a/sysdeps/unix/sysv/linux/pkey_mprotect.c b/sysdeps/unix/sysv/linux/pkey_mprotect.c new file mode 100644 index 0000000000..a78fe293b2 --- /dev/null +++ b/sysdeps/unix/sysv/linux/pkey_mprotect.c @@ -0,0 +1,37 @@ +/* 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 + 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 <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/sysdeps/unix/sysv/linux/pkey_set.c b/sysdeps/unix/sysv/linux/pkey_set.c new file mode 100644 index 0000000000..f686c4373c --- /dev/null +++ b/sysdeps/unix/sysv/linux/pkey_set.c @@ -0,0 +1,26 @@ +/* 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 + 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> + +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 48af097b6a..a074a05005 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 e30535dac9..5271f6dab3 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 f522700890..96cc6cdb1d 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 d3092afd25..3665895b76 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 752176108e..1aa0994c0a 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 b6d4c73635..538f7cca8c 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 1ee21fe8e8..17d5c0c7eb 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 e652191c60..e635f380b7 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 37cf8713a5..8cea2c0a8d 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 40c4fbb9ea..e3dfd0c8db 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 57427eb3ee..d7b49335ab 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 321f65c600..e96a45818c 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 57427eb3ee..d7b49335ab 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 0000000000..e7205dba1f --- /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/sysdeps/unix/sysv/linux/x86/arch-pkey.h b/sysdeps/unix/sysv/linux/x86/arch-pkey.h new file mode 100644 index 0000000000..8e9bfdae96 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/arch-pkey.h @@ -0,0 +1,40 @@ +/* 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 + 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/>. */ + +#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/sysdeps/unix/sysv/linux/x86/pkey_get.c b/sysdeps/unix/sysv/linux/x86/pkey_get.c new file mode 100644 index 0000000000..3a9bfbe676 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/pkey_get.c @@ -0,0 +1,33 @@ +/* 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 + 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 <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/sysdeps/unix/sysv/linux/x86/pkey_set.c b/sysdeps/unix/sysv/linux/x86/pkey_set.c new file mode 100644 index 0000000000..91dffd22c3 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86/pkey_set.c @@ -0,0 +1,35 @@ +/* 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 + 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 <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 f26c8b99d5..7317d17e7b 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 2a6057154b..0a9334f822 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 |