https://git.reactos.org/?p=reactos.git;a=commitdiff;h=242efae9a22cabf961a92…
commit 242efae9a22cabf961a92785de4dde842862d388
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Mon Apr 12 14:42:52 2021 +0200
Commit: George Bișoc <george.bisoc(a)reactos.org>
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);