diff mbox

[BZ,#19408] Fix linux personality syscall wrapper

Message ID 20151228010929.GA1819@altlinux.org
State New
Headers show

Commit Message

Dmitry V. Levin Dec. 28, 2015, 1:09 a.m. UTC
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 report syscall errors, add a wrapper around personality syscall;
if the system call return value looks like 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: New file.
* sysdeps/unix/sysv/linux/tst-personality.c: New file.
* 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.
---
 sysdeps/unix/sysv/linux/Makefile                   |  5 ++-
 sysdeps/unix/sysv/linux/arm/syscalls.list          |  2 +
 sysdeps/unix/sysv/linux/hppa/syscalls.list         |  1 +
 sysdeps/unix/sysv/linux/i386/syscalls.list         |  2 +
 sysdeps/unix/sysv/linux/m68k/syscalls.list         |  1 +
 sysdeps/unix/sysv/linux/microblaze/syscalls.list   |  1 +
 .../unix/sysv/linux/mips/mips64/n32/syscalls.list  |  2 +
 sysdeps/unix/sysv/linux/personality.c              | 49 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/s390/s390-32/syscalls.list |  1 +
 sysdeps/unix/sysv/linux/sh/syscalls.list           |  2 +
 .../unix/sysv/linux/sparc/sparc64/personality.c    |  3 ++
 sysdeps/unix/sysv/linux/syscalls.list              |  1 -
 sysdeps/unix/sysv/linux/tst-personality.c          | 41 ++++++++++++++++++
 sysdeps/unix/sysv/linux/wordsize-64/syscalls.list  |  1 +
 sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list   |  1 +
 15 files changed, 110 insertions(+), 3 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/personality.c
 create mode 100644 sysdeps/unix/sysv/linux/sparc/sparc64/personality.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-personality.c

Comments

Mike Frysinger Dec. 29, 2015, 9:42 p.m. UTC | #1
On 28 Dec 2015 04:09, Dmitry V. Levin wrote:
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/personality.c
>
> +  INTERNAL_SYSCALL_DECL (err);
> +  long ret = INTERNAL_SYSCALL (personality, err, 1, persona);
> +
> +  /* Starting with kernel commit v2.6.29-6609-g11d06b2, personality syscall
> +     never fails to set the personality.  However, due to architecture
> +     limitations of 32-bit kernels, personality syscall still may return
> +     an "error".  */
> +  if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (ret, err)))
> +    ret = -INTERNAL_SYSCALL_ERRNO (ret, err);
> +  return ret;
> +}

INTERNAL_SYSCALL returns the raw value from the kernel, so why do you
need to test it directly ?

> +  if (personality (test_persona) != saved_persona ||
> +      personality (0xffffffff) == -1 ||
> +      personality (PER_LINUX) == -1 ||
> +      personality (0xffffffff) != PER_LINUX)
> +    rc = 1;

should this also verify errno is not changed ?

> +  (void) personality (saved_persona);

we don't have __wur on this func, so the (void) is kind of pointless
-mike
Dmitry V. Levin Dec. 29, 2015, 11:27 p.m. UTC | #2
On Tue, Dec 29, 2015 at 04:42:18PM -0500, Mike Frysinger wrote:
> On 28 Dec 2015 04:09, Dmitry V. Levin wrote:
> > --- /dev/null
> > +++ b/sysdeps/unix/sysv/linux/personality.c
> >
> > +  INTERNAL_SYSCALL_DECL (err);
> > +  long ret = INTERNAL_SYSCALL (personality, err, 1, persona);
> > +
> > +  /* Starting with kernel commit v2.6.29-6609-g11d06b2, personality syscall
> > +     never fails to set the personality.  However, due to architecture
> > +     limitations of 32-bit kernels, personality syscall still may return
> > +     an "error".  */
> > +  if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (ret, err)))
> > +    ret = -INTERNAL_SYSCALL_ERRNO (ret, err);
> > +  return ret;
> > +}
> 
> INTERNAL_SYSCALL returns the raw value from the kernel, so why do you
> need to test it directly ?

While some architectures (including x86/x86_64) use negated errno semantics,
others (e.g. mips, nios2, powerpc, and sparc) use dedicated registers to return
an error condition.  In the latter case, the kernel syscall exit code negates
the value returned by sys_personality and returns it to userspace as an
"errno".  It has to be negated again to recover the value returned by
sys_personality.

> > +  if (personality (test_persona) != saved_persona ||
> > +      personality (0xffffffff) == -1 ||
> > +      personality (PER_LINUX) == -1 ||
> > +      personality (0xffffffff) != PER_LINUX)
> > +    rc = 1;
> 
> should this also verify errno is not changed ?

Like this?

  errno = 0xdefaced;
  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);
> 
> we don't have __wur on this func, so the (void) is kind of pointless

This is my way to show that in this case, unlike others,
the return code is irrelevant.  If you or somebody else don't like this style,
I have no problem removing the (void).
Mike Frysinger Dec. 29, 2015, 11:50 p.m. UTC | #3
On 30 Dec 2015 02:27, Dmitry V. Levin wrote:
> On Tue, Dec 29, 2015 at 04:42:18PM -0500, Mike Frysinger wrote:
> > On 28 Dec 2015 04:09, Dmitry V. Levin wrote:
> > > --- /dev/null
> > > +++ b/sysdeps/unix/sysv/linux/personality.c
> > >
> > > +  INTERNAL_SYSCALL_DECL (err);
> > > +  long ret = INTERNAL_SYSCALL (personality, err, 1, persona);
> > > +
> > > +  /* Starting with kernel commit v2.6.29-6609-g11d06b2, personality syscall
> > > +     never fails to set the personality.  However, due to architecture
> > > +     limitations of 32-bit kernels, personality syscall still may return
> > > +     an "error".  */
> > > +  if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (ret, err)))
> > > +    ret = -INTERNAL_SYSCALL_ERRNO (ret, err);
> > > +  return ret;
> > > +}
> > 
> > INTERNAL_SYSCALL returns the raw value from the kernel, so why do you
> > need to test it directly ?
> 
> While some architectures (including x86/x86_64) use negated errno semantics,
> others (e.g. mips, nios2, powerpc, and sparc) use dedicated registers to return
> an error condition.  In the latter case, the kernel syscall exit code negates
> the value returned by sys_personality and returns it to userspace as an
> "errno".  It has to be negated again to recover the value returned by
> sys_personality.

i'm aware of some arches doing split error paths, but doesn't the kernel
already handle this ?  i'm not seeing this sort of logic for ptrace or
mmap calls where any value is valid.

i guess the commit could use clarification here.
-mike
Dmitry V. Levin Dec. 30, 2015, 12:26 a.m. UTC | #4
On Tue, Dec 29, 2015 at 06:50:07PM -0500, Mike Frysinger wrote:
> On 30 Dec 2015 02:27, Dmitry V. Levin wrote:
> > On Tue, Dec 29, 2015 at 04:42:18PM -0500, Mike Frysinger wrote:
> > > On 28 Dec 2015 04:09, Dmitry V. Levin wrote:
> > > > --- /dev/null
> > > > +++ b/sysdeps/unix/sysv/linux/personality.c
> > > >
> > > > +  INTERNAL_SYSCALL_DECL (err);
> > > > +  long ret = INTERNAL_SYSCALL (personality, err, 1, persona);
> > > > +
> > > > +  /* Starting with kernel commit v2.6.29-6609-g11d06b2, personality syscall
> > > > +     never fails to set the personality.  However, due to architecture
> > > > +     limitations of 32-bit kernels, personality syscall still may return
> > > > +     an "error".  */
> > > > +  if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (ret, err)))
> > > > +    ret = -INTERNAL_SYSCALL_ERRNO (ret, err);
> > > > +  return ret;
> > > > +}
> > > 
> > > INTERNAL_SYSCALL returns the raw value from the kernel, so why do you
> > > need to test it directly ?
> > 
> > While some architectures (including x86/x86_64) use negated errno semantics,
> > others (e.g. mips, nios2, powerpc, and sparc) use dedicated registers to return
> > an error condition.  In the latter case, the kernel syscall exit code negates
> > the value returned by sys_personality and returns it to userspace as an
> > "errno".  It has to be negated again to recover the value returned by
> > sys_personality.
> 
> i'm aware of some arches doing split error paths, but doesn't the kernel
> already handle this ?

Unfortunately, it doesn't.

> i'm not seeing this sort of logic for ptrace or
> mmap calls where any value is valid.

mmap doesn't have this issue because you cannot trick it to return
an address >= -4095.

ptrace doesn't have this issue because it doesn't return arbitrary values,
PTRACE_PEEK{TEXT,DATA,USER) return value is stored in memory, see
sysdeps/unix/sysv/linux/ptrace.c.

> i guess the commit could use clarification here.

The subject is tricky and the commit is quite lengthy already.
What would you like to be clarified?
Mike Frysinger Dec. 30, 2015, 3:04 a.m. UTC | #5
On 30 Dec 2015 03:26, Dmitry V. Levin wrote:
> On Tue, Dec 29, 2015 at 06:50:07PM -0500, Mike Frysinger wrote:
> > i guess the commit could use clarification here.
> 
> The subject is tricky and the commit is quite lengthy already.
> What would you like to be clarified?

/* 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.  */
-mike
diff mbox

Patch

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..be5ada7
--- /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, personality
+     syscall accepts "unsigned int" instead of "long unsigned int".
+     Inbetween, a personality value that does not fit into "unsigned int"
+     would result to system call returning -EINVAL.
+     We explicitly truncate the personality value 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, personality syscall
+     never fails to set the personality.  However, due to architecture
+     limitations of 32-bit kernels, personality syscall still may return
+     an "error".  */
+  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..2763db2
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-personality.c
@@ -0,0 +1,41 @@ 
+/* 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 = personality (0xffffffff);
+
+  if (personality (test_persona) != saved_persona ||
+      personality (0xffffffff) == -1 ||
+      personality (PER_LINUX) == -1 ||
+      personality (0xffffffff) != PER_LINUX)
+    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