https://git.reactos.org/?p=reactos.git;a=commitdiff;h=242efae9a22cabf961a92785de4dde842862d388

commit 242efae9a22cabf961a92785de4dde842862d388
Author:     George Bișoc <[email protected]>
AuthorDate: Mon Apr 12 14:42:52 2021 +0200
Commit:     George Bișoc <[email protected]>
CommitDate: Sun May 2 16:55:20 2021 +0200

    [NTOS:PS] Make sure we can impersonate the given token first
    
    PsImpersonateClient blindly impersonates the requested client even though 
it doesn't know if the actual token given to the call can be impersonated for 
the thread of the client which we are going to begin impersonation. In the case 
where impersonation is not possible, make a copy of the given token and assign 
the newly one for impersonation instead.
    CORE-17539
---
 ntoskrnl/ps/security.c | 53 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 47 insertions(+), 6 deletions(-)

diff --git a/ntoskrnl/ps/security.c b/ntoskrnl/ps/security.c
index 0b3f97fbf06..23145529743 100644
--- a/ntoskrnl/ps/security.c
+++ b/ntoskrnl/ps/security.c
@@ -614,8 +614,10 @@ PsImpersonateClient(IN PETHREAD Thread,
                     IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
 {
     PPS_IMPERSONATION_INFORMATION Impersonation, OldData;
-    PTOKEN OldToken = NULL;
+    PTOKEN OldToken = NULL, ProcessToken = NULL;
+    PACCESS_TOKEN NewToken, ImpersonationToken;
     PEJOB Job;
+    NTSTATUS Status;
 
     PAGED_CODE();
     PSTRACE(PS_SECURITY_DEBUG, "Thread: %p, Token: %p\n", Thread, Token);
@@ -670,7 +672,46 @@ PsImpersonateClient(IN PETHREAD Thread,
             }
         }
 
-        /* FIXME: If the process token can't impersonate, we need to make a 
copy instead */
+        /*
+         * Assign the token we get from the caller first. The reason
+         * we have to do that is because we're unsure if we can impersonate
+         * in the first place. In the scenario where we cannot then the
+         * last resort is to make a copy of the token and assign that newly
+         * token to the impersonation information.
+         */
+        ImpersonationToken = Token;
+
+        /* Obtain a token from the process */
+        ProcessToken = PsReferencePrimaryToken(Thread->ThreadsProcess);
+        if (!ProcessToken)
+        {
+            /* We can't continue this way without having the process' token... 
*/
+            return STATUS_UNSUCCESSFUL;
+        }
+
+        /* Make sure we can impersonate */
+        if (!SeTokenCanImpersonate(ProcessToken,
+                                   Token,
+                                   ImpersonationLevel))
+        {
+            /* We can't, make a copy of the token instead */
+            Status = SeCopyClientToken(Token,
+                                       SecurityIdentification,
+                                       KernelMode,
+                                       &NewToken);
+            if (!NT_SUCCESS(Status))
+            {
+                /* We can't even make a copy of the token? Then bail out... */
+                ObFastDereferenceObject(&Thread->ThreadsProcess->Token, 
ProcessToken);
+                return Status;
+            }
+
+            /* Since we cannot impersonate, assign the newly copied token */
+            ImpersonationToken = NewToken;
+        }
+
+        /* We no longer need the process' token */
+        ObFastDereferenceObject(&Thread->ThreadsProcess->Token, ProcessToken);
 
         /* Check if this is a job */
         Job = Thread->ThreadsProcess->Job;
@@ -678,14 +719,14 @@ PsImpersonateClient(IN PETHREAD Thread,
         {
             /* No admin allowed in this job */
             if ((Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_NO_ADMIN) &&
-                SeTokenIsAdmin(Token))
+                SeTokenIsAdmin(ImpersonationToken))
             {
                 return STATUS_ACCESS_DENIED;
             }
 
             /* No restricted tokens allowed in this job */
             if ((Job->SecurityLimitFlags & 
JOB_OBJECT_SECURITY_RESTRICTED_TOKEN) &&
-                SeTokenIsRestricted(Token))
+                SeTokenIsRestricted(ImpersonationToken))
             {
                 return STATUS_ACCESS_DENIED;
             }
@@ -716,8 +757,8 @@ PsImpersonateClient(IN PETHREAD Thread,
         Impersonation->ImpersonationLevel = ImpersonationLevel;
         Impersonation->CopyOnOpen = CopyOnOpen;
         Impersonation->EffectiveOnly = EffectiveOnly;
-        Impersonation->Token = Token;
-        ObReferenceObject(Token);
+        Impersonation->Token = ImpersonationToken;
+        ObReferenceObject(ImpersonationToken);
 
         /* Unlock the thread */
         PspUnlockThreadSecurityExclusive(Thread);

Reply via email to