diff options
Diffstat (limited to 'nptl')
-rw-r--r-- | nptl/ChangeLog | 34 | ||||
-rw-r--r-- | nptl/Makefile | 6 | ||||
-rw-r--r-- | nptl/Versions | 5 | ||||
-rw-r--r-- | nptl/allocatestack.c | 81 | ||||
-rw-r--r-- | nptl/descr.h | 10 | ||||
-rw-r--r-- | nptl/init.c | 40 | ||||
-rw-r--r-- | nptl/pt-allocrtsig.c | 7 | ||||
-rw-r--r-- | nptl/pthreadP.h | 9 | ||||
-rw-r--r-- | nptl/pthread_setegid.c | 3 | ||||
-rw-r--r-- | nptl/pthread_seteuid.c | 3 | ||||
-rw-r--r-- | nptl/pthread_setgid.c | 3 | ||||
-rw-r--r-- | nptl/pthread_setregid.c | 3 | ||||
-rw-r--r-- | nptl/pthread_setresgid.c | 3 | ||||
-rw-r--r-- | nptl/pthread_setresuid.c | 3 | ||||
-rw-r--r-- | nptl/pthread_setreuid.c | 3 | ||||
-rw-r--r-- | nptl/pthread_setuid.c | 3 | ||||
-rw-r--r-- | nptl/sysdeps/pthread/pthread-functions.h | 2 | ||||
-rw-r--r-- | nptl/sysdeps/pthread/pthread.h | 30 | ||||
-rw-r--r-- | nptl/sysdeps/unix/sysv/linux/allocrtsig.c | 4 |
19 files changed, 243 insertions, 9 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog index db3aeba3f7..e4bcfed2e9 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,37 @@ +2004-09-19 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/allocrtsig.c: Allocate second signal for + internal use. + * allocatestack.c (__nptl_setxid): New function. + * descr.h (struct xid_command): Define type. + * init.c (pthread_functions): Add ptr__nptl_setxid initialization. + (sighandler_setxid): New function. + (__pthread_initialize_minimal): Register sighandler_setxid for + SIGCANCEL. + * pt-allocrtsig.c: Update comment. + * pthreadP.h: Define SIGSETXID. Declare __xidcmd variable. + Declare __nptl_setxid. + * sysdeps/pthread/pthread-functions.h: Add ptr__nptl_setxid. + * sysdeps/pthread/pthread.h: Declare pthread_setgid_np, + pthread_setuid_np, pthread_setegid_np, pthread_seteuid_np, + pthread_setregid_np, pthread_setreuid_np, pthread_setresgid_np, + and pthread_setresuid_np. + * pthread_setgid_np.c: New file. + * pthread_setuid_np.c: New file. + * pthread_setegid_np.c: New file. + * pthread_seteuid_np.c: New file. + * pthread_setregid_np.c: New file. + * pthread_setreuid_np.c: New file. + * pthread_setresgid_np.c: New file. + * pthread_setresuid_np.c: New file. + * Versions [libpthread, GLIBC_2.3.4]: Add pthread_setgid_np, + pthread_setuid_np, pthread_setegid_np, pthread_seteuid_np, + pthread_setregid_np, pthread_setreuid_np, pthread_setresgid_np, + and pthread_setresuid_np. + * Makefile (libpthread-routines): Add pthread_setuid, pthread_seteuid, + pthread_setreuid, pthread_setresuid, pthread_setgid, pthread_setegid, + pthread_setregid, and pthread_setresgid. + 2004-09-18 Ulrich Drepper <drepper@redhat.com> * allocatestack.c (allocate_stack): Return EAGAIN instead of diff --git a/nptl/Makefile b/nptl/Makefile index e75752f801..beaf6d7eab 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -115,7 +115,11 @@ libpthread-routines = init events version \ pthread_kill_other_threads \ pthread_getaffinity pthread_setaffinity \ pthread_attr_getaffinity pthread_attr_setaffinity \ - cleanup_routine unwind-forcedunwind + cleanup_routine unwind-forcedunwind \ + pthread_setuid pthread_seteuid pthread_setreuid \ + pthread_setresuid \ + pthread_setgid pthread_setegid pthread_setregid \ + pthread_setresgid libpthread-shared-only-routines = version pt-allocrtsig unwind-forcedunwind libpthread-static-only-routines = pthread_atfork diff --git a/nptl/Versions b/nptl/Versions index 7e8ac9e271..ee4a6e04b5 100644 --- a/nptl/Versions +++ b/nptl/Versions @@ -228,6 +228,11 @@ libpthread { # New affinity interfaces. pthread_getaffinity_np; pthread_setaffinity_np; pthread_attr_getaffinity_np; pthread_attr_setaffinity_np; + + pthread_setuid_np; pthread_seteuid_np; pthread_setreuid_np; + pthread_setresuid_np; + pthread_setgid_np; pthread_setegid_np; pthread_setregid_np; + pthread_setresgid_np; } GLIBC_PRIVATE { diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index cbdd781eeb..242da0a5a1 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -19,6 +19,7 @@ #include <assert.h> #include <errno.h> +#include <signal.h> #include <stdint.h> #include <string.h> #include <unistd.h> @@ -26,7 +27,7 @@ #include <sys/param.h> #include <dl-sysdep.h> #include <tls.h> - +#include <lowlevellock.h> #ifndef NEED_SEPARATE_REGISTER_STACK @@ -815,6 +816,84 @@ __find_thread_by_id (pid_t tid) } #endif +void +attribute_hidden +__nptl_setxid (struct xid_command *cmdp) +{ + lll_lock (stack_cache_lock); + + __xidcmd = cmdp; + cmdp->cntr = 0; + + INTERNAL_SYSCALL_DECL (err); + + struct pthread *self = THREAD_SELF; + + /* Iterate over the list with system-allocated threads first. */ + list_t *runp; + list_for_each (runp, &stack_used) + { + struct pthread *t = list_entry (runp, struct pthread, list); + if (t != self) + { + int val; +#if __ASSUME_TGKILL + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); +#else +# ifdef __NR_tgkill + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); + if (INTERNAL_SYSCALL_ERROR_P (val, err) + && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif + val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID); +#endif + + if (!INTERNAL_SYSCALL_ERROR_P (val, err)) + atomic_increment (&cmdp->cntr); + } + } + + /* Now the list with threads using user-allocated stacks. */ + list_for_each (runp, &__stack_user) + { + struct pthread *t = list_entry (runp, struct pthread, list); + if (t != self) + { + int val; +#if __ASSUME_TGKILL + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); +#else +# ifdef __NR_tgkill + val = INTERNAL_SYSCALL (tgkill, err, 3, + THREAD_GETMEM (THREAD_SELF, pid), + t->tid, SIGSETXID); + if (INTERNAL_SYSCALL_ERROR_P (val, err) + && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS) +# endif + val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID); +#endif + + if (!INTERNAL_SYSCALL_ERROR_P (val, err)) + atomic_increment (&cmdp->cntr); + } + } + + int cur = cmdp->cntr; + while (cur != 0) + { + lll_futex_wait (&cmdp->cntr, cur); + cur = cmdp->cntr; + } + + lll_unlock (stack_cache_lock); +} + static inline void __attribute__((always_inline)) init_one_static_tls (struct pthread *curp, struct link_map *map) { diff --git a/nptl/descr.h b/nptl/descr.h index 3611698048..0f8d347b79 100644 --- a/nptl/descr.h +++ b/nptl/descr.h @@ -92,6 +92,16 @@ struct pthread_unwind_buf }; +/* Opcodes and data types for communication with the signal handler to + change user/group IDs. */ +struct xid_command +{ + int syscall_no; + id_t id[3]; + volatile int cntr; +}; + + /* Thread descriptor data structure. */ struct pthread { diff --git a/nptl/init.c b/nptl/init.c index e58dae0ba6..aad2c9001f 100644 --- a/nptl/init.c +++ b/nptl/init.c @@ -32,6 +32,7 @@ #include <version.h> #include <shlib-compat.h> #include <smp.h> +#include <lowlevellock.h> #ifndef __NR_set_tid_address @@ -131,7 +132,8 @@ static const struct pthread_functions pthread_functions = .ptr__pthread_cleanup_pop_restore = __pthread_cleanup_pop_restore, .ptr_nthreads = &__nptl_nthreads, .ptr___pthread_unwind = &__pthread_unwind, - .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd + .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd, + .ptr__nptl_setxid = __nptl_setxid }; # define ptr_pthread_functions &pthread_functions #else @@ -144,7 +146,7 @@ static void sigcancel_handler (int sig, siginfo_t *si, void *ctx) { /* Safety check. It would be possible to call this function for - other signals and send a signal from another thread. This is not + other signals and send a signal from another process. This is not correct and might even be a security problem. Try to catch as many incorrect invocations as possible. */ if (sig != SIGCANCEL @@ -190,6 +192,34 @@ sigcancel_handler (int sig, siginfo_t *si, void *ctx) } +struct xid_command *__xidcmd attribute_hidden; + +/* For asynchronous cancellation we use a signal. This is the handler. */ +static void +sighandler_setxid (int sig, siginfo_t *si, void *ctx) +{ + /* Safety check. It would be possible to call this function for + other signals and send a signal from another process. This is not + correct and might even be a security problem. Try to catch as + many incorrect invocations as possible. */ + if (sig != SIGSETXID +#ifdef __ASSUME_CORRECT_SI_PID + /* Kernels before 2.5.75 stored the thread ID and not the process + ID in si_pid so we skip this test. */ + || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid) +#endif + || si->si_code != SI_TKILL) + return; + + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0], + __xidcmd->id[1], __xidcmd->id[2]); + + if (atomic_decrement_val (&__xidcmd->cntr) == 0) + lll_futex_wake (&__xidcmd->cntr, 1); +} + + /* When using __thread for this, we do it in libc so as not to give libpthread its own TLS segment just for this. */ extern void **__libc_dl_error_tsd (void) __attribute__ ((const)); @@ -242,6 +272,12 @@ __pthread_initialize_minimal_internal (void) (void) __libc_sigaction (SIGCANCEL, &sa, NULL); + /* Install the handle to change the threads' uid/gid. */ + sa.sa_sigaction = sighandler_setxid; + sa.sa_flags = SA_SIGINFO | SA_RESTART; + + (void) __libc_sigaction (SIGSETXID, &sa, NULL); + /* The parent process might have left the signal blocked. Just in case, unblock it. We reuse the signal mask in the sigaction structure. It is already cleared. */ diff --git a/nptl/pt-allocrtsig.c b/nptl/pt-allocrtsig.c index 3598dbb49f..9481e15f25 100644 --- a/nptl/pt-allocrtsig.c +++ b/nptl/pt-allocrtsig.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -27,8 +27,9 @@ extern int __libc_current_sigrtmax_private (void); extern int __libc_allocate_rtsig_private (int high); -/* We reserve __SIGRTMIN for use as the cancelation signal. This - signal is used internally. */ +/* We reserve __SIGRTMIN for use as the cancellation signal and + __SIGRTMIN+1 to andle setuid et.al. These signals are used + internally. */ int __libc_current_sigrtmin (void) { diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index c0941f0cf5..1fedce5f3a 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -206,6 +206,13 @@ __do_cancel (void) #define SIGTIMER SIGCANCEL +/* Signal used to implement the setuid et.al. functions. */ +#define SIGSETXID (__SIGRTMIN + 1) + +/* Used to communicate with signal handler. */ +extern struct xid_command *__xidcmd attribute_hidden; + + /* Internal prototypes. */ /* Thread list handling. */ @@ -441,4 +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; + #endif /* pthreadP.h */ diff --git a/nptl/pthread_setegid.c b/nptl/pthread_setegid.c new file mode 100644 index 0000000000..9252dfac7d --- /dev/null +++ b/nptl/pthread_setegid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define setegid pthread_setegid_np +#include <setegid.c> diff --git a/nptl/pthread_seteuid.c b/nptl/pthread_seteuid.c new file mode 100644 index 0000000000..47bb698025 --- /dev/null +++ b/nptl/pthread_seteuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define seteuid pthread_seteuid_np +#include <seteuid.c> diff --git a/nptl/pthread_setgid.c b/nptl/pthread_setgid.c new file mode 100644 index 0000000000..b06bffbf32 --- /dev/null +++ b/nptl/pthread_setgid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setgid pthread_setgid_np +#include <setgid.c> diff --git a/nptl/pthread_setregid.c b/nptl/pthread_setregid.c new file mode 100644 index 0000000000..7461d2b7fd --- /dev/null +++ b/nptl/pthread_setregid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setregid pthread_setregid_np +#include <setregid.c> diff --git a/nptl/pthread_setresgid.c b/nptl/pthread_setresgid.c new file mode 100644 index 0000000000..369fae2672 --- /dev/null +++ b/nptl/pthread_setresgid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setresgid pthread_setresgid_np +#include <setresgid.c> diff --git a/nptl/pthread_setresuid.c b/nptl/pthread_setresuid.c new file mode 100644 index 0000000000..ac57c0fa8d --- /dev/null +++ b/nptl/pthread_setresuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setresuid pthread_setresuid_np +#include <setresuid.c> diff --git a/nptl/pthread_setreuid.c b/nptl/pthread_setreuid.c new file mode 100644 index 0000000000..aa804ab01d --- /dev/null +++ b/nptl/pthread_setreuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setreuid pthread_setreuid_np +#include <setreuid.c> diff --git a/nptl/pthread_setuid.c b/nptl/pthread_setuid.c new file mode 100644 index 0000000000..ff949c850f --- /dev/null +++ b/nptl/pthread_setuid.c @@ -0,0 +1,3 @@ +#define SINGLE_THREAD +#define __setuid pthread_setuid_np +#include <setuid.c> diff --git a/nptl/sysdeps/pthread/pthread-functions.h b/nptl/sysdeps/pthread/pthread-functions.h index 23af214518..b1e0fcb26d 100644 --- a/nptl/sysdeps/pthread/pthread-functions.h +++ b/nptl/sysdeps/pthread/pthread-functions.h @@ -93,6 +93,8 @@ 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 *); }; /* Variable in libc.so. */ diff --git a/nptl/sysdeps/pthread/pthread.h b/nptl/sysdeps/pthread/pthread.h index 27666483d9..16f02d1314 100644 --- a/nptl/sysdeps/pthread/pthread.h +++ b/nptl/sysdeps/pthread/pthread.h @@ -953,6 +953,36 @@ extern int pthread_atfork (void (*__prepare) (void), void (*__parent) (void), void (*__child) (void)) __THROW; + +#ifdef __USE_GNU +/* Change UID of calling thread. */ +extern int pthread_setuid_np (__uid_t __uid) __THROW; + +/* Change effective UID of calling thread. */ +extern int pthread_seteuid_np (__uid_t __uid) __THROW; + +/* Change real and effective UID of calling thread. */ +extern int pthread_setreuid_np (__uid_t __ruid, __uid_t __euid) __THROW; + +/* Change real, effective, and saved UID of calling thread. */ +extern int pthread_setresuid_np (__uid_t __ruid, __uid_t __euid, + __uid_t __suid) __THROW; + + +/* Change GID of calling thread. */ +extern int pthread_setgid_np (__gid_t __gid) __THROW; + +/* Change effective GID of calling thread. */ +extern int pthread_setegid_np (__gid_t __gid) __THROW; + +/* Change real and effective GID of calling thread. */ +extern int pthread_setregid_np (__gid_t __rgid, __gid_t __egid) __THROW; + +/* Change real, effective, and saved GID of calling thread. */ +extern int pthread_setresgid_np (__gid_t __rgid, __gid_t __egid, + __gid_t __sgid) __THROW; +#endif + __END_DECLS #endif /* pthread.h */ diff --git a/nptl/sysdeps/unix/sysv/linux/allocrtsig.c b/nptl/sysdeps/unix/sysv/linux/allocrtsig.c index 51aeb22765..b37d54d65b 100644 --- a/nptl/sysdeps/unix/sysv/linux/allocrtsig.c +++ b/nptl/sysdeps/unix/sysv/linux/allocrtsig.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -20,7 +20,7 @@ #include <signal.h> -static int current_rtmin = __SIGRTMIN + 1; +static int current_rtmin = __SIGRTMIN + 2; static int current_rtmax = __SIGRTMAX; |