diff options
author | Dmitry V. Levin <ldv@altlinux.org> | 2015-12-27 16:30:02 +0000 |
---|---|---|
committer | Dmitry V. Levin <ldv@altlinux.org> | 2015-12-31 00:17:48 +0000 |
commit | e0043e17dfc52fe1702746543127cb4a87232bcd (patch) | |
tree | 73e7287e78b9775e8a4c603136fbf6c6fa1a5451 /sysdeps/unix | |
parent | cc42170ef6ca931c7527a86f14fc66059b6dfff4 (diff) | |
download | glibc-e0043e17dfc52fe1702746543127cb4a87232bcd.zip glibc-e0043e17dfc52fe1702746543127cb4a87232bcd.tar.gz glibc-e0043e17dfc52fe1702746543127cb4a87232bcd.tar.bz2 |
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.
Diffstat (limited to 'sysdeps/unix')
-rw-r--r-- | sysdeps/unix/sysv/linux/Makefile | 5 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/arm/syscalls.list | 2 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/hppa/syscalls.list | 1 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/i386/syscalls.list | 2 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/m68k/syscalls.list | 1 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/microblaze/syscalls.list | 1 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list | 2 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/personality.c | 49 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/s390/s390-32/syscalls.list | 1 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/sh/syscalls.list | 2 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/sparc/sparc64/personality.c | 3 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/syscalls.list | 1 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/tst-personality.c | 45 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/wordsize-64/syscalls.list | 1 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list | 1 |
15 files changed, 114 insertions, 3 deletions
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index f6269ea..9999600 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 911ed7d..c06954f 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 2cb8d02..d29c358 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 1cebd6a..6282ff8 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 ad4ca46..4260f3e 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 86fd40b..da0fd4e 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 7ad5523..584ad1f 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 0000000..6724f1b --- /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 82baf9c..141b165 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 2f4ac65..169d40f 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 0000000..250e501 --- /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 caa6ccf..afaf033 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 0000000..1bfa502 --- /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 51ee8d8..19cc6d9 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 2cc58af..c98ac74 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 |