Leaked source code of windows server 2003
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.

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