Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Dmitry V. Levin committed Dec 31, 2015
1 parent cc42170 commit e0043e1
Show file tree
Hide file tree
Showing 16 changed files with 139 additions and 3 deletions.
25 changes: 25 additions & 0 deletions 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>.
Expand Down
5 changes: 3 additions & 2 deletions sysdeps/unix/sysv/linux/Makefile
Expand Up @@ -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()"
Expand All @@ -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).

Expand Down
2 changes: 2 additions & 0 deletions sysdeps/unix/sysv/linux/arm/syscalls.list
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions sysdeps/unix/sysv/linux/hppa/syscalls.list
Expand Up @@ -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
2 changes: 2 additions & 0 deletions sysdeps/unix/sysv/linux/i386/syscalls.list
Expand Up @@ -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
1 change: 1 addition & 0 deletions sysdeps/unix/sysv/linux/m68k/syscalls.list
Expand Up @@ -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
1 change: 1 addition & 0 deletions sysdeps/unix/sysv/linux/microblaze/syscalls.list
Expand Up @@ -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).
Expand Down
2 changes: 2 additions & 0 deletions sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list
Expand Up @@ -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
49 changes: 49 additions & 0 deletions 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)
1 change: 1 addition & 0 deletions sysdeps/unix/sysv/linux/s390/s390-32/syscalls.list
Expand Up @@ -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
2 changes: 2 additions & 0 deletions sysdeps/unix/sysv/linux/sh/syscalls.list
Expand Up @@ -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
3 changes: 3 additions & 0 deletions 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>
1 change: 0 additions & 1 deletion sysdeps/unix/sysv/linux/syscalls.list
Expand Up @@ -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
Expand Down
45 changes: 45 additions & 0 deletions 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"
1 change: 1 addition & 0 deletions sysdeps/unix/sysv/linux/wordsize-64/syscalls.list
Expand Up @@ -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
1 change: 1 addition & 0 deletions sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
Expand Up @@ -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
Expand Down

0 comments on commit e0043e1

Please sign in to comment.