From ccd8de9aa69df004a3df02333fb01f4eaf990d92 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Fri, 12 Nov 2004 01:27:04 +0000 Subject: [PATCH] Update. 2004-11-10 Jakub Jelinek * sysdeps/unix/sysv/linux/setreuid.c: Remove sys/syscall.h, sys/types.h, linux/posix_types.h, sysdep.h and pthread-functions.h includes. Include setxid.h. Use INLINE_SETXID_SYSCALL macro instead of INLINE_SYSCALL, kill the HAVE_PTR__NPTL_SETXID guarded snippets. * sysdeps/unix/sysv/linux/setegid.c: Likewise. * sysdeps/unix/sysv/linux/setuid.c: Likewise. * sysdeps/unix/sysv/linux/seteuid.c: Likewise. * sysdeps/unix/sysv/linux/setgid.c: Likewise. * sysdeps/unix/sysv/linux/setresuid.c: Likewise. * sysdeps/unix/sysv/linux/setresgid.c: Likewise. * sysdeps/unix/sysv/linux/setregid.c: Likewise. * sysdeps/unix/sysv/linux/i386/setegid.c: Likewise. * sysdeps/unix/sysv/linux/i386/setreuid.c: Likewise. * sysdeps/unix/sysv/linux/i386/setuid.c: Likewise. * sysdeps/unix/sysv/linux/i386/seteuid.c: Likewise. * sysdeps/unix/sysv/linux/i386/setgid.c: Likewise. * sysdeps/unix/sysv/linux/i386/setresuid.c: Likewise. * sysdeps/unix/sysv/linux/i386/setresgid.c: Likewise. * sysdeps/unix/sysv/linux/i386/setregid.c: Likewise. * sysdeps/unix/sysv/linux/alpha/setreuid.c: Likewise. Formatting. Change signed int into int. * sysdeps/unix/sysv/linux/alpha/setresuid.c: Likewise. * sysdeps/unix/sysv/linux/alpha/setresgid.c: Likewise. * sysdeps/unix/sysv/linux/alpha/setregid.c: Likewise. * sysdeps/unix/sysv/linux/syscalls.list (setresuid, setresgid): Remove. * sysdeps/unix/setxid.h: New file. * Rules (binaries-static): Add xtests-static. * Makeconfig (run-program-prefix): Filter also xtests-static. --- ChangeLog | 34 + Makeconfig | 2 +- Rules | 2 +- nptl/ChangeLog | 17 + nptl/Makefile | 11 +- nptl/allocatestack.c | 14 +- nptl/descr.h | 2 +- nptl/pthreadP.h | 2 +- nptl/sysdeps/pthread/pthread-functions.h | 4 +- nptl/sysdeps/pthread/setxid.h | 64 ++ nptl/tst-setuid1-static.c | 1 + nptl/tst-setuid1.c | 1085 ++++++++++++++++++++++ sysdeps/unix/setxid.h | 4 + sysdeps/unix/sysv/linux/syscalls.list | 2 - 14 files changed, 1231 insertions(+), 13 deletions(-) create mode 100644 nptl/sysdeps/pthread/setxid.h create mode 100644 nptl/tst-setuid1-static.c create mode 100644 nptl/tst-setuid1.c create mode 100644 sysdeps/unix/setxid.h diff --git a/ChangeLog b/ChangeLog index 3bf7a3e31c..b02b433c88 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +2004-11-10 Jakub Jelinek + + * sysdeps/unix/sysv/linux/setreuid.c: Remove sys/syscall.h, + sys/types.h, linux/posix_types.h, sysdep.h and pthread-functions.h + includes. Include setxid.h. Use INLINE_SETXID_SYSCALL macro + instead of INLINE_SYSCALL, kill the HAVE_PTR__NPTL_SETXID guarded + snippets. + * sysdeps/unix/sysv/linux/setegid.c: Likewise. + * sysdeps/unix/sysv/linux/setuid.c: Likewise. + * sysdeps/unix/sysv/linux/seteuid.c: Likewise. + * sysdeps/unix/sysv/linux/setgid.c: Likewise. + * sysdeps/unix/sysv/linux/setresuid.c: Likewise. + * sysdeps/unix/sysv/linux/setresgid.c: Likewise. + * sysdeps/unix/sysv/linux/setregid.c: Likewise. + * sysdeps/unix/sysv/linux/i386/setegid.c: Likewise. + * sysdeps/unix/sysv/linux/i386/setreuid.c: Likewise. + * sysdeps/unix/sysv/linux/i386/setuid.c: Likewise. + * sysdeps/unix/sysv/linux/i386/seteuid.c: Likewise. + * sysdeps/unix/sysv/linux/i386/setgid.c: Likewise. + * sysdeps/unix/sysv/linux/i386/setresuid.c: Likewise. + * sysdeps/unix/sysv/linux/i386/setresgid.c: Likewise. + * sysdeps/unix/sysv/linux/i386/setregid.c: Likewise. + * sysdeps/unix/sysv/linux/alpha/setreuid.c: Likewise. + Formatting. Change signed int into int. + * sysdeps/unix/sysv/linux/alpha/setresuid.c: Likewise. + * sysdeps/unix/sysv/linux/alpha/setresgid.c: Likewise. + * sysdeps/unix/sysv/linux/alpha/setregid.c: Likewise. + * sysdeps/unix/sysv/linux/syscalls.list (setresuid, setresgid): + Remove. + * sysdeps/unix/setxid.h: New file. + + * Rules (binaries-static): Add xtests-static. + * Makeconfig (run-program-prefix): Filter also xtests-static. + 2004-11-09 Paul Eggert + + * sysdeps/pthread/setxid.h: New file. + * sysdeps/pthread/pthread-functions.h (HAVE_PTR__NPTL_SETXID): Remove. + (struct xid_command): Add forward decl. + (struct pthread_functions): Change return type of __nptl_setxid hook + to int. + * pthreadP.h (__nptl_setxid): Change return type to int. + * allocatestack.c (__nptl_setxid): Call INTERNAL_SYSCALL_NCS in the + calling thread, return its return value and set errno on failure. + * descr.h (struct xid_command): Change id type to long array. + + * Makefile: Add rules to build and test tst-setuid1 and + tst-setuid1-static. + * tst-setuid1.c: New test. + * tst-setuid1-static.c: New test. + 2004-11-10 Jakub Jelinek * Makefile (tests): Add tst-exit3. diff --git a/nptl/Makefile b/nptl/Makefile index 087b748bb4..7b1759a08f 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -242,6 +242,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 \ tst-backtrace1 \ tst-oddstacklimit \ tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x +xtests = tst-setuid1 tst-setuid1-static # Files which must not be linked with libpthread. tests-nolibpthread = tst-unload @@ -342,6 +343,7 @@ link-libc-static := $(common-objpfx)libc.a $(static-gnulib) \ ifeq ($(build-static),yes) tests-static += tst-locale1 tst-locale2 +xtests-static += tst-setuid1-static endif # These tests are linked with libc before libpthread tests-reverse += tst-cancel5 tst-cancel23 tst-vfork1x tst-vfork2x @@ -499,9 +501,10 @@ $(objpfx)libpthread.so: $(common-objpfx)libc.so \ # Make sure we link with the thread library. ifeq ($(build-shared),yes) $(addprefix $(objpfx), \ - $(filter-out $(tests-static) $(tests-reverse) $(tests-nolibpthread), \ - $(tests) $(test-srcs))): $(objpfx)libpthread.so \ - $(objpfx)libpthread_nonshared.a + $(filter-out $(tests-static) $(xtests-static) $(tests-reverse) \ + $(tests-nolibpthread), \ + $(tests) $(xtests) $(test-srcs))): $(objpfx)libpthread.so \ + $(objpfx)libpthread_nonshared.a $(objpfx)tst-unload: $(common-objpfx)dlfcn/libdl.so # $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so, # since otherwise libpthread.so comes before libc.so when linking. @@ -509,7 +512,7 @@ $(addprefix $(objpfx), $(tests-reverse)): \ $(objpfx)../libc.so $(objpfx)libpthread.so \ $(objpfx)libpthread_nonshared.a $(objpfx)../libc.so: $(common-objpfx)libc.so ; -$(addprefix $(objpfx),$(tests-static)): $(objpfx)libpthread.a +$(addprefix $(objpfx),$(tests-static) $(xtests-static)): $(objpfx)libpthread.a $(objpfx)tst-atfork2.out: $(objpfx)tst-atfork2mod.so else diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index d4f3188f53..6c2367cc89 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -816,10 +816,11 @@ __find_thread_by_id (pid_t tid) } #endif -void +int attribute_hidden __nptl_setxid (struct xid_command *cmdp) { + int result; lll_lock (stack_cache_lock); __xidcmd = cmdp; @@ -891,7 +892,18 @@ __nptl_setxid (struct xid_command *cmdp) cur = cmdp->cntr; } + /* This must be last, otherwise the current thread might not have + permissions to send SIGSETXID syscall to the other threads. */ + result = INTERNAL_SYSCALL_NCS (cmdp->syscall_no, err, 3, + cmdp->id[0], cmdp->id[1], cmdp->id[2]); + if (INTERNAL_SYSCALL_ERROR_P (result, err)) + { + __set_errno (INTERNAL_SYSCALL_ERRNO (result, err)); + result = -1; + } + lll_unlock (stack_cache_lock); + return result; } static inline void __attribute__((always_inline)) diff --git a/nptl/descr.h b/nptl/descr.h index d81392921c..454bb2a547 100644 --- a/nptl/descr.h +++ b/nptl/descr.h @@ -97,7 +97,7 @@ struct pthread_unwind_buf struct xid_command { int syscall_no; - id_t id[3]; + long id[3]; volatile int cntr; }; diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index 1fedce5f3a..f73c817f60 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -448,6 +448,6 @@ extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer extern void __nptl_deallocate_tsd (void) attribute_hidden; -extern void __nptl_setxid (struct xid_command *cmdp) attribute_hidden; +extern int __nptl_setxid (struct xid_command *cmdp) attribute_hidden; #endif /* pthreadP.h */ diff --git a/nptl/sysdeps/pthread/pthread-functions.h b/nptl/sysdeps/pthread/pthread-functions.h index b1e0fcb26d..2845346128 100644 --- a/nptl/sysdeps/pthread/pthread-functions.h +++ b/nptl/sysdeps/pthread/pthread-functions.h @@ -24,6 +24,7 @@ #include #include +struct xid_command; /* Data type shared with libc. The libc uses it to pass on calls to the thread functions. */ @@ -93,8 +94,7 @@ struct pthread_functions void (*ptr___pthread_unwind) (__pthread_unwind_buf_t *) __attribute ((noreturn)) __cleanup_fct_attribute; void (*ptr__nptl_deallocate_tsd) (void); -#define HAVE_PTR__NPTL_SETXID - void (*ptr__nptl_setxid) (struct xid_command *); + int (*ptr__nptl_setxid) (struct xid_command *); }; /* Variable in libc.so. */ diff --git a/nptl/sysdeps/pthread/setxid.h b/nptl/sysdeps/pthread/setxid.h new file mode 100644 index 0000000000..8ec382f406 --- /dev/null +++ b/nptl/sysdeps/pthread/setxid.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2004 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + +#define __SETXID_1(cmd, arg1) \ + cmd.id[0] = arg1 +#define __SETXID_2(cmd, arg1, arg2) \ + __SETXID_1 (cmd, arg1); cmd.id[1] = arg2 +#define __SETXID_3(cmd, arg1, arg2, arg3) \ + __SETXID_2 (cmd, arg1, arg2); cmd.id[2] = arg3 + +#ifdef SINGLE_THREAD +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ + INLINE_SYSCALL (name, nr, args) +#elif defined SHARED +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ + ({ \ + int __result; \ + if (__builtin_expect (__libc_pthread_functions.ptr__nptl_setxid \ + != NULL, 0)) \ + { \ + struct xid_command __cmd; \ + __cmd.syscall_no = __NR_##name; \ + __SETXID_##nr (__cmd, args); \ + __result = __libc_pthread_functions.ptr__nptl_setxid (&__cmd); \ + } \ + else \ + __result = INLINE_SYSCALL (name, nr, args); \ + __result; \ + }) +#else +# define INLINE_SETXID_SYSCALL(name, nr, args...) \ + ({ \ + extern __typeof (__nptl_setxid) __nptl_setxid __attribute__((weak));\ + int __result; \ + if (__builtin_expect (__nptl_setxid != NULL, 0)) \ + { \ + struct xid_command __cmd; \ + __cmd.syscall_no = __NR_##name; \ + __SETXID_##nr (__cmd, args); \ + __result =__nptl_setxid (&__cmd); \ + } \ + else \ + __result = INLINE_SYSCALL (name, nr, args); \ + __result; \ + }) +#endif diff --git a/nptl/tst-setuid1-static.c b/nptl/tst-setuid1-static.c new file mode 100644 index 0000000000..46d26f0991 --- /dev/null +++ b/nptl/tst-setuid1-static.c @@ -0,0 +1 @@ +#include "tst-setuid1.c" diff --git a/nptl/tst-setuid1.c b/nptl/tst-setuid1.c new file mode 100644 index 0000000000..f026c576d6 --- /dev/null +++ b/nptl/tst-setuid1.c @@ -0,0 +1,1085 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include + + +static pthread_barrier_t b3, b4; +static uid_t prev_ruid, prev_euid, prev_suid, nobody_uid; +static gid_t prev_rgid, prev_egid, prev_sgid, nobody_gid; +enum ACTION { PREPARE, SET, CHECK_BEFORE, CHECK_AFTER }; +#define TESTNO(arg) ((long int) (arg) & 0xff) +#define THREADNO(arg) ((long int) (arg) >> 8) + + +static void +check_prev_uid (int tno) +{ + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != prev_ruid || euid != prev_euid || suid != prev_suid) + { + printf ("uids before in %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, prev_ruid, prev_euid, prev_suid); + exit (1); + } +} + + +static void +check_prev_gid (int tno) +{ + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != prev_rgid || egid != prev_egid || sgid != prev_sgid) + { + printf ("gids before in %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, prev_rgid, prev_egid, prev_sgid); + exit (1); + } +} + + +static void +test_setuid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setuid (nobody_uid) < 0) + { + printf ("setuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != nobody_uid || euid != nobody_uid || suid != nobody_uid) + { + printf ("after setuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, nobody_uid, nobody_uid, nobody_uid); + exit (1); + } + } +} + + +static void +test_setuid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresuid (nobody_uid, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + prev_ruid = nobody_uid; + prev_euid = nobody_uid; + return; + } + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setuid (prev_suid) < 0) + { + printf ("setuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != nobody_uid || euid != prev_suid || suid != prev_suid) + { + printf ("after setuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, nobody_uid, prev_suid, prev_suid); + exit (1); + } + } +} + + +static void +test_seteuid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && seteuid (nobody_uid) < 0) + { + printf ("seteuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != prev_ruid || euid != nobody_uid || suid != prev_suid) + { + printf ("after seteuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, prev_ruid, nobody_uid, prev_suid); + exit (1); + } + } +} + + +static void +test_seteuid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresuid (nobody_uid, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + prev_ruid = nobody_uid; + prev_euid = nobody_uid; + nobody_uid = prev_suid; + return; + } + + test_seteuid1 (action, tno); +} + + +static void +test_setreuid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setreuid (-1, nobody_uid) < 0) + { + printf ("setreuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid, esuid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (prev_ruid != nobody_uid) + esuid = nobody_uid; + else + esuid = prev_suid; + + if (ruid != prev_ruid || euid != nobody_uid || suid != esuid) + { + printf ("after setreuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, prev_ruid, nobody_uid, esuid); + exit (1); + } + } +} + + +static void +test_setreuid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setreuid (nobody_uid, -1) < 0) + { + printf ("setreuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != nobody_uid || euid != prev_euid || suid != prev_euid) + { + printf ("after setreuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, nobody_uid, prev_euid, prev_euid); + exit (1); + } + } +} + + +static void +test_setreuid3 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setreuid (nobody_uid, nobody_uid) < 0) + { + printf ("setreuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != nobody_uid || euid != nobody_uid || suid != nobody_uid) + { + printf ("after setreuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, nobody_uid, nobody_uid, nobody_uid); + exit (1); + } + } +} + + +static void +test_setreuid4 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresuid (nobody_uid, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + prev_ruid = nobody_uid; + prev_euid = nobody_uid; + nobody_uid = prev_suid; + return; + } + + test_setreuid1 (action, tno); +} + + +static void +test_setresuid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setresuid (-1, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != prev_ruid || euid != nobody_uid || suid != prev_suid) + { + printf ("after setresuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, prev_ruid, nobody_uid, prev_suid); + exit (1); + } + } +} + + +static void +test_setresuid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setresuid (prev_euid, nobody_uid, nobody_uid) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != prev_euid || euid != nobody_uid || suid != nobody_uid) + { + printf ("after setresuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, prev_euid, nobody_uid, nobody_uid); + exit (1); + } + } +} + + +static void +test_setresuid3 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_uid (tno); + + if (action == SET && setresuid (nobody_uid, nobody_uid, nobody_uid) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + uid_t ruid, euid, suid; + if (getresuid (&ruid, &euid, &suid) < 0) + { + printf ("getresuid failed: %d %m\n", tno); + exit (1); + } + + if (ruid != nobody_uid || euid != nobody_uid || suid != nobody_uid) + { + printf ("after setresuid %d (%d %d %d) != (%d %d %d)\n", tno, + ruid, euid, suid, nobody_uid, nobody_uid, nobody_uid); + exit (1); + } + } +} + + +static void +test_setresuid4 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresuid (nobody_uid, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + prev_ruid = nobody_uid; + prev_euid = nobody_uid; + nobody_uid = prev_suid; + return; + } + + test_setresuid1 (action, tno); +} + + +static void +test_setgid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setgid (nobody_gid) < 0) + { + printf ("setgid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != nobody_gid || egid != nobody_gid || sgid != nobody_gid) + { + printf ("after setgid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, nobody_gid, nobody_gid, nobody_gid); + exit (1); + } + } +} + + +static void +test_setgid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresgid (nobody_gid, nobody_gid, -1) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + prev_rgid = nobody_gid; + prev_egid = nobody_gid; + + if (setresuid (nobody_uid, nobody_uid, -1) < 0) + { + printf ("setresuid failed: %m\n"); + exit (1); + } + + prev_ruid = nobody_uid; + prev_euid = nobody_uid; + return; + } + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setgid (prev_sgid) < 0) + { + printf ("setgid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != nobody_gid || egid != prev_sgid || sgid != prev_sgid) + { + printf ("after setgid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, nobody_gid, prev_sgid, prev_sgid); + exit (1); + } + } +} + + +static void +test_setegid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setegid (nobody_gid) < 0) + { + printf ("setegid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != prev_rgid || egid != nobody_gid || sgid != prev_sgid) + { + printf ("after setegid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, prev_rgid, nobody_gid, prev_sgid); + exit (1); + } + } +} + + +static void +test_setegid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresgid (nobody_gid, nobody_gid, -1) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + prev_rgid = nobody_gid; + prev_egid = nobody_gid; + nobody_gid = prev_sgid; + return; + } + + test_setegid1 (action, tno); +} + + +static void +test_setregid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setregid (-1, nobody_gid) < 0) + { + printf ("setregid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid, esgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (prev_rgid != nobody_gid) + esgid = nobody_gid; + else + esgid = prev_sgid; + + if (rgid != prev_rgid || egid != nobody_gid || sgid != esgid) + { + printf ("after setregid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, prev_rgid, nobody_gid, esgid); + exit (1); + } + } +} + + +static void +test_setregid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setregid (nobody_gid, -1) < 0) + { + printf ("setregid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != nobody_gid || egid != prev_egid || sgid != prev_egid) + { + printf ("after setregid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, nobody_gid, prev_egid, prev_egid); + exit (1); + } + } +} + + +static void +test_setregid3 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setregid (nobody_gid, nobody_gid) < 0) + { + printf ("setregid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != nobody_gid || egid != nobody_gid || sgid != nobody_gid) + { + printf ("after setregid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, nobody_gid, nobody_gid, nobody_gid); + exit (1); + } + } +} + + +static void +test_setregid4 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresgid (nobody_gid, nobody_gid, -1) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + prev_rgid = nobody_gid; + prev_egid = nobody_gid; + nobody_gid = prev_sgid; + return; + } + + test_setregid1 (action, tno); +} + + +static void +test_setresgid1 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setresgid (-1, nobody_gid, -1) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != prev_rgid || egid != nobody_gid || sgid != prev_sgid) + { + printf ("after setresgid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, prev_rgid, nobody_gid, prev_sgid); + exit (1); + } + } +} + + +static void +test_setresgid2 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setresgid (prev_egid, nobody_gid, nobody_gid) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != prev_egid || egid != nobody_gid || sgid != nobody_gid) + { + printf ("after setresgid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, prev_egid, nobody_gid, nobody_gid); + exit (1); + } + } +} + + +static void +test_setresgid3 (enum ACTION action, int tno) +{ + if (action == PREPARE) + return; + + if (action != CHECK_AFTER) + check_prev_gid (tno); + + if (action == SET && setresgid (nobody_gid, nobody_gid, nobody_gid) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + if (action != CHECK_BEFORE) + { + gid_t rgid, egid, sgid; + if (getresgid (&rgid, &egid, &sgid) < 0) + { + printf ("getresgid failed: %d %m\n", tno); + exit (1); + } + + if (rgid != nobody_gid || egid != nobody_gid || sgid != nobody_gid) + { + printf ("after setresgid %d (%d %d %d) != (%d %d %d)\n", tno, + rgid, egid, sgid, nobody_gid, nobody_gid, nobody_gid); + exit (1); + } + } +} + + +static void +test_setresgid4 (enum ACTION action, int tno) +{ + if (action == PREPARE) + { + if (setresgid (nobody_gid, nobody_gid, -1) < 0) + { + printf ("setresgid failed: %m\n"); + exit (1); + } + + prev_rgid = nobody_gid; + prev_egid = nobody_gid; + nobody_gid = prev_sgid; + return; + } + + test_setresgid1 (action, tno); +} + + +static struct setuid_test +{ + const char *name; + void (*test) (enum ACTION, int tno); +} setuid_tests[] = +{ + { "setuid1", test_setuid1 }, + { "setuid2", test_setuid2 }, + { "seteuid1", test_seteuid1 }, + { "seteuid2", test_seteuid2 }, + { "setreuid1", test_setreuid1 }, + { "setreuid2", test_setreuid2 }, + { "setreuid3", test_setreuid3 }, + { "setreuid4", test_setreuid4 }, + { "setresuid1", test_setresuid1 }, + { "setresuid2", test_setresuid2 }, + { "setresuid3", test_setresuid3 }, + { "setresuid4", test_setresuid4 }, + { "setgid1", test_setgid1 }, + { "setgid2", test_setgid2 }, + { "setegid1", test_setegid1 }, + { "setegid2", test_setegid2 }, + { "setregid1", test_setregid1 }, + { "setregid2", test_setregid2 }, + { "setregid3", test_setregid3 }, + { "setregid4", test_setregid4 }, + { "setresgid1", test_setresgid1 }, + { "setresgid2", test_setresgid2 }, + { "setresgid3", test_setresgid3 }, + { "setresgid4", test_setresgid4 } +}; + + +static void * +tf2 (void *arg) +{ + int e = pthread_barrier_wait (&b4); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + setuid_tests[TESTNO (arg)].test (CHECK_AFTER, THREADNO (arg)); + return NULL; +} + + +static void * +tf (void *arg) +{ + setuid_tests[TESTNO (arg)].test (CHECK_BEFORE, THREADNO (arg)); + + int e = pthread_barrier_wait (&b3); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + return tf2 (arg); +} + + +static int +do_one_test (long int testno) +{ + printf ("%s test\n", setuid_tests[testno].name); + + pid_t pid = fork (); + if (pid == 0) + { + setuid_tests[testno].test (PREPARE, 0); + setuid_tests[testno].test (SET, 0); + exit (0); + } + + if (pid < 0) + { + printf ("fork failed: %m\n"); + exit (1); + } + + int status; + if (waitpid (pid, &status, 0) < 0) + { + printf ("waitpid failed: %m\n"); + exit (1); + } + + if (!WIFEXITED (status)) + { + puts ("child did not exit"); + exit (1); + } + + if (WEXITSTATUS (status)) + { + printf ("skipping %s test\n", setuid_tests[testno].name); + return 0; + } + + pid = fork (); + if (pid == 0) + { + setuid_tests[testno].test (PREPARE, 0); + + pthread_t th; + int e = pthread_create (&th, NULL, tf, (void *) (testno | 0x100L)); + if (e != 0) + { + printf ("create failed: %m\n"); + exit (1); + } + + pthread_t th2; + e = pthread_create (&th2, NULL, tf, (void *) (testno | 0x200L)); + if (e != 0) + { + printf ("create failed: %m\n"); + exit (1); + } + + e = pthread_barrier_wait (&b3); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + setuid_tests[testno].test (SET, 0); + + pthread_t th3; + e = pthread_create (&th3, NULL, tf2, (void *) (testno | 0x300L)); + if (e != 0) + { + printf ("create failed: %m\n"); + exit (1); + } + + e = pthread_barrier_wait (&b4); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + exit (0); + } + + if (pid < 0) + { + printf ("fork failed: %m\n"); + exit (1); + } + + if (waitpid (pid, &status, 0) < 0) + { + printf ("waitpid failed: %m\n"); + exit (1); + } + + if (!WIFEXITED (status)) + { + puts ("second child did not exit"); + exit (1); + } + + if (WEXITSTATUS (status)) + exit (WEXITSTATUS (status)); + + return 0; +} + + +static int +do_test (void) +{ + struct passwd *pwd = getpwnam ("nobody"); + if (pwd == NULL) + { + puts ("User nobody doesn't exist"); + return 0; + } + nobody_uid = pwd->pw_uid; + nobody_gid = pwd->pw_gid; + + if (getresuid (&prev_ruid, &prev_euid, &prev_suid) < 0) + { + printf ("getresuid failed: %m\n"); + exit (1); + } + + if (getresgid (&prev_rgid, &prev_egid, &prev_sgid) < 0) + { + printf ("getresgid failed: %m\n"); + exit (1); + } + + if (prev_ruid == nobody_uid || prev_euid == nobody_uid + || prev_suid == nobody_uid) + { + puts ("already running as user nobody, skipping tests"); + exit (0); + } + + if (prev_rgid == nobody_gid || prev_egid == nobody_gid + || prev_sgid == nobody_gid) + { + puts ("already running as group nobody, skipping tests"); + exit (0); + } + + if (pthread_barrier_init (&b3, NULL, 3) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_barrier_init (&b4, NULL, 4) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + for (unsigned long int testno = 0; + testno < sizeof (setuid_tests) / sizeof (setuid_tests[0]); + ++testno) + do_one_test (testno); + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/unix/setxid.h b/sysdeps/unix/setxid.h new file mode 100644 index 0000000000..c18e2d4a6b --- /dev/null +++ b/sysdeps/unix/setxid.h @@ -0,0 +1,4 @@ +#include + +#define INLINE_SETXID_SYSCALL(name, nr, args...) \ + INLINE_SYSCALL (name, nr, args) diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list index d7c8b443c4..a97305e822 100644 --- a/sysdeps/unix/sysv/linux/syscalls.list +++ b/sysdeps/unix/sysv/linux/syscalls.list @@ -66,8 +66,6 @@ sendfile64 - sendfile64 i:iipi sendfile64 setfsgid EXTRA setfsgid i:i setfsgid setfsuid EXTRA setfsuid i:i setfsuid setpgid - setpgid i:ii __setpgid setpgid -setresuid - setresuid i:iii __setresuid setresuid -setresgid - setresgid i:iii __setresgid setresgid sigaltstack - sigaltstack i:PP __sigaltstack sigaltstack sysinfo EXTRA sysinfo i:p sysinfo swapon - swapon i:si __swapon swapon