securely access buffers in NtImpersonateThread()
[reactos.git] / reactos / ntoskrnl / ps / create.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/create.c
6 * PURPOSE: Thread managment
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 * Phillip Susi
10 * Skywing
11 */
12
13 /*
14 * NOTE:
15 *
16 * All of the routines that manipulate the thread queue synchronize on
17 * a single spinlock
18 *
19 */
20
21 /* INCLUDES ****************************************************************/
22
23 #include <ntoskrnl.h>
24 #define NDEBUG
25 #include <internal/debug.h>
26
27 /* GLOBAL *******************************************************************/
28
29 #define MAX_THREAD_NOTIFY_ROUTINE_COUNT 8
30
31 static ULONG PiThreadNotifyRoutineCount = 0;
32 static PCREATE_THREAD_NOTIFY_ROUTINE
33 PiThreadNotifyRoutine[MAX_THREAD_NOTIFY_ROUTINE_COUNT];
34
35 /* FUNCTIONS ***************************************************************/
36
37 /*
38 * @implemented
39 */
40 NTSTATUS STDCALL
41 PsAssignImpersonationToken(PETHREAD Thread,
42 HANDLE TokenHandle)
43 {
44 PACCESS_TOKEN Token;
45 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
46 NTSTATUS Status;
47
48 if (TokenHandle != NULL)
49 {
50 Status = ObReferenceObjectByHandle(TokenHandle,
51 TOKEN_IMPERSONATE,
52 SepTokenObjectType,
53 KeGetPreviousMode(),
54 (PVOID*)&Token,
55 NULL);
56 if (!NT_SUCCESS(Status))
57 {
58 return(Status);
59 }
60 ImpersonationLevel = SeTokenImpersonationLevel(Token);
61 }
62 else
63 {
64 Token = NULL;
65 ImpersonationLevel = 0;
66 }
67
68 PsImpersonateClient(Thread,
69 Token,
70 FALSE,
71 FALSE,
72 ImpersonationLevel);
73 if (Token != NULL)
74 {
75 ObDereferenceObject(Token);
76 }
77
78 return(STATUS_SUCCESS);
79 }
80
81
82 /*
83 * @implemented
84 */
85 VOID STDCALL
86 PsRevertToSelf (VOID)
87 {
88 PsRevertThreadToSelf(PsGetCurrentThread());
89 }
90
91 /*
92 * @implemented
93 */
94 VOID
95 STDCALL
96 PsRevertThreadToSelf(
97 IN PETHREAD Thread
98 )
99 {
100 if (Thread->ActiveImpersonationInfo == TRUE)
101 {
102 ObDereferenceObject (Thread->ImpersonationInfo->Token);
103 Thread->ActiveImpersonationInfo = FALSE;
104 }
105 }
106
107 /*
108 * @implemented
109 */
110 VOID STDCALL
111 PsImpersonateClient (IN PETHREAD Thread,
112 IN PACCESS_TOKEN Token,
113 IN BOOLEAN CopyOnOpen,
114 IN BOOLEAN EffectiveOnly,
115 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
116 {
117 if (Token == NULL)
118 {
119 if (Thread->ActiveImpersonationInfo == TRUE)
120 {
121 Thread->ActiveImpersonationInfo = FALSE;
122 if (Thread->ImpersonationInfo->Token != NULL)
123 {
124 ObDereferenceObject (Thread->ImpersonationInfo->Token);
125 }
126 }
127 return;
128 }
129
130 if (Thread->ImpersonationInfo == NULL)
131 {
132 Thread->ImpersonationInfo = ExAllocatePool (NonPagedPool,
133 sizeof(PS_IMPERSONATION_INFORMATION));
134 }
135
136 Thread->ImpersonationInfo->ImpersonationLevel = ImpersonationLevel;
137 Thread->ImpersonationInfo->CopyOnOpen = CopyOnOpen;
138 Thread->ImpersonationInfo->EffectiveOnly = EffectiveOnly;
139 Thread->ImpersonationInfo->Token = Token;
140 ObReferenceObjectByPointer (Token,
141 0,
142 SepTokenObjectType,
143 KernelMode);
144 Thread->ActiveImpersonationInfo = TRUE;
145 }
146
147
148 PACCESS_TOKEN
149 PsReferenceEffectiveToken(PETHREAD Thread,
150 PTOKEN_TYPE TokenType,
151 PBOOLEAN EffectiveOnly,
152 PSECURITY_IMPERSONATION_LEVEL Level)
153 {
154 PEPROCESS Process;
155 PACCESS_TOKEN Token;
156
157 if (Thread->ActiveImpersonationInfo == FALSE)
158 {
159 Process = Thread->ThreadsProcess;
160 *TokenType = TokenPrimary;
161 *EffectiveOnly = FALSE;
162 Token = Process->Token;
163 }
164 else
165 {
166 Token = Thread->ImpersonationInfo->Token;
167 *TokenType = TokenImpersonation;
168 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
169 *Level = Thread->ImpersonationInfo->ImpersonationLevel;
170 }
171 return(Token);
172 }
173
174
175 NTSTATUS STDCALL
176 NtImpersonateThread(IN HANDLE ThreadHandle,
177 IN HANDLE ThreadToImpersonateHandle,
178 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
179 {
180 SECURITY_QUALITY_OF_SERVICE SafeServiceQoS;
181 SECURITY_CLIENT_CONTEXT ClientContext;
182 PETHREAD Thread;
183 PETHREAD ThreadToImpersonate;
184 KPROCESSOR_MODE PreviousMode;
185 NTSTATUS Status = STATUS_SUCCESS;
186
187 PreviousMode = ExGetPreviousMode();
188
189 if(PreviousMode != KernelMode)
190 {
191 _SEH_TRY
192 {
193 ProbeForRead(SecurityQualityOfService,
194 sizeof(SECURITY_QUALITY_OF_SERVICE),
195 sizeof(ULONG));
196 SafeServiceQoS = *SecurityQualityOfService;
197 SecurityQualityOfService = &SafeServiceQoS;
198 }
199 _SEH_HANDLE
200 {
201 Status = _SEH_GetExceptionCode();
202 }
203 _SEH_END;
204
205 if(!NT_SUCCESS(Status))
206 {
207 return Status;
208 }
209 }
210
211 Status = ObReferenceObjectByHandle(ThreadHandle,
212 THREAD_IMPERSONATE,
213 PsThreadType,
214 PreviousMode,
215 (PVOID*)&Thread,
216 NULL);
217 if(NT_SUCCESS(Status))
218 {
219 Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
220 THREAD_DIRECT_IMPERSONATION,
221 PsThreadType,
222 PreviousMode,
223 (PVOID*)&ThreadToImpersonate,
224 NULL);
225 if(NT_SUCCESS(Status))
226 {
227 Status = SeCreateClientSecurity(ThreadToImpersonate,
228 SecurityQualityOfService,
229 0,
230 &ClientContext);
231 if(NT_SUCCESS(Status))
232 {
233 SeImpersonateClient(&ClientContext,
234 Thread);
235 if(ClientContext.ClientToken != NULL)
236 {
237 ObDereferenceObject (ClientContext.ClientToken);
238 }
239 }
240
241 ObDereferenceObject(ThreadToImpersonate);
242 }
243 ObDereferenceObject(Thread);
244 }
245
246 return Status;
247 }
248
249 /*
250 * @implemented
251 */
252 PACCESS_TOKEN STDCALL
253 PsReferenceImpersonationToken(IN PETHREAD Thread,
254 OUT PBOOLEAN CopyOnOpen,
255 OUT PBOOLEAN EffectiveOnly,
256 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
257 {
258 if (Thread->ActiveImpersonationInfo == FALSE)
259 {
260 return NULL;
261 }
262
263 *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
264 *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
265 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
266 ObReferenceObjectByPointer (Thread->ImpersonationInfo->Token,
267 TOKEN_ALL_ACCESS,
268 SepTokenObjectType,
269 KernelMode);
270
271 return Thread->ImpersonationInfo->Token;
272 }
273
274 #ifdef PsDereferencePrimaryToken
275 #undef PsDereferenceImpersonationToken
276 #endif
277 /*
278 * @implemented
279 */
280 VOID
281 STDCALL
282 PsDereferenceImpersonationToken(
283 IN PACCESS_TOKEN ImpersonationToken
284 )
285 {
286 if (ImpersonationToken) {
287 ObDereferenceObject(ImpersonationToken);
288 }
289 }
290
291 #ifdef PsDereferencePrimaryToken
292 #undef PsDereferencePrimaryToken
293 #endif
294 /*
295 * @implemented
296 */
297 VOID
298 STDCALL
299 PsDereferencePrimaryToken(
300 IN PACCESS_TOKEN PrimaryToken
301 )
302 {
303 ObDereferenceObject(PrimaryToken);
304 }
305
306 /*
307 * @implemented
308 */
309 BOOLEAN
310 STDCALL
311 PsDisableImpersonation(
312 IN PETHREAD Thread,
313 IN PSE_IMPERSONATION_STATE ImpersonationState
314 )
315 {
316 if (Thread->ActiveImpersonationInfo == FALSE)
317 {
318 ImpersonationState->Token = NULL;
319 ImpersonationState->CopyOnOpen = FALSE;
320 ImpersonationState->EffectiveOnly = FALSE;
321 ImpersonationState->Level = 0;
322 return TRUE;
323 }
324
325 /* FIXME */
326 /* ExfAcquirePushLockExclusive(&Thread->ThreadLock); */
327
328 Thread->ActiveImpersonationInfo = FALSE;
329 ImpersonationState->Token = Thread->ImpersonationInfo->Token;
330 ImpersonationState->CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
331 ImpersonationState->EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
332 ImpersonationState->Level = Thread->ImpersonationInfo->ImpersonationLevel;
333
334 /* FIXME */
335 /* ExfReleasePushLock(&Thread->ThreadLock); */
336
337 return TRUE;
338 }
339
340 /*
341 * @implemented
342 */
343 VOID
344 STDCALL
345 PsRestoreImpersonation(
346 IN PETHREAD Thread,
347 IN PSE_IMPERSONATION_STATE ImpersonationState
348 )
349 {
350 PsImpersonateClient(Thread, ImpersonationState->Token,
351 ImpersonationState->CopyOnOpen,
352 ImpersonationState->EffectiveOnly,
353 ImpersonationState->Level);
354 ObfDereferenceObject(ImpersonationState->Token);
355 }
356
357 VOID
358 PiBeforeBeginThread(CONTEXT c)
359 {
360 KeLowerIrql(PASSIVE_LEVEL);
361 }
362
363
364 VOID STDCALL
365 PiDeleteThread(PVOID ObjectBody)
366 {
367 PETHREAD Thread;
368 PEPROCESS Process;
369
370 Thread = (PETHREAD)ObjectBody;
371
372 DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody);
373
374 Process = Thread->ThreadsProcess;
375 Thread->ThreadsProcess = NULL;
376
377 PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType);
378
379 if(Thread->Tcb.Win32Thread != NULL)
380 {
381 /* Free the W32THREAD structure if present */
382 ExFreePool (Thread->Tcb.Win32Thread);
383 }
384
385 KeReleaseThread(ETHREAD_TO_KTHREAD(Thread));
386
387 ObDereferenceObject(Process);
388
389 DPRINT("PiDeleteThread() finished\n");
390 }
391
392
393 NTSTATUS
394 PsInitializeThread(PEPROCESS Process,
395 PETHREAD* ThreadPtr,
396 PHANDLE ThreadHandle,
397 ACCESS_MASK DesiredAccess,
398 POBJECT_ATTRIBUTES ThreadAttributes,
399 BOOLEAN First)
400 {
401 PETHREAD Thread;
402 NTSTATUS Status;
403 KIRQL oldIrql;
404
405 if (Process == NULL)
406 {
407 Process = PsInitialSystemProcess;
408 }
409
410 /*
411 * Reference process
412 */
413 ObReferenceObjectByPointer(Process,
414 PROCESS_CREATE_THREAD,
415 PsProcessType,
416 KernelMode);
417
418 /*
419 * Create and initialize thread
420 */
421 Status = ObCreateObject(UserMode,
422 PsThreadType,
423 ThreadAttributes,
424 UserMode,
425 NULL,
426 sizeof(ETHREAD),
427 0,
428 0,
429 (PVOID*)&Thread);
430 if (!NT_SUCCESS(Status))
431 {
432 ObDereferenceObject (Process);
433 return(Status);
434 }
435
436 /* create a client id handle */
437 Status = PsCreateCidHandle(Thread, PsThreadType, &Thread->Cid.UniqueThread);
438 if (!NT_SUCCESS(Status))
439 {
440 ObDereferenceObject (Thread);
441 ObDereferenceObject (Process);
442 return Status;
443 }
444 Thread->ThreadsProcess = Process;
445 Thread->Cid.UniqueProcess = (HANDLE)Thread->ThreadsProcess->UniqueProcessId;
446
447 Status = ObInsertObject ((PVOID)Thread,
448 NULL,
449 DesiredAccess,
450 0,
451 NULL,
452 ThreadHandle);
453 if (!NT_SUCCESS(Status))
454 {
455 ObDereferenceObject (Thread);
456 ObDereferenceObject (Process);
457 return Status;
458 }
459
460 DPRINT("Thread = %x\n",Thread);
461
462 KeInitializeThread(&Process->Pcb, &Thread->Tcb, First);
463 InitializeListHead(&Thread->TerminationPortList);
464 KeInitializeSpinLock(&Thread->ActiveTimerListLock);
465 InitializeListHead(&Thread->IrpList);
466 Thread->DeadThread = FALSE;
467 Thread->HasTerminated = FALSE;
468 Thread->Tcb.Win32Thread = NULL;
469 DPRINT("Thread->Cid.UniqueThread %d\n",Thread->Cid.UniqueThread);
470
471
472 Thread->Tcb.BasePriority = (CHAR)Process->Pcb.BasePriority;
473 Thread->Tcb.Priority = Thread->Tcb.BasePriority;
474
475 /*
476 * Local Procedure Call facility (LPC)
477 */
478 KeInitializeSemaphore (& Thread->LpcReplySemaphore, 0, LONG_MAX);
479 Thread->LpcReplyMessage = NULL;
480 Thread->LpcReplyMessageId = 0; /* not valid */
481 /* Thread->LpcReceiveMessageId = 0; */
482 Thread->LpcExitThreadCalled = FALSE;
483 Thread->LpcReceivedMsgIdValid = FALSE;
484
485 oldIrql = KeAcquireDispatcherDatabaseLock();
486 InsertTailList(&Process->ThreadListHead,
487 &Thread->ThreadListEntry);
488 KeReleaseDispatcherDatabaseLock(oldIrql);
489
490 *ThreadPtr = Thread;
491
492 return(STATUS_SUCCESS);
493 }
494
495
496 static NTSTATUS
497 PsCreateTeb(HANDLE ProcessHandle,
498 PTEB *TebPtr,
499 PETHREAD Thread,
500 PINITIAL_TEB InitialTeb)
501 {
502 PEPROCESS Process;
503 NTSTATUS Status;
504 ULONG ByteCount;
505 ULONG RegionSize;
506 ULONG TebSize;
507 PVOID TebBase;
508 TEB Teb;
509
510 TebSize = PAGE_SIZE;
511
512 if (NULL == Thread->ThreadsProcess)
513 {
514 /* We'll be allocating a 64k block here and only use 4k of it, but this
515 path should almost never be taken. Actually, I never saw it was taken,
516 so maybe we should just ASSERT(NULL != Thread->ThreadsProcess) and
517 move on */
518 TebBase = NULL;
519 Status = ZwAllocateVirtualMemory(ProcessHandle,
520 &TebBase,
521 0,
522 &TebSize,
523 MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
524 PAGE_READWRITE);
525 if (! NT_SUCCESS(Status))
526 {
527 DPRINT1("Failed to allocate virtual memory for TEB\n");
528 return Status;
529 }
530 }
531 else
532 {
533 Process = Thread->ThreadsProcess;
534 ExAcquireFastMutex(&Process->TebLock);
535 if (NULL == Process->TebBlock ||
536 Process->TebBlock == Process->TebLastAllocated)
537 {
538 Process->TebBlock = NULL;
539 RegionSize = MM_VIRTMEM_GRANULARITY;
540 Status = ZwAllocateVirtualMemory(ProcessHandle,
541 &Process->TebBlock,
542 0,
543 &RegionSize,
544 MEM_RESERVE | MEM_TOP_DOWN,
545 PAGE_READWRITE);
546 if (! NT_SUCCESS(Status))
547 {
548 ExReleaseFastMutex(&Process->TebLock);
549 DPRINT1("Failed to reserve virtual memory for TEB\n");
550 return Status;
551 }
552 Process->TebLastAllocated = (PVOID) ((char *) Process->TebBlock + RegionSize);
553 }
554 TebBase = (PVOID) ((char *) Process->TebLastAllocated - PAGE_SIZE);
555 Status = ZwAllocateVirtualMemory(ProcessHandle,
556 &TebBase,
557 0,
558 &TebSize,
559 MEM_COMMIT,
560 PAGE_READWRITE);
561 if (! NT_SUCCESS(Status))
562 {
563 DPRINT1("Failed to commit virtual memory for TEB\n");
564 return Status;
565 }
566 Process->TebLastAllocated = TebBase;
567 ExReleaseFastMutex(&Process->TebLock);
568 }
569
570 DPRINT ("TebBase %p TebSize %lu\n", TebBase, TebSize);
571 ASSERT(NULL != TebBase && PAGE_SIZE <= TebSize);
572
573 RtlZeroMemory(&Teb, sizeof(TEB));
574 /* set all pointers to and from the TEB */
575 Teb.Tib.Self = TebBase;
576 if (Thread->ThreadsProcess)
577 {
578 Teb.Peb = Thread->ThreadsProcess->Peb; /* No PEB yet!! */
579 }
580 DPRINT("Teb.Peb %x\n", Teb.Peb);
581
582 /* store stack information from InitialTeb */
583 if(InitialTeb != NULL)
584 {
585 /* fixed-size stack */
586 if(InitialTeb->StackBase && InitialTeb->StackLimit)
587 {
588 Teb.Tib.StackBase = InitialTeb->StackBase;
589 Teb.Tib.StackLimit = InitialTeb->StackLimit;
590 Teb.DeallocationStack = InitialTeb->StackLimit;
591 }
592 /* expandable stack */
593 else
594 {
595 Teb.Tib.StackBase = InitialTeb->StackCommit;
596 Teb.Tib.StackLimit = InitialTeb->StackCommitMax;
597 Teb.DeallocationStack = InitialTeb->StackReserved;
598 }
599 }
600
601 /* more initialization */
602 Teb.Cid.UniqueThread = Thread->Cid.UniqueThread;
603 Teb.Cid.UniqueProcess = Thread->Cid.UniqueProcess;
604 Teb.CurrentLocale = PsDefaultThreadLocaleId;
605
606 /* Terminate the exception handler list */
607 Teb.Tib.ExceptionList = (PVOID)-1;
608
609 DPRINT("sizeof(TEB) %x\n", sizeof(TEB));
610
611 /* write TEB data into teb page */
612 Status = NtWriteVirtualMemory(ProcessHandle,
613 TebBase,
614 &Teb,
615 sizeof(TEB),
616 &ByteCount);
617
618 if (!NT_SUCCESS(Status))
619 {
620 /* free TEB */
621 DPRINT1 ("Writing TEB failed!\n");
622
623 RegionSize = 0;
624 NtFreeVirtualMemory(ProcessHandle,
625 TebBase,
626 &RegionSize,
627 MEM_RELEASE);
628
629 return Status;
630 }
631
632 if (TebPtr != NULL)
633 {
634 *TebPtr = (PTEB)TebBase;
635 }
636
637 DPRINT("TEB allocated at %p\n", TebBase);
638
639 return Status;
640 }
641
642
643 VOID STDCALL
644 LdrInitApcRundownRoutine(PKAPC Apc)
645 {
646 ExFreePool(Apc);
647 }
648
649
650 VOID STDCALL
651 LdrInitApcKernelRoutine(PKAPC Apc,
652 PKNORMAL_ROUTINE* NormalRoutine,
653 PVOID* NormalContext,
654 PVOID* SystemArgument1,
655 PVOID* SystemArgument2)
656 {
657 ExFreePool(Apc);
658 }
659
660
661 NTSTATUS STDCALL
662 NtCreateThread(OUT PHANDLE ThreadHandle,
663 IN ACCESS_MASK DesiredAccess,
664 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
665 IN HANDLE ProcessHandle,
666 OUT PCLIENT_ID Client,
667 IN PCONTEXT ThreadContext,
668 IN PINITIAL_TEB InitialTeb,
669 IN BOOLEAN CreateSuspended)
670 {
671 PEPROCESS Process;
672 PETHREAD Thread;
673 PTEB TebBase;
674 NTSTATUS Status;
675 PKAPC LdrInitApc;
676 KIRQL oldIrql;
677
678 DPRINT("NtCreateThread(ThreadHandle %x, PCONTEXT %x)\n",
679 ThreadHandle,ThreadContext);
680
681 Status = ObReferenceObjectByHandle(ProcessHandle,
682 PROCESS_CREATE_THREAD,
683 PsProcessType,
684 UserMode,
685 (PVOID*)&Process,
686 NULL);
687 if(!NT_SUCCESS(Status))
688 {
689 return(Status);
690 }
691
692 Status = PsInitializeThread(Process,
693 &Thread,
694 ThreadHandle,
695 DesiredAccess,
696 ObjectAttributes,
697 FALSE);
698
699 ObDereferenceObject(Process);
700
701 if (!NT_SUCCESS(Status))
702 {
703 return(Status);
704 }
705
706 Status = KiArchInitThreadWithContext(&Thread->Tcb, ThreadContext);
707 if (!NT_SUCCESS(Status))
708 {
709 return(Status);
710 }
711
712 Status = PsCreateTeb(ProcessHandle,
713 &TebBase,
714 Thread,
715 InitialTeb);
716 if (!NT_SUCCESS(Status))
717 {
718 return(Status);
719 }
720 Thread->Tcb.Teb = TebBase;
721
722 Thread->StartAddress = NULL;
723
724 if (Client != NULL)
725 {
726 *Client = Thread->Cid;
727 }
728
729 /*
730 * Maybe send a message to the process's debugger
731 */
732 DbgkCreateThread((PVOID)ThreadContext->Eip);
733
734 /*
735 * First, force the thread to be non-alertable for user-mode alerts.
736 */
737 Thread->Tcb.Alertable = FALSE;
738
739 /*
740 * If the thread is to be created suspended then queue an APC to
741 * do the suspend before we run any userspace code.
742 */
743 if (CreateSuspended)
744 {
745 PsSuspendThread(Thread, NULL);
746 }
747
748 /*
749 * Queue an APC to the thread that will execute the ntdll startup
750 * routine.
751 */
752 LdrInitApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));
753 KeInitializeApc(LdrInitApc, &Thread->Tcb, OriginalApcEnvironment, LdrInitApcKernelRoutine,
754 LdrInitApcRundownRoutine, LdrpGetSystemDllEntryPoint(),
755 UserMode, NULL);
756 KeInsertQueueApc(LdrInitApc, NULL, NULL, IO_NO_INCREMENT);
757
758 /*
759 * The thread is non-alertable, so the APC we added did not set UserApcPending to TRUE.
760 * We must do this manually. Do NOT attempt to set the Thread to Alertable before the call,
761 * doing so is a blatant and erronous hack.
762 */
763 Thread->Tcb.ApcState.UserApcPending = TRUE;
764 Thread->Tcb.Alerted[KernelMode] = TRUE;
765
766 oldIrql = KeAcquireDispatcherDatabaseLock ();
767 PsUnblockThread(Thread, NULL, 0);
768 KeReleaseDispatcherDatabaseLock(oldIrql);
769
770
771 return(STATUS_SUCCESS);
772 }
773
774
775 /*
776 * @implemented
777 */
778 NTSTATUS STDCALL
779 PsCreateSystemThread(PHANDLE ThreadHandle,
780 ACCESS_MASK DesiredAccess,
781 POBJECT_ATTRIBUTES ObjectAttributes,
782 HANDLE ProcessHandle,
783 PCLIENT_ID ClientId,
784 PKSTART_ROUTINE StartRoutine,
785 PVOID StartContext)
786 /*
787 * FUNCTION: Creates a thread which executes in kernel mode
788 * ARGUMENTS:
789 * ThreadHandle (OUT) = Caller supplied storage for the returned thread
790 * handle
791 * DesiredAccess = Requested access to the thread
792 * ObjectAttributes = Object attributes (optional)
793 * ProcessHandle = Handle of process thread will run in
794 * NULL to use system process
795 * ClientId (OUT) = Caller supplied storage for the returned client id
796 * of the thread (optional)
797 * StartRoutine = Entry point for the thread
798 * StartContext = Argument supplied to the thread when it begins
799 * execution
800 * RETURNS: Success or failure status
801 */
802 {
803 PETHREAD Thread;
804 NTSTATUS Status;
805 KIRQL oldIrql;
806
807 DPRINT("PsCreateSystemThread(ThreadHandle %x, ProcessHandle %x)\n",
808 ThreadHandle,ProcessHandle);
809
810 Status = PsInitializeThread(NULL,
811 &Thread,
812 ThreadHandle,
813 DesiredAccess,
814 ObjectAttributes,
815 FALSE);
816 if (!NT_SUCCESS(Status))
817 {
818 return(Status);
819 }
820
821 Thread->StartAddress = StartRoutine;
822 Status = KiArchInitThread(&Thread->Tcb, StartRoutine, StartContext);
823 if (!NT_SUCCESS(Status))
824 {
825 return(Status);
826 }
827
828 if (ClientId != NULL)
829 {
830 *ClientId=Thread->Cid;
831 }
832
833 oldIrql = KeAcquireDispatcherDatabaseLock ();
834 PsUnblockThread(Thread, NULL, 0);
835 KeReleaseDispatcherDatabaseLock(oldIrql);
836
837 return(STATUS_SUCCESS);
838 }
839
840
841 VOID STDCALL
842 PspRunCreateThreadNotifyRoutines(PETHREAD CurrentThread,
843 BOOLEAN Create)
844 {
845 ULONG i;
846 CLIENT_ID Cid = CurrentThread->Cid;
847
848 for (i = 0; i < PiThreadNotifyRoutineCount; i++)
849 {
850 PiThreadNotifyRoutine[i](Cid.UniqueProcess, Cid.UniqueThread, Create);
851 }
852 }
853
854
855 /*
856 * @implemented
857 */
858 NTSTATUS STDCALL
859 PsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
860 {
861 if (PiThreadNotifyRoutineCount >= MAX_THREAD_NOTIFY_ROUTINE_COUNT)
862 {
863 return(STATUS_INSUFFICIENT_RESOURCES);
864 }
865
866 PiThreadNotifyRoutine[PiThreadNotifyRoutineCount] = NotifyRoutine;
867 PiThreadNotifyRoutineCount++;
868
869 return(STATUS_SUCCESS);
870 }
871
872 /* EOF */