[NTOSKRNL] On process primary token change, dereference device map
[reactos.git] / ntoskrnl / ps / security.c
index 45ec74d..619ff56 100644 (file)
@@ -86,7 +86,7 @@ PspInitializeProcessSecurity(IN PEPROCESS Process,
         Status = SeSubProcessToken(ParentToken,
                                    &NewToken,
                                    TRUE,
-                                   0);//MmGetSessionId(Process));
+                                   MmGetSessionId(Process));
 
         /* Dereference the Parent */
         ObFastDereferenceObject(&Parent->Token, ParentToken);
@@ -190,7 +190,7 @@ PspAssignPrimaryToken(IN PEPROCESS Process,
         /* Reference it from the handle */
         Status = ObReferenceObjectByHandle(Token,
                                            TOKEN_ASSIGN_PRIMARY,
-                                           SepTokenObjectType,
+                                           SeTokenObjectType,
                                            ExGetPreviousMode(),
                                            &NewToken,
                                            NULL);
@@ -206,7 +206,7 @@ PspAssignPrimaryToken(IN PEPROCESS Process,
 
     /* Dereference Tokens and Return */
     if (NT_SUCCESS(Status)) ObDereferenceObject(OldToken);
-    if (AccessToken) ObDereferenceObject(NewToken);
+    if (!AccessToken) ObDereferenceObject(NewToken);
     return Status;
 }
 
@@ -217,45 +217,59 @@ PspSetPrimaryToken(IN PEPROCESS Process,
                    IN PACCESS_TOKEN Token OPTIONAL)
 {
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-    BOOLEAN IsChild;
+    BOOLEAN IsChildOrSibling;
     PACCESS_TOKEN NewToken = Token;
     NTSTATUS Status, AccessStatus;
     BOOLEAN Result, SdAllocated;
-    PSECURITY_DESCRIPTOR SecurityDescriptor;
+    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
     SECURITY_SUBJECT_CONTEXT SubjectContext;
+
     PSTRACE(PS_SECURITY_DEBUG, "Process: %p Token: %p\n", Process, Token);
 
-    /* Make sure we got a handle */
-    if (TokenHandle)
+    /* Reference the token by handle if we don't already have a token object */
+    if (!Token)
     {
-        /* Reference it */
         Status = ObReferenceObjectByHandle(TokenHandle,
                                            TOKEN_ASSIGN_PRIMARY,
-                                           SepTokenObjectType,
+                                           SeTokenObjectType,
                                            PreviousMode,
                                            (PVOID*)&NewToken,
                                            NULL);
         if (!NT_SUCCESS(Status)) return Status;
     }
 
-    /* Check if this is a child */
-    Status = SeIsTokenChild(NewToken, &IsChild);
+    /*
+     * Check whether this token is a child or sibling of the current process token.
+     * NOTE: On Windows Vista+ both of these checks (together with extra steps)
+     * are now performed by a new SeIsTokenAssignableToProcess() helper.
+     */
+    Status = SeIsTokenChild(NewToken, &IsChildOrSibling);
     if (!NT_SUCCESS(Status))
     {
         /* Failed, dereference */
-        if (TokenHandle) ObDereferenceObject(NewToken);
+        if (!Token) ObDereferenceObject(NewToken);
         return Status;
     }
+    if (!IsChildOrSibling)
+    {
+        Status = SeIsTokenSibling(NewToken, &IsChildOrSibling);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Failed, dereference */
+            if (!Token) ObDereferenceObject(NewToken);
+            return Status;
+        }
+    }
 
     /* Check if this was an independent token */
-    if (!IsChild)
+    if (!IsChildOrSibling)
     {
         /* Make sure we have the privilege to assign a new one */
         if (!SeSinglePrivilegeCheck(SeAssignPrimaryTokenPrivilege,
                                     PreviousMode))
         {
             /* Failed, dereference */
-            if (TokenHandle) ObDereferenceObject(NewToken);
+            if (!Token) ObDereferenceObject(NewToken);
             return STATUS_PRIVILEGE_NOT_HELD;
         }
     }
@@ -311,10 +325,18 @@ PspSetPrimaryToken(IN PEPROCESS Process,
                                        STANDARD_RIGHTS_ALL |
                                        PROCESS_SET_QUOTA);
         }
+
+        /*
+         * In case LUID device maps are enable, we may not be using
+         * system device map for this process, but a logon LUID based
+         * device map. Because we change primary token, this usage is
+         * no longer valid, so dereference the process device map
+         */
+        if (ObIsLUIDDeviceMapsEnabled()) ObDereferenceDeviceMap(Process);
     }
 
     /* Dereference the token */
-    if (TokenHandle) ObDereferenceObject(NewToken);
+    if (!Token) ObDereferenceObject(NewToken);
     return Status;
 }
 
@@ -349,7 +371,7 @@ NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
     PACCESS_TOKEN Token;
     HANDLE hToken;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status;
     PAGED_CODE();
     PSTRACE(PS_SECURITY_DEBUG,
             "Process: %p DesiredAccess: %lx\n", ProcessHandle, DesiredAccess);
@@ -358,22 +380,22 @@ NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
     if (PreviousMode != KernelMode)
     {
         /* Enter SEH for probing */
-        _SEH_TRY
+        _SEH2_TRY
         {
             /* Probe the token handle */
             ProbeForWriteHandle(TokenHandle);
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            /* Get the exception code */
-            Status = _SEH_GetExceptionCode();
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
-        _SEH_END;
-
-        /* Fail on exception */
-        if (!NT_SUCCESS(Status)) return Status;
+        _SEH2_END;
     }
 
+    /* Validate object attributes */
+    HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
+
     /* Open the process token */
     Status = PsOpenTokenOfProcess(ProcessHandle, &Token);
     if (NT_SUCCESS(Status))
@@ -383,7 +405,7 @@ NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
                                        HandleAttributes,
                                        NULL,
                                        DesiredAccess,
-                                       SepTokenObjectType,
+                                       SeTokenObjectType,
                                        PreviousMode,
                                        &hToken);
         ObDereferenceObject(Token);
@@ -392,17 +414,17 @@ NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
         if (NT_SUCCESS(Status))
         {
             /* Enter SEH for write */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Return the handle */
                 *TokenHandle = hToken;
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
         }
     }
 
@@ -497,7 +519,7 @@ PsAssignImpersonationToken(IN PETHREAD Thread,
     /* Get the token object */
     Status = ObReferenceObjectByHandle(TokenHandle,
                                        TOKEN_IMPERSONATE,
-                                       SepTokenObjectType,
+                                       SeTokenObjectType,
                                        KeGetPreviousMode(),
                                        (PVOID*)&Token,
                                        NULL);
@@ -634,14 +656,14 @@ PsImpersonateClient(IN PETHREAD Thread,
             if (!Impersonation) return STATUS_INSUFFICIENT_RESOURCES;
 
             /* Update the pointer */
-            OldData = InterlockedCompareExchangePointer(&Thread->
+            OldData = InterlockedCompareExchangePointer((PVOID*)&Thread->
                                                         ImpersonationInfo,
                                                         Impersonation,
                                                         NULL);
             if (OldData)
             {
                 /* Someone beat us to it, free our copy */
-                ExFreePool(Impersonation);
+                ExFreePoolWithTag(Impersonation, TAG_PS_IMPERSONATION);
                 Impersonation = OldData;
             }
         }
@@ -691,35 +713,19 @@ NTAPI
 PsReferenceEffectiveToken(IN PETHREAD Thread,
                           OUT IN PTOKEN_TYPE TokenType,
                           OUT PBOOLEAN EffectiveOnly,
-                          OUT PSECURITY_IMPERSONATION_LEVEL Level)
+                          OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
 {
     PEPROCESS Process;
     PACCESS_TOKEN Token = NULL;
+
     PAGED_CODE();
+
     PSTRACE(PS_SECURITY_DEBUG,
             "Thread: %p, TokenType: %p\n", Thread, TokenType);
 
     /* Check if we don't have impersonation info */
     Process = Thread->ThreadsProcess;
-    if (!Thread->ActiveImpersonationInfo)
-    {
-        /* Fast Reference the Token */
-        Token = ObFastReferenceObject(&Process->Token);
-
-        /* Check if we got the Token or if we got locked */
-        if (!Token)
-        {
-            /* Lock the Process */
-            PspLockProcessSecurityShared(Process);
-
-            /* Do a Locked Fast Reference */
-            Token = ObFastReferenceObjectLocked(&Process->Token);
-
-            /* Unlock the Process */
-            PspUnlockProcessSecurityShared(Process);
-        }
-    }
-    else
+    if (Thread->ActiveImpersonationInfo)
     {
         /* Lock the Process */
         PspLockProcessSecurityShared(Process);
@@ -734,7 +740,7 @@ PsReferenceEffectiveToken(IN PETHREAD Thread,
             /* Return data to caller */
             *TokenType = TokenImpersonation;
             *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
-            *Level = Thread->ImpersonationInfo->ImpersonationLevel;
+            *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
 
             /* Unlock the Process */
             PspUnlockProcessSecurityShared(Process);
@@ -745,9 +751,26 @@ PsReferenceEffectiveToken(IN PETHREAD Thread,
         PspUnlockProcessSecurityShared(Process);
     }
 
+    /* Fast Reference the Token */
+    Token = ObFastReferenceObject(&Process->Token);
+
+    /* Check if we got the Token or if we got locked */
+    if (!Token)
+    {
+        /* Lock the Process */
+        PspLockProcessSecurityShared(Process);
+
+        /* Do a Locked Fast Reference */
+        Token = ObFastReferenceObjectLocked(&Process->Token);
+
+        /* Unlock the Process */
+        PspUnlockProcessSecurityShared(Process);
+    }
+
     /* Return the token */
     *TokenType = TokenPrimary;
     *EffectiveOnly = FALSE;
+    // NOTE: ImpersonationLevel is left untouched on purpose!
     return Token;
 }
 
@@ -823,10 +846,10 @@ PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)
 BOOLEAN
 NTAPI
 PsDisableImpersonation(IN PETHREAD Thread,
-                       IN PSE_IMPERSONATION_STATE ImpersonationState)
+                       OUT PSE_IMPERSONATION_STATE ImpersonationState)
 {
     PPS_IMPERSONATION_INFORMATION Impersonation = NULL;
-    LONG NewValue, OldValue;
+    LONG OldFlags;
     PAGED_CODE();
     PSTRACE(PS_SECURITY_DEBUG,
             "Thread: %p State: %p\n", Thread, ImpersonationState);
@@ -838,19 +861,11 @@ PsDisableImpersonation(IN PETHREAD Thread,
         PspLockThreadSecurityExclusive(Thread);
 
         /* Disable impersonation */
-        OldValue = Thread->CrossThreadFlags;
-        do
-        {
-            /* Attempt to change the flag */
-            NewValue =
-                InterlockedCompareExchange((PLONG)&Thread->CrossThreadFlags,
-                                           OldValue &~
-                                           CT_ACTIVE_IMPERSONATION_INFO_BIT,
-                                           OldValue);
-        } while (NewValue != OldValue);
+        OldFlags = PspClearCrossThreadFlag(Thread,
+                                           CT_ACTIVE_IMPERSONATION_INFO_BIT);
 
         /* Make sure nobody disabled it behind our back */
-        if (NewValue & CT_ACTIVE_IMPERSONATION_INFO_BIT)
+        if (OldFlags & CT_ACTIVE_IMPERSONATION_INFO_BIT)
         {
             /* Copy the old state */
             Impersonation = Thread->ImpersonationInfo;
@@ -938,7 +953,7 @@ NtImpersonateThread(IN HANDLE ThreadHandle,
     PETHREAD Thread;
     PETHREAD ThreadToImpersonate;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status;
     PAGED_CODE();
     PSTRACE(PS_SECURITY_DEBUG,
             "Threads: %p %p\n", ThreadHandle, ThreadToImpersonateHandle);
@@ -947,7 +962,7 @@ NtImpersonateThread(IN HANDLE ThreadHandle,
     if (PreviousMode != KernelMode)
     {
         /* Enter SEH for probing */
-        _SEH_TRY
+        _SEH2_TRY
         {
             /* Probe QoS */
             ProbeForRead(SecurityQualityOfService,
@@ -958,45 +973,42 @@ NtImpersonateThread(IN HANDLE ThreadHandle,
             SafeServiceQoS = *SecurityQualityOfService;
             SecurityQualityOfService = &SafeServiceQoS;
         }
-        _SEH_HANDLE
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            /* Get exception status */
-            Status = _SEH_GetExceptionCode();
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
         }
-        _SEH_END;
-
-        /* Fail on exception */
-        if (!NT_SUCCESS(Status)) return Status;
+        _SEH2_END;
     }
 
     /* Reference the thread */
     Status = ObReferenceObjectByHandle(ThreadHandle,
-                                       THREAD_IMPERSONATE,
+                                       THREAD_DIRECT_IMPERSONATION,
                                        PsThreadType,
                                        PreviousMode,
                                        (PVOID*)&Thread,
                                        NULL);
-    if(NT_SUCCESS(Status))
+    if (NT_SUCCESS(Status))
     {
         /* Reference the impersonating thead */
         Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
-                                           THREAD_DIRECT_IMPERSONATION,
+                                           THREAD_IMPERSONATE,
                                            PsThreadType,
                                            PreviousMode,
                                            (PVOID*)&ThreadToImpersonate,
                                            NULL);
-        if(NT_SUCCESS(Status))
+        if (NT_SUCCESS(Status))
         {
             /* Create a client security context */
             Status = SeCreateClientSecurity(ThreadToImpersonate,
                                             SecurityQualityOfService,
                                             0,
                                             &ClientContext);
-            if(NT_SUCCESS(Status))
+            if (NT_SUCCESS(Status))
             {
                 /* Do the impersonation */
                 SeImpersonateClient(&ClientContext, Thread);
-                if(ClientContext.ClientToken)
+                if (ClientContext.ClientToken)
                 {
                     /* Dereference the client token if we had one */
                     ObDereferenceObject(ClientContext.ClientToken);