aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry V. Levin <ldv@altlinux.org>2015-12-27 16:30:02 +0000
committerDmitry V. Levin <ldv@altlinux.org>2015-12-31 00:17:48 +0000
commite0043e17dfc52fe1702746543127cb4a87232bcd (patch)
tree73e7287e78b9775e8a4c603136fbf6c6fa1a5451
parentCleanup ARM ioperm implementation (step 2) (diff)
downloadglibc-e0043e17dfc52fe1702746543127cb4a87232bcd.tar.gz
glibc-e0043e17dfc52fe1702746543127cb4a87232bcd.tar.bz2
glibc-e0043e17dfc52fe1702746543127cb4a87232bcd.zip
Fix linux personality syscall wrapper
The personality system call, starting with linux kernel commit v2.6.29-6609-g11d06b2a1e5658f448a308aa3beb97bacd64a940, always successfully changes the personality if requested. The syscall wrapper, however, still can return an error in the following cases: - the value returned by the system call looks like an error due to architecture limitations of 32-bit kernels; - a personality greater than 0xffffffff is passed to the system call, and the 64-bit kernel does not have commit v2.6.35-rc1-372-g485d527686850d68a0e9006dd9904f19f122485e that would truncate this value to unsigned int; - on sparc64, the value returned by the system call looks like an error due to sparc64 kernel sign extension bug. The solution is three-fold: - move generic syscalls.list personality entry to generic 64-bit syscalls.list file; - for each 32-bit architecture that use negated errno semantics, add a NOERRNO personality entry to their syscalls.list file; - for sparc64 and 32-bit architectures that use dedicated registers to flag syscall errors, add a wrapper around personality syscall; if the system call return value is flagged as an error, this wrapper returns the negated "would be errno" value, otherwise it returns the system call return value; on sparc64, it also truncates the personality argument to unsigned int before passing it to the kernel. [BZ #19408] * sysdeps/unix/sysv/linux/personality.c: New file. * sysdeps/unix/sysv/linux/sparc/sparc64/personality.c: Likewise. * sysdeps/unix/sysv/linux/tst-personality.c: Likewise. * sysdeps/unix/sysv/linux/Makefile [$(subdir) == misc] (sysdep_routines): Add personality. (tests): Add tst-personality. * sysdeps/unix/sysv/linux/syscalls.list (personality): Move ... * sysdeps/unix/sysv/linux/wordsize-64/syscalls.list: ... here. * sysdeps/unix/sysv/linux/arm/syscalls.list (personality): New entry. * sysdeps/unix/sysv/linux/hppa/syscalls.list (personality): Likewise. * sysdeps/unix/sysv/linux/i386/syscalls.list (personality): Likewise. * sysdeps/unix/sysv/linux/m68k/syscalls.list (personality): Likewise. * sysdeps/unix/sysv/linux/microblaze/syscalls.list (personality): Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list (personality): Likewise. * sysdeps/unix/sysv/linux/s390/s390-32/syscalls.list (personality): Likewise. * sysdeps/unix/sysv/linux/sh/syscalls.list (personality): Likewise. * sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list (personality): Likewise.
-rw-r--r--ChangeLog25
-rw-r--r--sysdeps/unix/sysv/linux/Makefile5
-rw-r--r--sysdeps/unix/sysv/linux/arm/syscalls.list2
-rw-r--r--sysdeps/unix/sysv/linux/hppa/syscalls.list1
-rw-r--r--sysdeps/unix/sysv/linux/i386/syscalls.list2
-rw-r--r--sysdeps/unix/sysv/linux/m68k/syscalls.list1
-rw-r--r--sysdeps/unix/sysv/linux/microblaze/syscalls.list1
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list2
-rw-r--r--sysdeps/unix/sysv/linux/personality.c49
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-32/syscalls.list1
-rw-r--r--sysdeps/unix/sysv/linux/sh/syscalls.list2
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc64/personality.c3
-rw-r--r--sysdeps/unix/sysv/linux/syscalls.list1
-rw-r--r--sysdeps/unix/sysv/linux/tst-personality.c45
-rw-r--r--sysdeps/unix/sysv/linux/wordsize-64/syscalls.list1
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list1
16 files changed, 139 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 85d39d6107..51a055c825 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2015-12-30 Dmitry V. Levin <ldv@altlinux.org>
+
+ [BZ #19408]
+ * sysdeps/unix/sysv/linux/personality.c: New file.
+ * sysdeps/unix/sysv/linux/sparc/sparc64/personality.c: Likewise.
+ * sysdeps/unix/sysv/linux/tst-personality.c: Likewise.
+ * sysdeps/unix/sysv/linux/Makefile [$(subdir) == misc]
+ (sysdep_routines): Add personality.
+ (tests): Add tst-personality.
+ * sysdeps/unix/sysv/linux/syscalls.list (personality): Move ...
+ * sysdeps/unix/sysv/linux/wordsize-64/syscalls.list: ... here.
+ * sysdeps/unix/sysv/linux/arm/syscalls.list (personality): New entry.
+ * sysdeps/unix/sysv/linux/hppa/syscalls.list (personality): Likewise.
+ * sysdeps/unix/sysv/linux/i386/syscalls.list (personality): Likewise.
+ * sysdeps/unix/sysv/linux/m68k/syscalls.list (personality): Likewise.
+ * sysdeps/unix/sysv/linux/microblaze/syscalls.list (personality):
+ Likewise.
+ * sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list (personality):
+ Likewise.
+ * sysdeps/unix/sysv/linux/s390/s390-32/syscalls.list (personality):
+ Likewise.
+ * sysdeps/unix/sysv/linux/sh/syscalls.list (personality): Likewise.
+ * sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list (personality):
+ Likewise.
+
2015-12-30 Aurelien Jarno <aurelien@aurel32.net>
* sysdeps/unix/sysv/linux/arm/ioperm.c: Do not include <string.h>.
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index f6269ea3d8..9999600633 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -16,7 +16,8 @@ include $(firstword $(wildcard $(sysdirs:=/sysctl.mk)))
sysdep_routines += clone llseek umount umount2 readahead \
setfsuid setfsgid makedev epoll_pwait signalfd \
- eventfd eventfd_read eventfd_write prlimit
+ eventfd eventfd_read eventfd_write prlimit \
+ personality
CFLAGS-gethostid.c = -fexceptions
CFLAGS-tst-writev.c += "-DARTIFICIAL_LIMIT=0x80000000-__getpagesize()"
@@ -41,7 +42,7 @@ sysdep_headers += sys/mount.h sys/acct.h sys/sysctl.h \
bits/socket_type.h bits/syscall.h bits/sysctl.h \
bits/mman-linux.h
-tests += tst-clone tst-fanotify
+tests += tst-clone tst-fanotify tst-personality
# Generate the list of SYS_* macros for the system calls (__NR_* macros).
diff --git a/sysdeps/unix/sysv/linux/arm/syscalls.list b/sysdeps/unix/sysv/linux/arm/syscalls.list
index 911ed7d2fa..c06954f824 100644
--- a/sysdeps/unix/sysv/linux/arm/syscalls.list
+++ b/sysdeps/unix/sysv/linux/arm/syscalls.list
@@ -19,6 +19,8 @@ prlimit64 EXTRA prlimit64 i:iipp prlimit64
fanotify_mark EXTRA fanotify_mark i:iiiiis fanotify_mark
+personality EXTRA personality Ei:i __personality personality
+
# Semaphore and shm system calls. msgctl, shmctl, and semctl have C
# wrappers (to set __IPC_64).
msgget - msgget i:ii __msgget msgget
diff --git a/sysdeps/unix/sysv/linux/hppa/syscalls.list b/sysdeps/unix/sysv/linux/hppa/syscalls.list
index 2cb8d027c3..d29c35866d 100644
--- a/sysdeps/unix/sysv/linux/hppa/syscalls.list
+++ b/sysdeps/unix/sysv/linux/hppa/syscalls.list
@@ -37,3 +37,4 @@ setrlimit - setrlimit i:ip __setrlimit setrlimit
getrlimit - getrlimit i:ip __getrlimit getrlimit
prlimit64 EXTRA prlimit64 i:iipp __prlimit64 prlimit64@@GLIBC_2.17
fanotify_mark EXTRA fanotify_mark i:iiiiis __fanotify_mark fanotify_mark@@GLIBC_2.19
+personality EXTRA personality Ei:i __personality personality
diff --git a/sysdeps/unix/sysv/linux/i386/syscalls.list b/sysdeps/unix/sysv/linux/i386/syscalls.list
index 1cebd6a50f..6282ff8e2f 100644
--- a/sysdeps/unix/sysv/linux/i386/syscalls.list
+++ b/sysdeps/unix/sysv/linux/i386/syscalls.list
@@ -25,3 +25,5 @@ waitpid - waitpid Ci:ipi __waitpid waitpid
prlimit64 EXTRA prlimit64 i:iipp prlimit64
fanotify_mark EXTRA fanotify_mark i:iiiiis fanotify_mark
+
+personality EXTRA personality Ei:i __personality personality
diff --git a/sysdeps/unix/sysv/linux/m68k/syscalls.list b/sysdeps/unix/sysv/linux/m68k/syscalls.list
index ad4ca46b50..4260f3e55f 100644
--- a/sysdeps/unix/sysv/linux/m68k/syscalls.list
+++ b/sysdeps/unix/sysv/linux/m68k/syscalls.list
@@ -19,3 +19,4 @@ setfsuid - setfsuid32 Ei:i setfsuid
cacheflush EXTRA cacheflush i:iiii __cacheflush cacheflush
prlimit64 EXTRA prlimit64 i:iipp prlimit64
fanotify_mark EXTRA fanotify_mark i:iiiiis fanotify_mark
+personality EXTRA personality Ei:i __personality personality
diff --git a/sysdeps/unix/sysv/linux/microblaze/syscalls.list b/sysdeps/unix/sysv/linux/microblaze/syscalls.list
index 86fd40bd15..da0fd4ec98 100644
--- a/sysdeps/unix/sysv/linux/microblaze/syscalls.list
+++ b/sysdeps/unix/sysv/linux/microblaze/syscalls.list
@@ -4,6 +4,7 @@ cacheflush EXTRA cacheflush i:iiii __cacheflush cacheflush
prlimit64 EXTRA prlimit64 i:iipp prlimit64
fanotify_mark EXTRA fanotify_mark i:iiiiis fanotify_mark
+personality EXTRA personality Ei:i __personality personality
# Semaphore and shm system calls. msgctl, shmctl, and semctl have C
# wrappers (to set __IPC_64).
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list b/sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list
index 7ad55231f6..584ad1fcba 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list
@@ -6,3 +6,5 @@ sync_file_range - sync_file_range Ci:iiii sync_file_range
prlimit64 EXTRA prlimit64 i:iipp prlimit64
fanotify_mark EXTRA fanotify_mark i:iiiis fanotify_mark
+
+personality EXTRA personality Ei:i __personality personality
diff --git a/sysdeps/unix/sysv/linux/personality.c b/sysdeps/unix/sysv/linux/personality.c
new file mode 100644
index 0000000000..6724f1b2a6
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/personality.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 2015 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 <sys/personality.h>
+#include <sysdep.h>
+
+extern __typeof (personality) __personality;
+
+int
+__personality (unsigned long persona)
+{
+#ifdef PERSONALITY_TRUNCATE_ARGUMENT
+ /* Starting with kernel commit v2.6.21-3117-g97dc32c, the type of
+ task_struct->pesonality is "unsigned int".
+ Starting with kernel commit v2.6.35-rc1-372-g485d527, the personality
+ syscall accepts "unsigned int" instead of "long unsigned int".
+ Inbetween, a personality argument that does not fit into "unsigned int"
+ would result to system call returning -EINVAL.
+ We explicitly truncate the personality argument to "unsigned int"
+ to eliminate the uncertainty. */
+ persona = (unsigned int) persona;
+#endif
+
+ INTERNAL_SYSCALL_DECL (err);
+ long ret = INTERNAL_SYSCALL (personality, err, 1, persona);
+
+ /* Starting with kernel commit v2.6.29-6609-g11d06b2, the personality syscall
+ never fails. However, 32-bit kernels might flag valid values as errors, so
+ we need to reverse the error setting. We can't use the raw result as some
+ arches split the return/error values. */
+ if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (ret, err)))
+ ret = -INTERNAL_SYSCALL_ERRNO (ret, err);
+ return ret;
+}
+weak_alias (__personality, personality)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/syscalls.list b/sysdeps/unix/sysv/linux/s390/s390-32/syscalls.list
index 82baf9cf36..141b16523d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/syscalls.list
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/syscalls.list
@@ -20,3 +20,4 @@ setrlimit - setrlimit i:ip __setrlimit setrlimit@GLIBC_2.0 setrlimit@@GLIBC_2.2
prlimit64 EXTRA prlimit64 i:iipp prlimit64
fanotify_mark EXTRA fanotify_mark i:iiiiis fanotify_mark
+personality EXTRA personality Ei:i __personality personality
diff --git a/sysdeps/unix/sysv/linux/sh/syscalls.list b/sysdeps/unix/sysv/linux/sh/syscalls.list
index 2f4ac6548d..169d40f074 100644
--- a/sysdeps/unix/sysv/linux/sh/syscalls.list
+++ b/sysdeps/unix/sysv/linux/sh/syscalls.list
@@ -20,3 +20,5 @@ waitpid - waitpid Ci:ipi __waitpid waitpid
prlimit64 EXTRA prlimit64 i:iipp prlimit64
fanotify_mark EXTRA fanotify_mark i:iiiiis __fanotify_mark fanotify_mark@@GLIBC_2.16
+
+personality EXTRA personality Ei:i __personality personality
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/personality.c b/sysdeps/unix/sysv/linux/sparc/sparc64/personality.c
new file mode 100644
index 0000000000..250e501d91
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/personality.c
@@ -0,0 +1,3 @@
+/* Work around sign extension bug in the kernel. */
+#define PERSONALITY_TRUNCATE_ARGUMENT
+#include <sysdeps/unix/sysv/linux/personality.c>
diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
index caa6ccfbb1..afaf0337bd 100644
--- a/sysdeps/unix/sysv/linux/syscalls.list
+++ b/sysdeps/unix/sysv/linux/syscalls.list
@@ -46,7 +46,6 @@ munlockall - munlockall i: munlockall
nanosleep - nanosleep Ci:pp __nanosleep nanosleep
nfsservctl EXTRA nfsservctl i:ipp nfsservctl
pause - pause Ci: __libc_pause pause
-personality EXTRA personality i:i __personality personality
pipe - pipe i:f __pipe pipe
pipe2 - pipe2 i:fi __pipe2 pipe2
pivot_root EXTRA pivot_root i:ss pivot_root
diff --git a/sysdeps/unix/sysv/linux/tst-personality.c b/sysdeps/unix/sysv/linux/tst-personality.c
new file mode 100644
index 0000000000..1bfa5029df
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-personality.c
@@ -0,0 +1,45 @@
+/* BZ #19408 linux personality syscall wrapper test.
+
+ Copyright (C) 2015 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/personality.h>
+
+static int
+do_test (void)
+{
+ int rc = 0;
+ unsigned int test_persona = -EINVAL;
+ unsigned int saved_persona;
+
+ errno = 0xdefaced;
+ saved_persona = personality (0xffffffff);
+
+ if (personality (test_persona) != saved_persona ||
+ personality (0xffffffff) == -1 ||
+ personality (PER_LINUX) == -1 ||
+ personality (0xffffffff) != PER_LINUX ||
+ 0xdefaced != errno)
+ rc = 1;
+
+ (void) personality (saved_persona);
+ return rc;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/syscalls.list b/sysdeps/unix/sysv/linux/wordsize-64/syscalls.list
index 51ee8d8239..19cc6d9833 100644
--- a/sysdeps/unix/sysv/linux/wordsize-64/syscalls.list
+++ b/sysdeps/unix/sysv/linux/wordsize-64/syscalls.list
@@ -20,3 +20,4 @@ open - open Ci:siv __libc_open __open open __open64 open64
prlimit EXTRA prlimit64 i:iipp prlimit prlimit64
fanotify_mark EXTRA fanotify_mark i:iiiis fanotify_mark
+personality EXTRA personality i:i __personality personality
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list b/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
index 2cc58af2df..c98ac74d46 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
@@ -2,6 +2,7 @@
fallocate - fallocate Ci:iiii fallocate fallocate64
gettimeofday - gettimeofday:__vdso_gettimeofday@LINUX_2.6 i:pP __gettimeofday gettimeofday
+personality EXTRA personality Ei:i __personality personality
posix_fadvise - fadvise64 Vi:iiii posix_fadvise posix_fadvise64
preadv - preadv Ci:ipii preadv preadv64
pwritev - pwritev Ci:ipii pwritev pwritev64