123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- /*++
- Copyright (c) 2015 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- setids.c
- Abstract:
- This module implements the logic to make setuid and friends calls work
- across all threads.
- Author:
- Evan Green 1-May-2015
- Environment:
- User Mode C Library
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "pthreadp.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the amount of time to wait for a set ID request to go through, in
- // seconds.
- //
- #define PTHREAD_SETID_TIMEOUT 60
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure stores details for a setuid (and friends) request.
- Members:
- SetGroups - Stores a boolean indicating if this is a set supplementary
- groups call (TRUE) or a set thread identity call.
- Fields - Stores the fields to set in the thread identity.
- Identity - Stores a pointer to the thread identity to set.
- Groups - Stores a pointer to an array of supplementary group IDs to set.
- GroupCount - Stores the number of elements in the supplementary group ID
- array.
- Thread - Stores the thread the request is directed to.
- Mutex - Stores the mutex guarding the condition.
- Condition - Stores the condition variable.
- --*/
- typedef struct _PTHREAD_SETID_REQUEST {
- BOOL SetGroups;
- ULONG Fields;
- PTHREAD_IDENTITY Identity;
- PGROUP_ID Groups;
- UINTN GroupCount;
- pthread_t Thread;
- pthread_mutex_t Mutex;
- pthread_cond_t Condition;
- } PTHREAD_SETID_REQUEST, *PPTHREAD_SETID_REQUEST;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- ClpExecuteSetIdRequest (
- PPTHREAD_SETID_REQUEST Request
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PPTHREAD_SETID_REQUEST ClSetIdRequest;
- //
- // ------------------------------------------------------------------ Functions
- //
- VOID
- ClpSetThreadIdentityOnAllThreads (
- ULONG Fields,
- PTHREAD_IDENTITY Identity
- )
- /*++
- Routine Description:
- This routine uses a signal to set the thread identity on all threads
- except the current one (which is assumed to have already been set).
- Arguments:
- Fields - Supplies the bitfield of identity fields to set. See
- THREAD_IDENTITY_FIELD_* definitions.
- Identity - Supplies a pointer to the thread identity information to set.
- Return Value:
- None.
- --*/
- {
- PTHREAD_SETID_REQUEST Request;
- //
- // If threading's not been fired up, nothing needs to be done.
- //
- if (ClThreadList.Next == NULL) {
- return;
- }
- RtlZeroMemory(&Request, sizeof(PTHREAD_SETID_REQUEST));
- Request.SetGroups = FALSE;
- Request.Fields = Fields;
- Request.Identity = Identity;
- ClpExecuteSetIdRequest(&Request);
- return;
- }
- VOID
- ClpSetSupplementaryGroupsOnAllThreads (
- PGROUP_ID GroupIds,
- UINTN GroupIdCount
- )
- /*++
- Routine Description:
- This routine uses a signal to set the supplementary groups on all threads
- except the current one (which is assumed to have already been set).
- Arguments:
- GroupIds - Supplies a pointer to the array of group IDs to set.
- GroupIdCount - Supplies the number of elements in the group ID array.
- Return Value:
- None.
- --*/
- {
- PTHREAD_SETID_REQUEST Request;
- //
- // If threading's not been fired up, nothing needs to be done.
- //
- if (ClThreadList.Next == NULL) {
- return;
- }
- RtlZeroMemory(&Request, sizeof(PTHREAD_SETID_REQUEST));
- Request.SetGroups = TRUE;
- Request.Groups = GroupIds;
- Request.GroupCount = GroupIdCount;
- ClpExecuteSetIdRequest(&Request);
- return;
- }
- void
- ClpSetIdSignalHandler (
- int Signal
- )
- /*++
- Routine Description:
- This routine is a signal handler called to fix up the user identity on a
- thread.
- Arguments:
- Signal - Supplies the signal that caused this handler to be invoked.
- Return Value:
- None.
- --*/
- {
- PPTHREAD_SETID_REQUEST Request;
- Request = ClSetIdRequest;
- //
- // Ignore spurious requests. Note that this is not foolproof, as the
- // request might be set now but be destroyed in just a moment if a request
- // is not actually going through.
- //
- if ((Request == NULL) || (Request->Thread != pthread_self())) {
- abort();
- }
- if (Request->SetGroups != FALSE) {
- OsSetSupplementaryGroups(TRUE, Request->Groups, &(Request->GroupCount));
- } else {
- OsSetThreadIdentity(Request->Fields, Request->Identity);
- }
- pthread_mutex_lock(&(Request->Mutex));
- Request->Thread = 0;
- pthread_cond_signal(&(Request->Condition));
- pthread_mutex_unlock(&(Request->Mutex));
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- ClpExecuteSetIdRequest (
- PPTHREAD_SETID_REQUEST Request
- )
- /*++
- Routine Description:
- This routine uses a signal to set the thread identity on all threads
- except the current one (which is assumed to have already been set).
- Arguments:
- Request - Supplies a pointer to the request to execute.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- KSTATUS KernelStatus;
- PPTHREAD Self;
- int Status;
- PPTHREAD Thread;
- struct timespec Timeout;
- pthread_mutex_init(&(Request->Mutex), NULL);
- pthread_mutex_lock(&(Request->Mutex));
- Self = (PPTHREAD)pthread_self();
- pthread_mutex_lock(&ClThreadListMutex);
- ClSetIdRequest = Request;
- CurrentEntry = ClThreadList.Next;
- while (CurrentEntry != &ClThreadList) {
- Thread = LIST_VALUE(CurrentEntry, PTHREAD, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (Thread == Self) {
- continue;
- }
- Request->Thread = (pthread_t)Thread;
- //
- // Fire off the request. Allow for the possibility that the thread has
- // died, which is okay.
- //
- KernelStatus = OsSendSignal(SignalTargetThread,
- Thread->ThreadId,
- SIGNAL_SETID,
- SIGNAL_CODE_USER,
- 0);
- if (KernelStatus == STATUS_NO_SUCH_THREAD) {
- continue;
- }
- if (!KSUCCESS(KernelStatus)) {
- fprintf(stderr,
- "Error: Failed to signal thread %x: %d\n",
- Thread,
- KernelStatus);
- abort();
- }
- clock_gettime(CLOCK_REALTIME_COARSE, &Timeout);
- Timeout.tv_sec += PTHREAD_SETID_TIMEOUT;
- while (Request->Thread == (pthread_t)Thread) {
- Status = pthread_cond_timedwait(&(Request->Condition),
- &(Request->Mutex),
- &Timeout);
- if (Status == ETIMEDOUT) {
- fprintf(stderr,
- "Error: Thread %x failed to respond to set ID "
- "request.\n",
- Thread);
- abort();
- }
- }
- }
- ClSetIdRequest = NULL;
- pthread_mutex_unlock(&ClThreadListMutex);
- pthread_mutex_unlock(&(Request->Mutex));
- pthread_mutex_destroy(&(Request->Mutex));
- return;
- }
|