Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2439 lines
69 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. create.c
  5. Abstract:
  6. Process and Thread Creation.
  7. Author:
  8. Mark Lucovsky (markl) 20-Apr-1989
  9. Neill Clift (NeillC) 8-Apr-2001
  10. Revamped process lock usage to limit time spend under the lock.
  11. Use rundown protection to protect parent against deletion.
  12. Tidy up errors paths to be small and mostly handled by process delete.
  13. Lock free and unload safe callouts.
  14. Revision History:
  15. --*/
  16. #include "psp.h"
  17. ULONG
  18. PspUnhandledExceptionInSystemThread(
  19. IN PEXCEPTION_POINTERS ExceptionPointers
  20. );
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE, NtCreateThread)
  23. #pragma alloc_text(PAGE, PsCreateSystemThread)
  24. #pragma alloc_text(PAGE, PspCreateThread)
  25. #pragma alloc_text(PAGE, NtCreateProcess)
  26. #pragma alloc_text(PAGE, NtCreateProcessEx)
  27. #pragma alloc_text(PAGE, PsCreateSystemProcess)
  28. #pragma alloc_text(PAGE, PspCreateProcess)
  29. #pragma alloc_text(PAGE, PsSetCreateProcessNotifyRoutine)
  30. #pragma alloc_text(PAGE, PsSetCreateThreadNotifyRoutine)
  31. #pragma alloc_text(PAGE, PsRemoveCreateThreadNotifyRoutine)
  32. #pragma alloc_text(PAGE, PspUserThreadStartup)
  33. #pragma alloc_text(PAGE, PsSetLoadImageNotifyRoutine)
  34. #pragma alloc_text(PAGE, PsRemoveLoadImageNotifyRoutine)
  35. #pragma alloc_text(PAGE, PsCallImageNotifyRoutines)
  36. #pragma alloc_text(PAGE, PspUnhandledExceptionInSystemThread)
  37. #pragma alloc_text(PAGE, PspSystemThreadStartup)
  38. #pragma alloc_text(PAGE, PspImageNotifyTest)
  39. #endif
  40. extern UNICODE_STRING CmCSDVersionString;
  41. #ifdef ALLOC_DATA_PRAGMA
  42. #pragma data_seg("PAGEDATA")
  43. #endif
  44. LCID PsDefaultSystemLocaleId = 0;
  45. LCID PsDefaultThreadLocaleId = 0;
  46. LANGID PsDefaultUILanguageId = 0;
  47. LANGID PsInstallUILanguageId = 0;
  48. //
  49. // The following two globals are present to make it easier to change
  50. // working set sizes when debugging.
  51. //
  52. ULONG PsMinimumWorkingSet = 20;
  53. ULONG PsMaximumWorkingSet = 45;
  54. BOOLEAN PsImageNotifyEnabled = FALSE;
  55. #ifdef ALLOC_DATA_PRAGMA
  56. #pragma data_seg()
  57. #endif
  58. //
  59. // Define the local storage for the process lock fast mutex.
  60. //
  61. NTSTATUS
  62. NtCreateThread(
  63. OUT PHANDLE ThreadHandle,
  64. IN ACCESS_MASK DesiredAccess,
  65. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  66. IN HANDLE ProcessHandle,
  67. OUT PCLIENT_ID ClientId,
  68. IN PCONTEXT ThreadContext,
  69. IN PINITIAL_TEB InitialTeb,
  70. IN BOOLEAN CreateSuspended
  71. )
  72. /*++
  73. Routine Description:
  74. This system service API creates and initializes a thread object.
  75. Arguments:
  76. ThreadHandle - Returns the handle for the new thread.
  77. DesiredAccess - Supplies the desired access modes to the new thread.
  78. ObjectAttributes - Supplies the object attributes of the new thread.
  79. ProcessHandle - Supplies a handle to the process that the thread is being
  80. created within.
  81. ClientId - Returns the CLIENT_ID of the new thread.
  82. ThreadContext - Supplies an initial context for the new thread.
  83. InitialTeb - Supplies the initial contents for the thread's TEB.
  84. CreateSuspended - Supplies a value that controls whether or not a
  85. thread is created in a suspended state.
  86. Return Value:
  87. TBD
  88. --*/
  89. {
  90. NTSTATUS Status;
  91. INITIAL_TEB CapturedInitialTeb;
  92. PAGED_CODE();
  93. //
  94. // Probe all arguments
  95. //
  96. try {
  97. if (KeGetPreviousMode () != KernelMode) {
  98. ProbeForWriteHandle (ThreadHandle);
  99. if (ARGUMENT_PRESENT (ClientId)) {
  100. ProbeForWriteSmallStructure (ClientId, sizeof (CLIENT_ID), sizeof (ULONG));
  101. }
  102. if (ARGUMENT_PRESENT (ThreadContext) ) {
  103. ProbeForReadSmallStructure (ThreadContext, sizeof (CONTEXT), CONTEXT_ALIGN);
  104. } else {
  105. return STATUS_INVALID_PARAMETER;
  106. }
  107. ProbeForReadSmallStructure (InitialTeb, sizeof (InitialTeb->OldInitialTeb), sizeof (ULONG));
  108. }
  109. CapturedInitialTeb.OldInitialTeb = InitialTeb->OldInitialTeb;
  110. if (CapturedInitialTeb.OldInitialTeb.OldStackBase == NULL &&
  111. CapturedInitialTeb.OldInitialTeb.OldStackLimit == NULL) {
  112. //
  113. // Since the structure size here is less than 64k we don't need to reprobe
  114. //
  115. CapturedInitialTeb = *InitialTeb;
  116. }
  117. } except (ExSystemExceptionFilter ()) {
  118. return GetExceptionCode ();
  119. }
  120. Status = PspCreateThread (ThreadHandle,
  121. DesiredAccess,
  122. ObjectAttributes,
  123. ProcessHandle,
  124. NULL,
  125. ClientId,
  126. ThreadContext,
  127. &CapturedInitialTeb,
  128. CreateSuspended,
  129. NULL,
  130. NULL);
  131. return Status;
  132. }
  133. NTSTATUS
  134. PsCreateSystemThread(
  135. OUT PHANDLE ThreadHandle,
  136. IN ACCESS_MASK DesiredAccess,
  137. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  138. IN HANDLE ProcessHandle OPTIONAL,
  139. OUT PCLIENT_ID ClientId OPTIONAL,
  140. IN PKSTART_ROUTINE StartRoutine,
  141. IN PVOID StartContext
  142. )
  143. /*++
  144. Routine Description:
  145. This routine creates and starts a system thread.
  146. Arguments:
  147. ThreadHandle - Returns the handle for the new thread.
  148. DesiredAccess - Supplies the desired access modes to the new thread.
  149. ObjectAttributes - Supplies the object attributes of the new thread.
  150. ProcessHandle - Supplies a handle to the process that the thread is being
  151. created within. If this parameter is not specified, then
  152. the initial system process is used.
  153. ClientId - Returns the CLIENT_ID of the new thread.
  154. StartRoutine - Supplies the address of the system thread start routine.
  155. StartContext - Supplies context for a system thread start routine.
  156. Return Value:
  157. TBD
  158. --*/
  159. {
  160. NTSTATUS Status;
  161. HANDLE SystemProcess;
  162. PEPROCESS ProcessPointer;
  163. PAGED_CODE();
  164. ProcessPointer = NULL;
  165. if (ARGUMENT_PRESENT (ProcessHandle)) {
  166. SystemProcess = ProcessHandle;
  167. } else {
  168. SystemProcess = NULL;
  169. ProcessPointer = PsInitialSystemProcess;
  170. }
  171. Status = PspCreateThread (ThreadHandle,
  172. DesiredAccess,
  173. ObjectAttributes,
  174. SystemProcess,
  175. ProcessPointer,
  176. ClientId,
  177. NULL,
  178. NULL,
  179. FALSE,
  180. StartRoutine,
  181. StartContext);
  182. return Status;
  183. }
  184. NTSTATUS
  185. PspCreateThread(
  186. OUT PHANDLE ThreadHandle,
  187. IN ACCESS_MASK DesiredAccess,
  188. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  189. IN HANDLE ProcessHandle,
  190. IN PEPROCESS ProcessPointer,
  191. OUT PCLIENT_ID ClientId OPTIONAL,
  192. IN PCONTEXT ThreadContext OPTIONAL,
  193. IN PINITIAL_TEB InitialTeb OPTIONAL,
  194. IN BOOLEAN CreateSuspended,
  195. IN PKSTART_ROUTINE StartRoutine OPTIONAL,
  196. IN PVOID StartContext
  197. )
  198. /*++
  199. Routine Description:
  200. This routine creates and initializes a thread object. It implements the
  201. foundation for NtCreateThread and for PsCreateSystemThread.
  202. Arguments:
  203. ThreadHandle - Returns the handle for the new thread.
  204. DesiredAccess - Supplies the desired access modes to the new thread.
  205. ObjectAttributes - Supplies the object attributes of the new thread.
  206. ProcessHandle - Supplies a handle to the process that the thread is being
  207. created within.
  208. ClientId - Returns the CLIENT_ID of the new thread.
  209. ThreadContext - Supplies a pointer to a context frame that represents the
  210. initial user-mode context for a user-mode thread. The absence
  211. of this parameter indicates that a system thread is being
  212. created.
  213. InitialTeb - Supplies the contents of certain fields for the new threads
  214. TEB. This parameter is only examined if both a trap and
  215. exception frame were specified.
  216. CreateSuspended - Supplies a value that controls whether or not a user-mode
  217. thread is created in a suspended state.
  218. StartRoutine - Supplies the address of the system thread start routine.
  219. StartContext - Supplies context for a system thread start routine.
  220. Return Value:
  221. TBD
  222. --*/
  223. {
  224. HANDLE_TABLE_ENTRY CidEntry;
  225. NTSTATUS Status;
  226. PETHREAD Thread;
  227. PETHREAD CurrentThread;
  228. PEPROCESS Process;
  229. PTEB Teb;
  230. KPROCESSOR_MODE PreviousMode;
  231. HANDLE LocalThreadHandle;
  232. BOOLEAN AccessCheck;
  233. BOOLEAN MemoryAllocated;
  234. PSECURITY_DESCRIPTOR SecurityDescriptor;
  235. SECURITY_SUBJECT_CONTEXT SubjectContext;
  236. NTSTATUS accesst;
  237. LARGE_INTEGER CreateTime;
  238. ULONG OldActiveThreads;
  239. PEJOB Job;
  240. PAGED_CODE();
  241. CurrentThread = PsGetCurrentThread ();
  242. if (StartRoutine != NULL) {
  243. PreviousMode = KernelMode;
  244. } else {
  245. PreviousMode = KeGetPreviousModeByThread (&CurrentThread->Tcb);
  246. }
  247. Teb = NULL;
  248. Thread = NULL;
  249. Process = NULL;
  250. if (ProcessHandle != NULL) {
  251. //
  252. // Process object reference count is biased by one for each thread.
  253. // This accounts for the pointer given to the kernel that remains
  254. // in effect until the thread terminates (and becomes signaled)
  255. //
  256. Status = ObReferenceObjectByHandle (ProcessHandle,
  257. PROCESS_CREATE_THREAD,
  258. PsProcessType,
  259. PreviousMode,
  260. &Process,
  261. NULL);
  262. } else {
  263. if (StartRoutine != NULL) {
  264. ObReferenceObject (ProcessPointer);
  265. Process = ProcessPointer;
  266. Status = STATUS_SUCCESS;
  267. } else {
  268. Status = STATUS_INVALID_HANDLE;
  269. }
  270. }
  271. if (!NT_SUCCESS (Status)) {
  272. return Status;
  273. }
  274. //
  275. // If the previous mode is user and the target process is the system
  276. // process, then the operation cannot be performed.
  277. //
  278. if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess)) {
  279. ObDereferenceObject (Process);
  280. return STATUS_INVALID_HANDLE;
  281. }
  282. Status = ObCreateObject (PreviousMode,
  283. PsThreadType,
  284. ObjectAttributes,
  285. PreviousMode,
  286. NULL,
  287. sizeof(ETHREAD),
  288. 0,
  289. 0,
  290. &Thread);
  291. if (!NT_SUCCESS (Status)) {
  292. ObDereferenceObject (Process);
  293. return Status;
  294. }
  295. RtlZeroMemory (Thread, sizeof (ETHREAD));
  296. //
  297. // Initialize rundown protection for cross thread TEB refs etc.
  298. //
  299. ExInitializeRundownProtection (&Thread->RundownProtect);
  300. //
  301. // Assign this thread to the process so that from now on
  302. // we don't have to dereference in error paths.
  303. //
  304. Thread->ThreadsProcess = Process;
  305. Thread->Cid.UniqueProcess = Process->UniqueProcessId;
  306. CidEntry.Object = Thread;
  307. CidEntry.GrantedAccess = 0;
  308. Thread->Cid.UniqueThread = ExCreateHandle (PspCidTable, &CidEntry);
  309. if (Thread->Cid.UniqueThread == NULL) {
  310. ObDereferenceObject (Process);
  311. return (STATUS_INSUFFICIENT_RESOURCES);
  312. }
  313. //
  314. // Initialize Mm
  315. //
  316. Thread->ReadClusterSize = MmReadClusterSize;
  317. //
  318. // Initialize LPC
  319. //
  320. KeInitializeSemaphore (&Thread->LpcReplySemaphore, 0L, 1L);
  321. InitializeListHead (&Thread->LpcReplyChain);
  322. //
  323. // Initialize Io
  324. //
  325. InitializeListHead (&Thread->IrpList);
  326. //
  327. // Initialize Registry
  328. //
  329. InitializeListHead (&Thread->PostBlockList);
  330. //
  331. // Initialize the thread lock
  332. //
  333. PspInitializeThreadLock (Thread);
  334. //
  335. // Initialize Security. Unneeded as we zero out the entire thread block
  336. //
  337. // PspInitializeThreadSecurity (Process, Thread);
  338. //
  339. // Initialize Termination port list. Unneeded as we zero out the entire thread
  340. //
  341. // InitializeListHead (&Thread->TerminationPort);
  342. KeInitializeSpinLock (&Thread->ActiveTimerListLock);
  343. InitializeListHead (&Thread->ActiveTimerListHead);
  344. if (!ExAcquireRundownProtection (&Process->RundownProtect)) {
  345. ObDereferenceObject (Thread);
  346. return STATUS_PROCESS_IS_TERMINATING;
  347. }
  348. if (ARGUMENT_PRESENT (ThreadContext)) {
  349. //
  350. // User-mode thread. Create TEB etc
  351. //
  352. Status = MmCreateTeb (Process, InitialTeb, &Thread->Cid, &Teb);
  353. if (!NT_SUCCESS (Status)) {
  354. ExReleaseRundownProtection (&Process->RundownProtect);
  355. ObDereferenceObject (Thread);
  356. return Status;
  357. }
  358. try {
  359. //
  360. // Initialize kernel thread object for user mode thread.
  361. //
  362. Thread->StartAddress = (PVOID)CONTEXT_TO_PROGRAM_COUNTER(ThreadContext);
  363. #if defined(_IA64_)
  364. Thread->Win32StartAddress = (PVOID)ThreadContext->IntT0;
  365. #elif defined(_AMD64_)
  366. Thread->Win32StartAddress = (PVOID)ThreadContext->Rdx;
  367. #elif defined(_X86_)
  368. Thread->Win32StartAddress = (PVOID)ThreadContext->Eax;
  369. #else
  370. #error "no target architecture"
  371. #endif // defined(_IA64_)
  372. } except (EXCEPTION_EXECUTE_HANDLER) {
  373. Status = GetExceptionCode();
  374. }
  375. if (NT_SUCCESS (Status)) {
  376. Status = KeInitThread (&Thread->Tcb,
  377. NULL,
  378. PspUserThreadStartup,
  379. (PKSTART_ROUTINE)NULL,
  380. Thread->StartAddress,
  381. ThreadContext,
  382. Teb,
  383. &Process->Pcb);
  384. }
  385. } else {
  386. Teb = NULL;
  387. //
  388. // Set the system thread bit thats kept for all time
  389. //
  390. PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_SYSTEM);
  391. //
  392. // Initialize kernel thread object for kernel mode thread.
  393. //
  394. Thread->StartAddress = (PKSTART_ROUTINE) StartRoutine;
  395. Status = KeInitThread (&Thread->Tcb,
  396. NULL,
  397. PspSystemThreadStartup,
  398. StartRoutine,
  399. StartContext,
  400. NULL,
  401. NULL,
  402. &Process->Pcb);
  403. }
  404. if (!NT_SUCCESS (Status)) {
  405. if (Teb != NULL) {
  406. MmDeleteTeb(Process, Teb);
  407. Thread->Tcb.Teb = NULL;
  408. }
  409. ExReleaseRundownProtection (&Process->RundownProtect);
  410. ObDereferenceObject (Thread);
  411. return Status;
  412. }
  413. PspLockProcessExclusive (Process, CurrentThread);
  414. //
  415. // Process is exiting or has had delete process called
  416. //
  417. if ((Process->Flags&PS_PROCESS_FLAGS_PROCESS_DELETE) != 0) {
  418. PspUnlockProcessExclusive (Process, CurrentThread);
  419. KeUninitThread (&Thread->Tcb);
  420. if (Teb != NULL) {
  421. MmDeleteTeb(Process, Teb);
  422. }
  423. ExReleaseRundownProtection (&Process->RundownProtect);
  424. ObDereferenceObject(Thread);
  425. return STATUS_PROCESS_IS_TERMINATING;
  426. }
  427. OldActiveThreads = Process->ActiveThreads++;
  428. InsertTailList (&Process->ThreadListHead, &Thread->ThreadListEntry);
  429. KeStartThread (&Thread->Tcb);
  430. PspUnlockProcessExclusive (Process, CurrentThread);
  431. ExReleaseRundownProtection (&Process->RundownProtect);
  432. //
  433. // Failures that occur after this point cause the thread to
  434. // go through PspExitThread
  435. //
  436. if (OldActiveThreads == 0) {
  437. PERFINFO_PROCESS_CREATE (Process);
  438. if (PspCreateProcessNotifyRoutineCount != 0) {
  439. ULONG i;
  440. PEX_CALLBACK_ROUTINE_BLOCK CallBack;
  441. PCREATE_PROCESS_NOTIFY_ROUTINE Rtn;
  442. for (i=0; i<PSP_MAX_CREATE_PROCESS_NOTIFY; i++) {
  443. CallBack = ExReferenceCallBackBlock (&PspCreateProcessNotifyRoutine[i]);
  444. if (CallBack != NULL) {
  445. Rtn = (PCREATE_PROCESS_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack);
  446. Rtn (Process->InheritedFromUniqueProcessId,
  447. Process->UniqueProcessId,
  448. TRUE);
  449. ExDereferenceCallBackBlock (&PspCreateProcessNotifyRoutine[i],
  450. CallBack);
  451. }
  452. }
  453. }
  454. }
  455. //
  456. // If the process has a job with a completion port,
  457. // AND if the process is really considered to be in the Job, AND
  458. // the process has not reported, report in
  459. //
  460. // This should really be done in add process to job, but can't
  461. // in this path because the process's ID isn't assigned until this point
  462. // in time
  463. //
  464. Job = Process->Job;
  465. if (Job != NULL && Job->CompletionPort &&
  466. !(Process->JobStatus & (PS_JOB_STATUS_NOT_REALLY_ACTIVE|PS_JOB_STATUS_NEW_PROCESS_REPORTED))) {
  467. PS_SET_BITS (&Process->JobStatus, PS_JOB_STATUS_NEW_PROCESS_REPORTED);
  468. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  469. ExAcquireResourceSharedLite (&Job->JobLock, TRUE);
  470. if (Job->CompletionPort != NULL) {
  471. IoSetIoCompletion (Job->CompletionPort,
  472. Job->CompletionKey,
  473. (PVOID)Process->UniqueProcessId,
  474. STATUS_SUCCESS,
  475. JOB_OBJECT_MSG_NEW_PROCESS,
  476. FALSE);
  477. }
  478. ExReleaseResourceLite (&Job->JobLock);
  479. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  480. }
  481. PERFINFO_THREAD_CREATE(Thread, InitialTeb);
  482. //
  483. // Notify registered callout routines of thread creation.
  484. //
  485. if (PspCreateThreadNotifyRoutineCount != 0) {
  486. ULONG i;
  487. PEX_CALLBACK_ROUTINE_BLOCK CallBack;
  488. PCREATE_THREAD_NOTIFY_ROUTINE Rtn;
  489. for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++) {
  490. CallBack = ExReferenceCallBackBlock (&PspCreateThreadNotifyRoutine[i]);
  491. if (CallBack != NULL) {
  492. Rtn = (PCREATE_THREAD_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack);
  493. Rtn (Thread->Cid.UniqueProcess,
  494. Thread->Cid.UniqueThread,
  495. TRUE);
  496. ExDereferenceCallBackBlock (&PspCreateThreadNotifyRoutine[i],
  497. CallBack);
  498. }
  499. }
  500. }
  501. //
  502. // Reference count of thread is biased once for itself and once for the handle if we create it.
  503. //
  504. ObReferenceObjectEx (Thread, 2);
  505. if (ARGUMENT_PRESENT (ThreadContext)) {
  506. PKAPC InitialApc;
  507. //
  508. // Allocate the initial APC
  509. //
  510. InitialApc = ExAllocatePoolWithTag (NonPagedPool, sizeof(KAPC), 'aCsP');
  511. if (InitialApc == NULL) {
  512. PS_SET_BITS (&Thread->CrossThreadFlags,
  513. PS_CROSS_THREAD_FLAGS_DEADTHREAD);
  514. KeReadyThread (&Thread->Tcb);
  515. ObDereferenceObjectEx (Thread, 2);
  516. return STATUS_INSUFFICIENT_RESOURCES;
  517. }
  518. KeInitializeApc (InitialApc,
  519. &Thread->Tcb,
  520. OriginalApcEnvironment,
  521. PspNullSpecialApc,
  522. NULL,
  523. PspSystemDll.LoaderInitRoutine,
  524. UserMode,
  525. NULL);
  526. if (!KeInsertQueueApc (InitialApc, PspSystemDll.DllBase, NULL, 0)) {
  527. PS_SET_BITS (&Thread->CrossThreadFlags,
  528. PS_CROSS_THREAD_FLAGS_DEADTHREAD);
  529. ExFreePool (InitialApc);
  530. KeReadyThread (&Thread->Tcb);
  531. ObDereferenceObjectEx (Thread, 2);
  532. return STATUS_INSUFFICIENT_RESOURCES;
  533. }
  534. }
  535. if (CreateSuspended) {
  536. try {
  537. KeSuspendThread (&Thread->Tcb);
  538. } except (EXCEPTION_EXECUTE_HANDLER) {
  539. }
  540. //
  541. // If deletion was started after we suspended then wake up the thread
  542. //
  543. if (Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_TERMINATED) {
  544. KeForceResumeThread (&Thread->Tcb);
  545. }
  546. }
  547. Status = ObInsertObject (Thread,
  548. NULL,
  549. DesiredAccess,
  550. 0,
  551. NULL,
  552. &LocalThreadHandle);
  553. if (!NT_SUCCESS (Status)) {
  554. //
  555. // The insert failed. Terminate the thread.
  556. //
  557. //
  558. // This trick is used so that Dbgk doesn't report
  559. // events for dead threads
  560. //
  561. PS_SET_BITS (&Thread->CrossThreadFlags,
  562. PS_CROSS_THREAD_FLAGS_DEADTHREAD);
  563. if (CreateSuspended) {
  564. KeResumeThread (&Thread->Tcb);
  565. }
  566. } else {
  567. try {
  568. *ThreadHandle = LocalThreadHandle;
  569. if (ARGUMENT_PRESENT (ClientId)) {
  570. *ClientId = Thread->Cid;
  571. }
  572. } except(EXCEPTION_EXECUTE_HANDLER) {
  573. PS_SET_BITS (&Thread->CrossThreadFlags,
  574. PS_CROSS_THREAD_FLAGS_DEADTHREAD);
  575. if (CreateSuspended) {
  576. (VOID) KeResumeThread (&Thread->Tcb);
  577. }
  578. KeReadyThread (&Thread->Tcb);
  579. ObDereferenceObject (Thread);
  580. ObCloseHandle (LocalThreadHandle, PreviousMode);
  581. return GetExceptionCode();
  582. }
  583. }
  584. KeQuerySystemTime(&CreateTime);
  585. ASSERT ((CreateTime.HighPart & 0xf0000000) == 0);
  586. PS_SET_THREAD_CREATE_TIME(Thread, CreateTime);
  587. if ((Thread->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_DEADTHREAD) == 0) {
  588. Status = ObGetObjectSecurity (Thread,
  589. &SecurityDescriptor,
  590. &MemoryAllocated);
  591. if (!NT_SUCCESS (Status)) {
  592. //
  593. // This trick us used so that Dbgk doesn't report
  594. // events for dead threads
  595. //
  596. PS_SET_BITS (&Thread->CrossThreadFlags,
  597. PS_CROSS_THREAD_FLAGS_DEADTHREAD);
  598. if (CreateSuspended) {
  599. KeResumeThread(&Thread->Tcb);
  600. }
  601. KeReadyThread (&Thread->Tcb);
  602. ObDereferenceObject (Thread);
  603. ObCloseHandle (LocalThreadHandle, PreviousMode);
  604. return Status;
  605. }
  606. //
  607. // Compute the subject security context
  608. //
  609. SubjectContext.ProcessAuditId = Process;
  610. SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
  611. SubjectContext.ClientToken = NULL;
  612. AccessCheck = SeAccessCheck (SecurityDescriptor,
  613. &SubjectContext,
  614. FALSE,
  615. MAXIMUM_ALLOWED,
  616. 0,
  617. NULL,
  618. &PsThreadType->TypeInfo.GenericMapping,
  619. PreviousMode,
  620. &Thread->GrantedAccess,
  621. &accesst);
  622. PsDereferencePrimaryTokenEx (Process, SubjectContext.PrimaryToken);
  623. ObReleaseObjectSecurity (SecurityDescriptor,
  624. MemoryAllocated);
  625. if (!AccessCheck) {
  626. Thread->GrantedAccess = 0;
  627. }
  628. Thread->GrantedAccess |= (THREAD_TERMINATE | THREAD_SET_INFORMATION | THREAD_QUERY_INFORMATION);
  629. } else {
  630. Thread->GrantedAccess = THREAD_ALL_ACCESS;
  631. }
  632. KeReadyThread (&Thread->Tcb);
  633. ObDereferenceObject (Thread);
  634. return Status;
  635. }
  636. NTSTATUS
  637. NtCreateProcess(
  638. OUT PHANDLE ProcessHandle,
  639. IN ACCESS_MASK DesiredAccess,
  640. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  641. IN HANDLE ParentProcess,
  642. IN BOOLEAN InheritObjectTable,
  643. IN HANDLE SectionHandle OPTIONAL,
  644. IN HANDLE DebugPort OPTIONAL,
  645. IN HANDLE ExceptionPort OPTIONAL
  646. )
  647. {
  648. ULONG Flags = 0;
  649. if ((ULONG_PTR)SectionHandle & 1) {
  650. Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY;
  651. }
  652. if ((ULONG_PTR) DebugPort & 1) {
  653. Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT;
  654. }
  655. if (InheritObjectTable) {
  656. Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
  657. }
  658. return NtCreateProcessEx (ProcessHandle,
  659. DesiredAccess,
  660. ObjectAttributes OPTIONAL,
  661. ParentProcess,
  662. Flags,
  663. SectionHandle,
  664. DebugPort,
  665. ExceptionPort,
  666. 0);
  667. }
  668. NTSTATUS
  669. NtCreateProcessEx(
  670. OUT PHANDLE ProcessHandle,
  671. IN ACCESS_MASK DesiredAccess,
  672. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  673. IN HANDLE ParentProcess,
  674. IN ULONG Flags,
  675. IN HANDLE SectionHandle OPTIONAL,
  676. IN HANDLE DebugPort OPTIONAL,
  677. IN HANDLE ExceptionPort OPTIONAL,
  678. IN ULONG JobMemberLevel
  679. )
  680. /*++
  681. Routine Description:
  682. This routine creates a process object.
  683. Arguments:
  684. ProcessHandle - Returns the handle for the new process.
  685. DesiredAccess - Supplies the desired access modes to the new process.
  686. ObjectAttributes - Supplies the object attributes of the new process.
  687. .
  688. .
  689. .
  690. Return Value:
  691. TBD
  692. --*/
  693. {
  694. NTSTATUS Status;
  695. PAGED_CODE();
  696. if (KeGetPreviousMode() != KernelMode) {
  697. //
  698. // Probe all arguments
  699. //
  700. try {
  701. ProbeForWriteHandle (ProcessHandle);
  702. } except (EXCEPTION_EXECUTE_HANDLER) {
  703. return GetExceptionCode ();
  704. }
  705. }
  706. if (ARGUMENT_PRESENT (ParentProcess)) {
  707. Status = PspCreateProcess (ProcessHandle,
  708. DesiredAccess,
  709. ObjectAttributes,
  710. ParentProcess,
  711. Flags,
  712. SectionHandle,
  713. DebugPort,
  714. ExceptionPort,
  715. JobMemberLevel);
  716. } else {
  717. Status = STATUS_INVALID_PARAMETER;
  718. }
  719. return Status;
  720. }
  721. NTSTATUS
  722. PsCreateSystemProcess(
  723. OUT PHANDLE ProcessHandle,
  724. IN ACCESS_MASK DesiredAccess,
  725. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
  726. )
  727. /*++
  728. Routine Description:
  729. This routine creates a system process object. A system process
  730. has an address space that is initialized to an empty address space
  731. that maps the system.
  732. The process inherits its access token and other attributes from the
  733. initial system process. The process is created with an empty handle table.
  734. Arguments:
  735. ProcessHandle - Returns the handle for the new process.
  736. DesiredAccess - Supplies the desired access modes to the new process.
  737. ObjectAttributes - Supplies the object attributes of the new process.
  738. Return Value:
  739. TBD
  740. --*/
  741. {
  742. NTSTATUS Status;
  743. PAGED_CODE();
  744. Status = PspCreateProcess (ProcessHandle,
  745. DesiredAccess,
  746. ObjectAttributes,
  747. PspInitialSystemProcessHandle,
  748. 0,
  749. NULL,
  750. NULL,
  751. NULL,
  752. 0);
  753. return Status;
  754. }
  755. NTSTATUS
  756. PspCreateProcess(
  757. OUT PHANDLE ProcessHandle,
  758. IN ACCESS_MASK DesiredAccess,
  759. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  760. IN HANDLE ParentProcess OPTIONAL,
  761. IN ULONG Flags,
  762. IN HANDLE SectionHandle OPTIONAL,
  763. IN HANDLE DebugPort OPTIONAL,
  764. IN HANDLE ExceptionPort OPTIONAL,
  765. IN ULONG JobMemberLevel
  766. )
  767. /*++
  768. Routine Description:
  769. This routine creates and initializes a process object. It implements the
  770. foundation for NtCreateProcess and for system initialization process
  771. creation.
  772. Arguments:
  773. ProcessHandle - Returns the handle for the new process.
  774. DesiredAccess - Supplies the desired access modes to the new process.
  775. ObjectAttributes - Supplies the object attributes of the new process.
  776. ParentProcess - Supplies a handle to the process' parent process. If this
  777. parameter is not specified, then the process has no parent
  778. and is created using the system address space.
  779. Flags - Process creation flags
  780. SectionHandle - Supplies a handle to a section object to be used to create
  781. the process' address space. If this parameter is not
  782. specified, then the address space is simply a clone of the
  783. parent process' address space.
  784. DebugPort - Supplies a handle to a port object that will be used as the
  785. process' debug port.
  786. ExceptionPort - Supplies a handle to a port object that will be used as the
  787. process' exception port.
  788. JobMemberLevel - Level for a create process in a jobset
  789. Return Value:
  790. TBD
  791. --*/
  792. {
  793. NTSTATUS Status;
  794. PEPROCESS Process;
  795. PEPROCESS CurrentProcess;
  796. PEPROCESS Parent;
  797. PETHREAD CurrentThread;
  798. KAFFINITY Affinity;
  799. KPRIORITY BasePriority;
  800. PVOID SectionObject;
  801. PVOID ExceptionPortObject;
  802. PVOID DebugPortObject;
  803. ULONG WorkingSetMinimum, WorkingSetMaximum;
  804. HANDLE LocalProcessHandle;
  805. KPROCESSOR_MODE PreviousMode;
  806. INITIAL_PEB InitialPeb;
  807. BOOLEAN CreatePeb;
  808. ULONG_PTR DirectoryTableBase[2];
  809. BOOLEAN AccessCheck;
  810. BOOLEAN MemoryAllocated;
  811. PSECURITY_DESCRIPTOR SecurityDescriptor;
  812. SECURITY_SUBJECT_CONTEXT SubjectContext;
  813. NTSTATUS accesst;
  814. NTSTATUS SavedStatus;
  815. ULONG ImageFileNameSize;
  816. HANDLE_TABLE_ENTRY CidEntry;
  817. PEJOB Job;
  818. PAGED_CODE();
  819. CurrentThread = PsGetCurrentThread ();
  820. PreviousMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  821. CurrentProcess = PsGetCurrentProcessByThread (CurrentThread);
  822. CreatePeb = FALSE;
  823. DirectoryTableBase[0] = 0;
  824. DirectoryTableBase[1] = 0;
  825. //
  826. // Reject bogus create parameters for future expansion
  827. //
  828. if (Flags&~PROCESS_CREATE_FLAGS_LEGAL_MASK) {
  829. return STATUS_INVALID_PARAMETER;
  830. }
  831. //
  832. // Parent
  833. //
  834. if (ARGUMENT_PRESENT (ParentProcess)) {
  835. Status = ObReferenceObjectByHandle (ParentProcess,
  836. PROCESS_CREATE_PROCESS,
  837. PsProcessType,
  838. PreviousMode,
  839. &Parent,
  840. NULL);
  841. if (!NT_SUCCESS (Status)) {
  842. return Status;
  843. }
  844. if (JobMemberLevel != 0 && Parent->Job == NULL) {
  845. ObDereferenceObject (Parent);
  846. return STATUS_INVALID_PARAMETER;
  847. }
  848. BasePriority = (KPRIORITY) NORMAL_BASE_PRIORITY;
  849. //
  850. //BasePriority = Parent->Pcb.BasePriority;
  851. //
  852. Affinity = Parent->Pcb.Affinity;
  853. WorkingSetMinimum = PsMinimumWorkingSet;
  854. WorkingSetMaximum = PsMaximumWorkingSet;
  855. } else {
  856. Parent = NULL;
  857. Affinity = KeActiveProcessors;
  858. BasePriority = (KPRIORITY) NORMAL_BASE_PRIORITY;
  859. WorkingSetMinimum = PsMinimumWorkingSet;
  860. WorkingSetMaximum = PsMaximumWorkingSet;
  861. }
  862. //
  863. // Create the process object
  864. //
  865. Status = ObCreateObject (PreviousMode,
  866. PsProcessType,
  867. ObjectAttributes,
  868. PreviousMode,
  869. NULL,
  870. sizeof (EPROCESS),
  871. 0,
  872. 0,
  873. &Process);
  874. if (!NT_SUCCESS (Status)) {
  875. goto exit_and_deref_parent;
  876. }
  877. //
  878. // The process object is created set to NULL. Errors
  879. // That occur after this step cause the process delete
  880. // routine to be entered.
  881. //
  882. // Teardown actions that occur in the process delete routine
  883. // do not need to be performed inline.
  884. //
  885. RtlZeroMemory (Process, sizeof(EPROCESS));
  886. ExInitializeRundownProtection (&Process->RundownProtect);
  887. PspInitializeProcessLock (Process);
  888. InitializeListHead (&Process->ThreadListHead);
  889. #if defined(_WIN64)
  890. if (Flags & PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE) {
  891. PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_OVERRIDE_ADDRESS_SPACE);
  892. }
  893. #endif
  894. PspInheritQuota (Process, Parent);
  895. ObInheritDeviceMap (Process, Parent);
  896. if (Parent != NULL) {
  897. Process->DefaultHardErrorProcessing = Parent->DefaultHardErrorProcessing;
  898. Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId;
  899. } else {
  900. Process->DefaultHardErrorProcessing = 1;
  901. Process->InheritedFromUniqueProcessId = NULL;
  902. }
  903. //
  904. // Section
  905. //
  906. if (ARGUMENT_PRESENT (SectionHandle)) {
  907. Status = ObReferenceObjectByHandle (SectionHandle,
  908. SECTION_MAP_EXECUTE,
  909. MmSectionObjectType,
  910. PreviousMode,
  911. &SectionObject,
  912. NULL);
  913. if (!NT_SUCCESS (Status)) {
  914. goto exit_and_deref;
  915. }
  916. } else {
  917. SectionObject = NULL;
  918. if (Parent != PsInitialSystemProcess) {
  919. //
  920. // Fetch the section pointer from the parent process
  921. // as we will be cloning. Since the section pointer
  922. // is removed at last thread exit we need to protect against
  923. // process exit here to be safe.
  924. //
  925. if (ExAcquireRundownProtection (&Parent->RundownProtect)) {
  926. SectionObject = Parent->SectionObject;
  927. if (SectionObject != NULL) {
  928. ObReferenceObject (SectionObject);
  929. }
  930. ExReleaseRundownProtection (&Parent->RundownProtect);
  931. }
  932. if (SectionObject == NULL) {
  933. Status = STATUS_PROCESS_IS_TERMINATING;
  934. goto exit_and_deref;
  935. }
  936. }
  937. }
  938. Process->SectionObject = SectionObject;
  939. //
  940. // DebugPort
  941. //
  942. if (ARGUMENT_PRESENT (DebugPort)) {
  943. Status = ObReferenceObjectByHandle (DebugPort,
  944. DEBUG_PROCESS_ASSIGN,
  945. DbgkDebugObjectType,
  946. PreviousMode,
  947. &DebugPortObject,
  948. NULL);
  949. if (!NT_SUCCESS (Status)) {
  950. goto exit_and_deref;
  951. }
  952. Process->DebugPort = DebugPortObject;
  953. if (Flags&PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT) {
  954. PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_NO_DEBUG_INHERIT);
  955. }
  956. } else {
  957. if (Parent != NULL) {
  958. DbgkCopyProcessDebugPort (Process, Parent);
  959. }
  960. }
  961. //
  962. // ExceptionPort
  963. //
  964. if (ARGUMENT_PRESENT (ExceptionPort)) {
  965. Status = ObReferenceObjectByHandle (ExceptionPort,
  966. 0,
  967. LpcPortObjectType,
  968. PreviousMode,
  969. &ExceptionPortObject,
  970. NULL);
  971. if (!NT_SUCCESS (Status)) {
  972. goto exit_and_deref;
  973. }
  974. Process->ExceptionPort = ExceptionPortObject;
  975. }
  976. Process->ExitStatus = STATUS_PENDING;
  977. //
  978. // Initialize the security fields of the process
  979. // The parent may be null exactly once (during system init).
  980. // Thereafter, a parent is always required so that we have a
  981. // security context to duplicate for the new process.
  982. //
  983. Status = PspInitializeProcessSecurity (Parent, Process);
  984. if (!NT_SUCCESS (Status)) {
  985. goto exit_and_deref;
  986. }
  987. //
  988. // Clone parent's object table.
  989. // If no parent (booting) then use the current object table created in
  990. // ObInitSystem.
  991. //
  992. if (Parent != NULL) {
  993. //
  994. // Calculate address space
  995. //
  996. // If Parent == PspInitialSystem
  997. //
  998. if (!MmCreateProcessAddressSpace (WorkingSetMinimum,
  999. Process,
  1000. &DirectoryTableBase[0])) {
  1001. Status = STATUS_INSUFFICIENT_RESOURCES;
  1002. goto exit_and_deref;
  1003. }
  1004. } else {
  1005. Process->ObjectTable = CurrentProcess->ObjectTable;
  1006. //
  1007. // Initialize the Working Set Mutex and address creation mutex
  1008. // for this "hand built" process.
  1009. // Normally, the call the MmInitializeAddressSpace initializes the
  1010. // working set mutex, however, in this case, we have already initialized
  1011. // the address space and we are now creating a second process using
  1012. // the address space of the idle thread.
  1013. //
  1014. MmInitializeHandBuiltProcess (Process, &DirectoryTableBase[0]);
  1015. }
  1016. PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_HAS_ADDRESS_SPACE);
  1017. Process->Vm.MaximumWorkingSetSize = WorkingSetMaximum;
  1018. KeInitializeProcess (&Process->Pcb,
  1019. BasePriority,
  1020. Affinity,
  1021. &DirectoryTableBase[0],
  1022. (BOOLEAN)(Process->DefaultHardErrorProcessing & PROCESS_HARDERROR_ALIGNMENT_BIT));
  1023. Process->Pcb.ThreadQuantum = PspForegroundQuantum[0];
  1024. Process->PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
  1025. if (Parent != NULL) {
  1026. if (Parent->PriorityClass == PROCESS_PRIORITY_CLASS_IDLE ||
  1027. Parent->PriorityClass == PROCESS_PRIORITY_CLASS_BELOW_NORMAL) {
  1028. Process->PriorityClass = Parent->PriorityClass;
  1029. }
  1030. //
  1031. // if address space creation worked, then when going through
  1032. // delete, we will attach. Of course, attaching means that the kprocess
  1033. // must be initialized, so we delay the object stuff till here.
  1034. //
  1035. Status = ObInitProcess ((Flags&PROCESS_CREATE_FLAGS_INHERIT_HANDLES) ? Parent : NULL,
  1036. Process);
  1037. if (!NT_SUCCESS (Status)) {
  1038. goto exit_and_deref;
  1039. }
  1040. }
  1041. else {
  1042. Status = MmInitializeHandBuiltProcess2 (Process);
  1043. if (!NT_SUCCESS (Status)) {
  1044. goto exit_and_deref;
  1045. }
  1046. }
  1047. Status = STATUS_SUCCESS;
  1048. SavedStatus = STATUS_SUCCESS;
  1049. //
  1050. // Initialize the process address space
  1051. // The address space has four possibilities
  1052. //
  1053. // 1 - Boot Process. Address space is initialized during
  1054. // MmInit. Parent is not specified.
  1055. //
  1056. // 2 - System Process. Address space is a virgin address
  1057. // space that only maps system space. Process is same
  1058. // as PspInitialSystemProcess.
  1059. //
  1060. // 3 - User Process (Cloned Address Space). Address space
  1061. // is cloned from the specified process.
  1062. //
  1063. // 4 - User Process (New Image Address Space). Address space
  1064. // is initialized so that it maps the specified section.
  1065. //
  1066. if (SectionHandle != NULL) {
  1067. //
  1068. // User Process (New Image Address Space). Don't specify Process to
  1069. // clone, just SectionObject.
  1070. //
  1071. //
  1072. // Passing in the 4th parameter as below lets the EPROCESS struct contain its image file name, provided that
  1073. // appropriate audit settings are enabled. Memory is allocated inside of MmInitializeProcessAddressSpace
  1074. // and pointed to by ImageFileName, so that must be freed in the process deletion routine (PspDeleteProcess())
  1075. //
  1076. Status = MmInitializeProcessAddressSpace (Process,
  1077. NULL,
  1078. SectionObject,
  1079. &(Process->SeAuditProcessCreationInfo.ImageFileName));
  1080. if (!NT_SUCCESS (Status)) {
  1081. goto exit_and_deref;
  1082. }
  1083. //
  1084. // In order to support relocating executables, the proper status
  1085. // (STATUS_IMAGE_NOT_AT_BASE) must be returned, so save it here.
  1086. //
  1087. SavedStatus = Status;
  1088. Status = PspMapSystemDll (Process, NULL);
  1089. if (!NT_SUCCESS (Status)) {
  1090. goto exit_and_deref;
  1091. }
  1092. CreatePeb = TRUE;
  1093. } else if (Parent != NULL) {
  1094. if (Parent != PsInitialSystemProcess) {
  1095. Process->SectionBaseAddress = Parent->SectionBaseAddress;
  1096. //
  1097. // User Process ( Cloned Address Space ). Don't specify section to
  1098. // map, just Process to clone.
  1099. //
  1100. Status = MmInitializeProcessAddressSpace (Process,
  1101. Parent,
  1102. NULL,
  1103. NULL);
  1104. CreatePeb = TRUE;
  1105. if (!NT_SUCCESS (Status)) {
  1106. goto exit_and_deref;
  1107. }
  1108. //
  1109. // A cloned process isn't started from an image file, so we give it the name
  1110. // of the process of which it is a clone, provided the original has a name.
  1111. //
  1112. if (Parent->SeAuditProcessCreationInfo.ImageFileName != NULL) {
  1113. ImageFileNameSize = sizeof(OBJECT_NAME_INFORMATION) +
  1114. Parent->SeAuditProcessCreationInfo.ImageFileName->Name.MaximumLength;
  1115. Process->SeAuditProcessCreationInfo.ImageFileName =
  1116. ExAllocatePoolWithTag (PagedPool,
  1117. ImageFileNameSize,
  1118. 'aPeS');
  1119. if (Process->SeAuditProcessCreationInfo.ImageFileName != NULL) {
  1120. RtlCopyMemory (Process->SeAuditProcessCreationInfo.ImageFileName,
  1121. Parent->SeAuditProcessCreationInfo.ImageFileName,
  1122. ImageFileNameSize);
  1123. //
  1124. // The UNICODE_STRING in the process is self contained, so calculate the
  1125. // offset for the buffer.
  1126. //
  1127. Process->SeAuditProcessCreationInfo.ImageFileName->Name.Buffer =
  1128. (PUSHORT)(((PUCHAR) Process->SeAuditProcessCreationInfo.ImageFileName) +
  1129. sizeof(UNICODE_STRING));
  1130. } else {
  1131. Status = STATUS_INSUFFICIENT_RESOURCES;
  1132. goto exit_and_deref;
  1133. }
  1134. }
  1135. } else {
  1136. //
  1137. // System Process. Don't specify Process to clone or section to map
  1138. //
  1139. Status = MmInitializeProcessAddressSpace (Process,
  1140. NULL,
  1141. NULL,
  1142. NULL);
  1143. if (!NT_SUCCESS (Status)) {
  1144. goto exit_and_deref;
  1145. }
  1146. //
  1147. // In case the image file name of this system process is ever queried, we give
  1148. // a zero length UNICODE_STRING.
  1149. //
  1150. Process->SeAuditProcessCreationInfo.ImageFileName =
  1151. ExAllocatePoolWithTag (PagedPool,
  1152. sizeof(OBJECT_NAME_INFORMATION),
  1153. 'aPeS');
  1154. if (Process->SeAuditProcessCreationInfo.ImageFileName != NULL) {
  1155. RtlZeroMemory (Process->SeAuditProcessCreationInfo.ImageFileName,
  1156. sizeof(OBJECT_NAME_INFORMATION));
  1157. } else {
  1158. Status = STATUS_INSUFFICIENT_RESOURCES;
  1159. goto exit_and_deref;
  1160. }
  1161. }
  1162. }
  1163. //
  1164. // Fix up the session ID just in case this was a cross session create
  1165. // We don't need to reference the token as we are creating the process.
  1166. //
  1167. SeSetSessionIdToken (ExFastRefGetObject (Process->Token), MmGetSessionId (Process));
  1168. //
  1169. // Create the process ID
  1170. //
  1171. CidEntry.Object = Process;
  1172. CidEntry.GrantedAccess = 0;
  1173. Process->UniqueProcessId = ExCreateHandle (PspCidTable, &CidEntry);
  1174. if (Process->UniqueProcessId == NULL) {
  1175. Status = STATUS_INSUFFICIENT_RESOURCES;
  1176. goto exit_and_deref;
  1177. }
  1178. ExSetHandleTableOwner (Process->ObjectTable, Process->UniqueProcessId);
  1179. //
  1180. // Audit the process creation.
  1181. //
  1182. if (SeDetailedAuditing) {
  1183. SeAuditProcessCreation (Process);
  1184. }
  1185. //
  1186. // See if the parent has a job. If so reference the job
  1187. // and add the process in.
  1188. //
  1189. if (Parent) {
  1190. Job = Parent->Job;
  1191. if (Job != NULL && !(Job->LimitFlags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)) {
  1192. if (Flags&PROCESS_CREATE_FLAGS_BREAKAWAY) {
  1193. if (!(Job->LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK)) {
  1194. Status = STATUS_ACCESS_DENIED;
  1195. } else {
  1196. Status = STATUS_SUCCESS;
  1197. }
  1198. } else {
  1199. Status = PspGetJobFromSet (Job, JobMemberLevel, &Process->Job);
  1200. if (NT_SUCCESS (Status)) {
  1201. PACCESS_TOKEN Token, NewToken;
  1202. Job = Process->Job;
  1203. Status = PspAddProcessToJob (Job, Process);
  1204. //
  1205. // Duplicate a new process token if one is specified for the job
  1206. //
  1207. Token = Job->Token;
  1208. if (Token != NULL) {
  1209. Status = SeSubProcessToken (Token,
  1210. &NewToken,
  1211. FALSE);
  1212. if (!NT_SUCCESS (Status)) {
  1213. goto exit_and_deref;
  1214. }
  1215. SeAssignPrimaryToken (Process, NewToken);
  1216. ObDereferenceObject (NewToken);
  1217. }
  1218. }
  1219. }
  1220. if (!NT_SUCCESS (Status)) {
  1221. goto exit_and_deref;
  1222. }
  1223. }
  1224. }
  1225. if (Parent && CreatePeb) {
  1226. //
  1227. // For processes created w/ a section,
  1228. // a new "virgin" PEB is created. Otherwise,
  1229. // for forked processes, uses inherited PEB
  1230. // with an updated mutant.
  1231. RtlZeroMemory (&InitialPeb, FIELD_OFFSET(INITIAL_PEB, Mutant));
  1232. InitialPeb.Mutant = (HANDLE)(-1);
  1233. if (SectionHandle != NULL) {
  1234. Status = MmCreatePeb (Process, &InitialPeb, &Process->Peb);
  1235. if (!NT_SUCCESS (Status)) {
  1236. Process->Peb = NULL;
  1237. goto exit_and_deref;
  1238. }
  1239. } else {
  1240. SIZE_T BytesCopied;
  1241. InitialPeb.InheritedAddressSpace = TRUE;
  1242. Process->Peb = Parent->Peb;
  1243. MmCopyVirtualMemory (CurrentProcess,
  1244. &InitialPeb,
  1245. Process,
  1246. Process->Peb,
  1247. sizeof (INITIAL_PEB),
  1248. KernelMode,
  1249. &BytesCopied);
  1250. }
  1251. }
  1252. //
  1253. // Add the process to the global list of processes.
  1254. //
  1255. PspLockProcessList (CurrentThread);
  1256. InsertTailList (&PsActiveProcessHead, &Process->ActiveProcessLinks);
  1257. PspUnlockProcessList (CurrentThread);
  1258. //
  1259. // Insert the object. Once we do this is reachable from the outside world via
  1260. // open by name. Open by ID is still disabled. Since its reachable
  1261. // somebody might create a thread in the process and cause
  1262. // rundown.
  1263. //
  1264. Status = ObInsertObject (Process,
  1265. NULL,
  1266. DesiredAccess,
  1267. 1, // bias the refcnt by one for future process manipulations
  1268. NULL,
  1269. &LocalProcessHandle);
  1270. if (!NT_SUCCESS (Status)) {
  1271. goto exit_and_deref_parent;
  1272. }
  1273. //
  1274. // As soon as we create the handle the process is accessible to the outside world. Allow the process to
  1275. // be deleted.
  1276. //
  1277. Process->GrantedAccess = PROCESS_TERMINATE;
  1278. PsSetProcessPriorityByClass (Process, PsProcessPriorityBackground);
  1279. if (Parent && Parent != PsInitialSystemProcess) {
  1280. Status = ObGetObjectSecurity (Process,
  1281. &SecurityDescriptor,
  1282. &MemoryAllocated);
  1283. if (!NT_SUCCESS (Status)) {
  1284. ObCloseHandle (LocalProcessHandle, PreviousMode);
  1285. goto exit_and_deref;
  1286. }
  1287. //
  1288. // Compute the subject security context
  1289. //
  1290. SubjectContext.ProcessAuditId = Process;
  1291. SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
  1292. SubjectContext.ClientToken = NULL;
  1293. AccessCheck = SeAccessCheck (SecurityDescriptor,
  1294. &SubjectContext,
  1295. FALSE,
  1296. MAXIMUM_ALLOWED,
  1297. 0,
  1298. NULL,
  1299. &PsProcessType->TypeInfo.GenericMapping,
  1300. PreviousMode,
  1301. &Process->GrantedAccess,
  1302. &accesst);
  1303. PsDereferencePrimaryTokenEx (Process, SubjectContext.PrimaryToken);
  1304. ObReleaseObjectSecurity (SecurityDescriptor,
  1305. MemoryAllocated);
  1306. if (!AccessCheck) {
  1307. Process->GrantedAccess = 0;
  1308. }
  1309. //
  1310. // It does not make any sense to create a process that can not
  1311. // do anything to itself.
  1312. // Note: Changes to this set of bits should be reflected in psquery.c
  1313. // code, in PspSetPrimaryToken.
  1314. //
  1315. Process->GrantedAccess |= (PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_DUP_HANDLE | PROCESS_CREATE_PROCESS | PROCESS_SET_INFORMATION);
  1316. } else {
  1317. Process->GrantedAccess = PROCESS_ALL_ACCESS;
  1318. }
  1319. KeQuerySystemTime (&Process->CreateTime);
  1320. try {
  1321. *ProcessHandle = LocalProcessHandle;
  1322. } except (EXCEPTION_EXECUTE_HANDLER) {
  1323. }
  1324. if (SavedStatus != STATUS_SUCCESS) {
  1325. Status = SavedStatus;
  1326. }
  1327. exit_and_deref:
  1328. ObDereferenceObject (Process);
  1329. exit_and_deref_parent:
  1330. if (Parent != NULL) {
  1331. ObDereferenceObject (Parent);
  1332. }
  1333. return Status;
  1334. }
  1335. NTSTATUS
  1336. PsSetCreateProcessNotifyRoutine(
  1337. IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
  1338. IN BOOLEAN Remove
  1339. )
  1340. /*++
  1341. Routine Description:
  1342. This function allows an installable file system to hook into process
  1343. creation and deletion to track those events against their own internal
  1344. data structures.
  1345. Arguments:
  1346. NotifyRoutine - Supplies the address of a routine which is called at
  1347. process creation and deletion. The routine is passed the unique Id
  1348. of the created or deleted process and the parent process if it was
  1349. created with the inherit handles option. If it was created without
  1350. the inherit handle options, then the parent process Id will be NULL.
  1351. The third parameter passed to the notify routine is TRUE if the process
  1352. is being created and FALSE if it is being deleted.
  1353. The callout for creation happens just after the first thread in the
  1354. process has been created. The callout for deletion happens after the
  1355. last thread in a process has terminated and the address space is about
  1356. to be deleted. It is possible to get a deletion call without a creation
  1357. call if the pathological case where a process is created and deleted
  1358. without a thread ever being created.
  1359. Remove - FALSE specifies to install the callout and TRUE specifies to
  1360. remove the callout that mat
  1361. Return Value:
  1362. STATUS_SUCCESS if successful, and STATUS_INVALID_PARAMETER if not.
  1363. --*/
  1364. {
  1365. ULONG i;
  1366. PEX_CALLBACK_ROUTINE_BLOCK CallBack;
  1367. PAGED_CODE();
  1368. if (Remove) {
  1369. for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++) {
  1370. //
  1371. // Reference the callback so we can check its routine address.
  1372. //
  1373. CallBack = ExReferenceCallBackBlock (&PspCreateProcessNotifyRoutine[i]);
  1374. if (CallBack != NULL) {
  1375. //
  1376. // See if the routine matches our target
  1377. //
  1378. if ((PCREATE_PROCESS_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack) == NotifyRoutine) {
  1379. if (ExCompareExchangeCallBack (&PspCreateProcessNotifyRoutine[i],
  1380. NULL,
  1381. CallBack)) {
  1382. InterlockedDecrement ((PLONG) &PspCreateProcessNotifyRoutineCount);
  1383. ExDereferenceCallBackBlock (&PspCreateProcessNotifyRoutine[i],
  1384. CallBack);
  1385. //
  1386. // Wait for any active callbacks to finish and free the block.
  1387. //
  1388. ExWaitForCallBacks (CallBack);
  1389. ExFreeCallBack (CallBack);
  1390. return STATUS_SUCCESS;
  1391. }
  1392. }
  1393. ExDereferenceCallBackBlock (&PspCreateProcessNotifyRoutine[i],
  1394. CallBack);
  1395. }
  1396. }
  1397. return STATUS_PROCEDURE_NOT_FOUND;
  1398. } else {
  1399. //
  1400. // Allocate a new callback block.
  1401. //
  1402. CallBack = ExAllocateCallBack ((PEX_CALLBACK_FUNCTION) NotifyRoutine, NULL);
  1403. if (CallBack == NULL) {
  1404. return STATUS_INSUFFICIENT_RESOURCES;
  1405. }
  1406. for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++) {
  1407. //
  1408. // Try and swap a null entry for the new block.
  1409. //
  1410. if (ExCompareExchangeCallBack (&PspCreateProcessNotifyRoutine[i],
  1411. CallBack,
  1412. NULL)) {
  1413. InterlockedIncrement ((PLONG) &PspCreateProcessNotifyRoutineCount);
  1414. return STATUS_SUCCESS;
  1415. }
  1416. }
  1417. //
  1418. // No slots left. Free the block and return.
  1419. //
  1420. ExFreeCallBack (CallBack);
  1421. return STATUS_INVALID_PARAMETER;
  1422. }
  1423. }
  1424. NTSTATUS
  1425. PsSetCreateThreadNotifyRoutine(
  1426. IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. This function allows an installable file system to hook into thread
  1431. creation and deletion to track those events against their own internal
  1432. data structures.
  1433. Arguments:
  1434. NotifyRoutine - Supplies the address of the routine which is called at
  1435. thread creation and deletion. The routine is passed the unique Id
  1436. of the created or deleted thread and the unique Id of the containing
  1437. process. The third parameter passed to the notify routine is TRUE if
  1438. the thread is being created and FALSE if it is being deleted.
  1439. Return Value:
  1440. STATUS_SUCCESS if successful, and STATUS_INSUFFICIENT_RESOURCES if not.
  1441. --*/
  1442. {
  1443. ULONG i;
  1444. PEX_CALLBACK_ROUTINE_BLOCK CallBack;
  1445. PAGED_CODE();
  1446. //
  1447. // Allocate a new callback block.
  1448. //
  1449. CallBack = ExAllocateCallBack ((PEX_CALLBACK_FUNCTION) NotifyRoutine, NULL);
  1450. if (CallBack == NULL) {
  1451. return STATUS_INSUFFICIENT_RESOURCES;
  1452. }
  1453. for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i += 1) {
  1454. //
  1455. // Try and swap a null entry for the new block.
  1456. //
  1457. if (ExCompareExchangeCallBack (&PspCreateThreadNotifyRoutine[i],
  1458. CallBack,
  1459. NULL)) {
  1460. InterlockedIncrement ((PLONG) &PspCreateThreadNotifyRoutineCount);
  1461. return STATUS_SUCCESS;
  1462. }
  1463. }
  1464. //
  1465. // No slots left. Free the block and return.
  1466. //
  1467. ExFreeCallBack (CallBack);
  1468. return STATUS_INSUFFICIENT_RESOURCES;
  1469. }
  1470. NTSTATUS
  1471. PsRemoveCreateThreadNotifyRoutine (
  1472. IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine
  1473. )
  1474. /*++
  1475. Routine Description:
  1476. This function allows an installable file system to unhook from thread
  1477. creation and deletion.
  1478. Arguments:
  1479. NotifyRoutine - Supplies the address of the routine which was previously
  1480. registered with PsSetCreateThreadNotifyRoutine
  1481. Return Value:
  1482. STATUS_SUCCESS if successful, and STATUS_PROCEDURE_NOT_FOUND if not.
  1483. --*/
  1484. {
  1485. ULONG i;
  1486. PEX_CALLBACK_ROUTINE_BLOCK CallBack;
  1487. PAGED_CODE();
  1488. for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i += 1) {
  1489. //
  1490. // Reference the callback so we can check its routine address.
  1491. //
  1492. CallBack = ExReferenceCallBackBlock (&PspCreateThreadNotifyRoutine[i]);
  1493. if (CallBack != NULL) {
  1494. //
  1495. // See if the routine matches our target
  1496. //
  1497. if ((PCREATE_THREAD_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack) == NotifyRoutine) {
  1498. if (ExCompareExchangeCallBack (&PspCreateThreadNotifyRoutine[i],
  1499. NULL,
  1500. CallBack)) {
  1501. InterlockedDecrement ((PLONG) &PspCreateThreadNotifyRoutineCount);
  1502. ExDereferenceCallBackBlock (&PspCreateThreadNotifyRoutine[i],
  1503. CallBack);
  1504. //
  1505. // Wait for any active callbacks to finish and free the block.
  1506. //
  1507. ExWaitForCallBacks (CallBack);
  1508. ExFreeCallBack (CallBack);
  1509. return STATUS_SUCCESS;
  1510. }
  1511. }
  1512. ExDereferenceCallBackBlock (&PspCreateThreadNotifyRoutine[i],
  1513. CallBack);
  1514. }
  1515. }
  1516. return STATUS_PROCEDURE_NOT_FOUND;
  1517. }
  1518. VOID
  1519. PspUserThreadStartup(
  1520. IN PKSTART_ROUTINE StartRoutine,
  1521. IN PVOID StartContext
  1522. )
  1523. /*++
  1524. Routine Description:
  1525. This function is called by the kernel to start a user-mode thread.
  1526. Arguments:
  1527. StartRoutine - Ignored.
  1528. StartContext - Supplies the initial pc value for the thread.
  1529. Return Value:
  1530. None.
  1531. --*/
  1532. {
  1533. PETHREAD Thread;
  1534. PEPROCESS Process;
  1535. PTEB Teb;
  1536. NTSTATUS KillStatus = STATUS_THREAD_IS_TERMINATING;
  1537. ULONG OldFlags;
  1538. BOOLEAN KillThread;
  1539. PAGED_CODE();
  1540. UNREFERENCED_PARAMETER(StartRoutine);
  1541. Thread = PsGetCurrentThread ();
  1542. Process = PsGetCurrentProcessByThread (Thread);
  1543. //
  1544. // All threads start with an APC at LdrInitializeThunk
  1545. //
  1546. MmAllowWorkingSetExpansion();
  1547. KillThread = FALSE;
  1548. if ((Thread->CrossThreadFlags & (PS_CROSS_THREAD_FLAGS_TERMINATED|PS_CROSS_THREAD_FLAGS_DEADTHREAD)) != 0) {
  1549. KillThread = TRUE;
  1550. }
  1551. //
  1552. // A process delete may hae been issued just before this thread got put into the thread list.
  1553. //
  1554. if (Process->Flags&PS_PROCESS_FLAGS_PROCESS_DELETE) {
  1555. KillThread = TRUE;
  1556. }
  1557. if (!KillThread) {
  1558. Teb = NtCurrentTeb ();
  1559. try {
  1560. Teb->CurrentLocale = MmGetSessionLocaleId ();
  1561. Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
  1562. } except (EXCEPTION_EXECUTE_HANDLER) {
  1563. }
  1564. //
  1565. // We just queued a user APC to this thread in the create path.
  1566. // User APCs won't fire until we do an alertable wait so we need
  1567. // to set this flag here.
  1568. //
  1569. Thread->Tcb.ApcState.UserApcPending = TRUE;
  1570. }
  1571. KeLowerIrql(0);
  1572. //
  1573. // If the create worked then notify the debugger.
  1574. //
  1575. if ((Thread->CrossThreadFlags&
  1576. (PS_CROSS_THREAD_FLAGS_DEADTHREAD|PS_CROSS_THREAD_FLAGS_HIDEFROMDBG)) == 0) {
  1577. DbgkCreateThread(StartContext);
  1578. }
  1579. //
  1580. // If something went wrong then terminate the thread
  1581. //
  1582. if (KillThread) {
  1583. PspTerminateThreadByPointer (Thread,
  1584. KillStatus);
  1585. } else {
  1586. if (CCPF_IS_PREFETCHER_ENABLED()) {
  1587. //
  1588. // If this is the first thread we are starting up in this process,
  1589. // prefetch the pages likely to be used when initializing the
  1590. // application into the system cache.
  1591. //
  1592. if ((Process->Flags & PS_PROCESS_FLAGS_LAUNCH_PREFETCHED) == 0) {
  1593. OldFlags = PS_TEST_SET_BITS(&Process->Flags, PS_PROCESS_FLAGS_LAUNCH_PREFETCHED);
  1594. if ((OldFlags & PS_PROCESS_FLAGS_LAUNCH_PREFETCHED) == 0) {
  1595. if (Process->SectionObject) {
  1596. //
  1597. // Notify cache manager of this application launch.
  1598. //
  1599. CcPfBeginAppLaunch(Process, Process->SectionObject);
  1600. }
  1601. }
  1602. }
  1603. }
  1604. }
  1605. if (Process->Pcb.UserTime == 0) {
  1606. Process->Pcb.UserTime = 1;
  1607. }
  1608. }
  1609. ULONG
  1610. PspUnhandledExceptionInSystemThread(
  1611. IN PEXCEPTION_POINTERS ExceptionPointers
  1612. )
  1613. {
  1614. KdPrint(("PS: Unhandled Kernel Mode Exception Pointers = 0x%p\n", ExceptionPointers));
  1615. KdPrint(("Code %x Addr %p Info0 %p Info1 %p Info2 %p Info3 %p\n",
  1616. ExceptionPointers->ExceptionRecord->ExceptionCode,
  1617. (ULONG_PTR)ExceptionPointers->ExceptionRecord->ExceptionAddress,
  1618. ExceptionPointers->ExceptionRecord->ExceptionInformation[0],
  1619. ExceptionPointers->ExceptionRecord->ExceptionInformation[1],
  1620. ExceptionPointers->ExceptionRecord->ExceptionInformation[2],
  1621. ExceptionPointers->ExceptionRecord->ExceptionInformation[3]
  1622. ));
  1623. KeBugCheckEx(
  1624. SYSTEM_THREAD_EXCEPTION_NOT_HANDLED,
  1625. ExceptionPointers->ExceptionRecord->ExceptionCode,
  1626. (ULONG_PTR)ExceptionPointers->ExceptionRecord->ExceptionAddress,
  1627. (ULONG_PTR)ExceptionPointers->ExceptionRecord,
  1628. (ULONG_PTR)ExceptionPointers->ContextRecord);
  1629. // return EXCEPTION_EXECUTE_HANDLER;
  1630. }
  1631. // PspUnhandledExceptionInSystemThread doesn't return, and the compiler
  1632. // sometimes gives 'unreachable code' warnings as a result.
  1633. #pragma warning(push)
  1634. #pragma warning(disable:4702)
  1635. VOID
  1636. PspSystemThreadStartup(
  1637. IN PKSTART_ROUTINE StartRoutine,
  1638. IN PVOID StartContext
  1639. )
  1640. /*++
  1641. Routine Description:
  1642. This function is called by the kernel to start a system thread.
  1643. Arguments:
  1644. StartRoutine - Supplies the address of the system threads entry point.
  1645. StartContext - Supplies a context value for the system thread.
  1646. Return Value:
  1647. None.
  1648. --*/
  1649. {
  1650. PETHREAD Thread;
  1651. MmAllowWorkingSetExpansion();
  1652. KeLowerIrql(0);
  1653. Thread = PsGetCurrentThread();
  1654. try {
  1655. if ((Thread->CrossThreadFlags&(PS_CROSS_THREAD_FLAGS_TERMINATED|PS_CROSS_THREAD_FLAGS_DEADTHREAD)) == 0) {
  1656. (StartRoutine)(StartContext);
  1657. }
  1658. } except (PspUnhandledExceptionInSystemThread(GetExceptionInformation())) {
  1659. KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
  1660. }
  1661. PspTerminateThreadByPointer (Thread, STATUS_SUCCESS);
  1662. }
  1663. #pragma warning(pop)
  1664. HANDLE
  1665. PsGetCurrentProcessId( VOID )
  1666. {
  1667. return PsGetCurrentThread()->Cid.UniqueProcess;
  1668. }
  1669. HANDLE
  1670. PsGetCurrentThreadId( VOID )
  1671. {
  1672. return PsGetCurrentThread()->Cid.UniqueThread;
  1673. }
  1674. BOOLEAN
  1675. PsGetVersion(
  1676. PULONG MajorVersion OPTIONAL,
  1677. PULONG MinorVersion OPTIONAL,
  1678. PULONG BuildNumber OPTIONAL,
  1679. PUNICODE_STRING CSDVersion OPTIONAL
  1680. )
  1681. {
  1682. if (ARGUMENT_PRESENT(MajorVersion)) {
  1683. *MajorVersion = NtMajorVersion;
  1684. }
  1685. if (ARGUMENT_PRESENT(MinorVersion)) {
  1686. *MinorVersion = NtMinorVersion;
  1687. }
  1688. if (ARGUMENT_PRESENT(BuildNumber)) {
  1689. *BuildNumber = NtBuildNumber & 0x3FFF;
  1690. }
  1691. if (ARGUMENT_PRESENT(CSDVersion)) {
  1692. *CSDVersion = CmCSDVersionString;
  1693. }
  1694. return (BOOLEAN)((NtBuildNumber >> 28) == 0xC);
  1695. }
  1696. NTSTATUS
  1697. PsSetLoadImageNotifyRoutine(
  1698. IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine
  1699. )
  1700. /*++
  1701. Routine Description:
  1702. This function allows a device driver to get notified for
  1703. image loads. The notify is issued for both kernel and user
  1704. mode image loads system-wide.
  1705. Arguments:
  1706. NotifyRoutine - Supplies the address of a routine which is called at
  1707. image load. The routine is passed information describing the
  1708. image being loaded.
  1709. The callout for creation happens just after the image is loaded
  1710. into memory but before executiona of the image.
  1711. Return Value:
  1712. STATUS_SUCCESS if successful, and STATUS_INVALID_PARAMETER if not.
  1713. --*/
  1714. {
  1715. ULONG i;
  1716. PEX_CALLBACK_ROUTINE_BLOCK CallBack;
  1717. PAGED_CODE();
  1718. //
  1719. // Allocate a new callback block.
  1720. //
  1721. CallBack = ExAllocateCallBack ((PEX_CALLBACK_FUNCTION) NotifyRoutine, NULL);
  1722. if (CallBack == NULL) {
  1723. return STATUS_INSUFFICIENT_RESOURCES;
  1724. }
  1725. for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++) {
  1726. //
  1727. // Try and swap a null entry for the new block.
  1728. //
  1729. if (ExCompareExchangeCallBack (&PspLoadImageNotifyRoutine[i],
  1730. CallBack,
  1731. NULL)) {
  1732. InterlockedIncrement ((PLONG) &PspLoadImageNotifyRoutineCount);
  1733. PsImageNotifyEnabled = TRUE;
  1734. return STATUS_SUCCESS;
  1735. }
  1736. }
  1737. //
  1738. // No slots left. Free the block and return.
  1739. //
  1740. ExFreeCallBack (CallBack);
  1741. return STATUS_INSUFFICIENT_RESOURCES;
  1742. }
  1743. NTSTATUS
  1744. PsRemoveLoadImageNotifyRoutine(
  1745. IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine
  1746. )
  1747. /*++
  1748. Routine Description:
  1749. This function allows an installable file system to unhook from image
  1750. load notification.
  1751. Arguments:
  1752. NotifyRoutine - Supplies the address of the routine which was previously
  1753. registered with PsSetLoadImageNotifyRoutine
  1754. Return Value:
  1755. STATUS_SUCCESS if successful, and STATUS_PROCEDURE_NOT_FOUND if not.
  1756. --*/
  1757. {
  1758. ULONG i;
  1759. PEX_CALLBACK_ROUTINE_BLOCK CallBack;
  1760. PAGED_CODE();
  1761. for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++) {
  1762. //
  1763. // Reference the callback so we can check its routine address.
  1764. //
  1765. CallBack = ExReferenceCallBackBlock (&PspLoadImageNotifyRoutine[i]);
  1766. if (CallBack != NULL) {
  1767. //
  1768. // See if the routine matches our target
  1769. //
  1770. if ((PLOAD_IMAGE_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack) == NotifyRoutine) {
  1771. if (ExCompareExchangeCallBack (&PspLoadImageNotifyRoutine[i],
  1772. NULL,
  1773. CallBack)) {
  1774. InterlockedDecrement ((PLONG) &PspLoadImageNotifyRoutineCount);
  1775. ExDereferenceCallBackBlock (&PspLoadImageNotifyRoutine[i],
  1776. CallBack);
  1777. //
  1778. // Wait for any active callbacks to finish and free the block.
  1779. //
  1780. ExWaitForCallBacks (CallBack);
  1781. ExFreeCallBack (CallBack);
  1782. return STATUS_SUCCESS;
  1783. }
  1784. }
  1785. ExDereferenceCallBackBlock (&PspLoadImageNotifyRoutine[i],
  1786. CallBack);
  1787. }
  1788. }
  1789. return STATUS_PROCEDURE_NOT_FOUND;
  1790. }
  1791. VOID
  1792. PsCallImageNotifyRoutines(
  1793. IN PUNICODE_STRING FullImageName,
  1794. IN HANDLE ProcessId, // pid into which image is being mapped
  1795. IN PIMAGE_INFO ImageInfo
  1796. )
  1797. /*++
  1798. Routine Description:
  1799. This function actually calls the registered image notify functions (on behalf)
  1800. of mapview.c and sysload.c
  1801. Arguments:
  1802. FullImageName - The name of the image being loaded
  1803. ProcessId - The process that the image is being loaded into (0 for driver loads)
  1804. ImageInfo - Various flags for the image
  1805. Return Value:
  1806. None.
  1807. --*/
  1808. {
  1809. ULONG i;
  1810. PEX_CALLBACK_ROUTINE_BLOCK CallBack;
  1811. PLOAD_IMAGE_NOTIFY_ROUTINE Rtn;
  1812. PAGED_CODE();
  1813. if (PsImageNotifyEnabled) {
  1814. for (i=0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++) {
  1815. CallBack = ExReferenceCallBackBlock (&PspLoadImageNotifyRoutine[i]);
  1816. if (CallBack != NULL) {
  1817. Rtn = (PLOAD_IMAGE_NOTIFY_ROUTINE) ExGetCallBackBlockRoutine (CallBack);
  1818. Rtn (FullImageName,
  1819. ProcessId,
  1820. ImageInfo);
  1821. ExDereferenceCallBackBlock (&PspLoadImageNotifyRoutine[i], CallBack);
  1822. }
  1823. }
  1824. }
  1825. }
  1826. VOID
  1827. PspImageNotifyTest(
  1828. IN PUNICODE_STRING FullImageName,
  1829. IN HANDLE ProcessId,
  1830. IN PIMAGE_INFO ImageInfo
  1831. )
  1832. /*++
  1833. Routine Description:
  1834. This function is registered as a image notify routine on checked systems to test the interface.
  1835. Arguments:
  1836. FullImageName - The name of the image being loaded
  1837. ProcessId - The process that the image is being loaded into (0 for driver loads)
  1838. ImageInfo - Various flags for the image
  1839. Return Value:
  1840. None.
  1841. --*/
  1842. {
  1843. UNREFERENCED_PARAMETER (FullImageName);
  1844. UNREFERENCED_PARAMETER (ProcessId);
  1845. UNREFERENCED_PARAMETER (ImageInfo);
  1846. return;
  1847. }