about summary refs log tree commit diff
path: root/nptl
diff options
context:
space:
mode:
Diffstat (limited to 'nptl')
-rw-r--r--nptl/ChangeLog34
-rw-r--r--nptl/Makefile6
-rw-r--r--nptl/Versions5
-rw-r--r--nptl/allocatestack.c81
-rw-r--r--nptl/descr.h10
-rw-r--r--nptl/init.c40
-rw-r--r--nptl/pt-allocrtsig.c7
-rw-r--r--nptl/pthreadP.h9
-rw-r--r--nptl/pthread_setegid.c3
-rw-r--r--nptl/pthread_seteuid.c3
-rw-r--r--nptl/pthread_setgid.c3
-rw-r--r--nptl/pthread_setregid.c3
-rw-r--r--nptl/pthread_setresgid.c3
-rw-r--r--nptl/pthread_setresuid.c3
-rw-r--r--nptl/pthread_setreuid.c3
-rw-r--r--nptl/pthread_setuid.c3
-rw-r--r--nptl/sysdeps/pthread/pthread-functions.h2
-rw-r--r--nptl/sysdeps/pthread/pthread.h30
-rw-r--r--nptl/sysdeps/unix/sysv/linux/allocrtsig.c4
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;