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.

1526 lines
50 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. rtlexec.c
  5. Abstract:
  6. User Mode routines for creating user mode processes and threads.
  7. Author:
  8. Steve Wood (stevewo) 18-Aug-1989
  9. Environment:
  10. User Mode or Kernel Mode
  11. Revision History:
  12. --*/
  13. #include "ntrtlp.h"
  14. #include <nturtl.h>
  15. #include <string.h>
  16. #include "init.h"
  17. #include "ntos.h"
  18. #define ROUND_UP( x, y ) ((ULONG)(x) + ((y)-1) & ~((y)-1))
  19. #ifdef KERNEL
  20. #define ISTERMINALSERVER() (SharedUserData->SuiteMask & (1 << TerminalServer))
  21. #else
  22. #define ISTERMINALSERVER() (USER_SHARED_DATA->SuiteMask & (1 << TerminalServer))
  23. #endif
  24. VOID
  25. RtlpCopyProcString(
  26. IN OUT PWSTR *pDst,
  27. OUT PUNICODE_STRING DestString,
  28. IN PUNICODE_STRING SourceString,
  29. IN ULONG DstAlloc OPTIONAL
  30. );
  31. NTSTATUS
  32. RtlpOpenImageFile(
  33. IN PUNICODE_STRING ImagePathName,
  34. IN ULONG Attributes,
  35. OUT PHANDLE FileHandle,
  36. IN BOOLEAN ReportErrors
  37. );
  38. NTSTATUS
  39. RtlpFreeStack(
  40. IN HANDLE Process,
  41. IN PINITIAL_TEB InitialTeb
  42. );
  43. NTSTATUS
  44. RtlpCreateStack(
  45. IN HANDLE Process,
  46. IN SIZE_T MaximumStackSize OPTIONAL,
  47. IN SIZE_T CommittedStackSize OPTIONAL,
  48. IN ULONG ZeroBits OPTIONAL,
  49. OUT PINITIAL_TEB InitialTeb
  50. );
  51. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  52. #pragma alloc_text(INIT,RtlpCopyProcString )
  53. #pragma alloc_text(INIT,RtlCreateProcessParameters )
  54. #pragma alloc_text(INIT,RtlDestroyProcessParameters )
  55. #pragma alloc_text(INIT,RtlNormalizeProcessParams )
  56. #pragma alloc_text(INIT,RtlDeNormalizeProcessParams )
  57. #pragma alloc_text(INIT,RtlpOpenImageFile )
  58. #pragma alloc_text(PAGE,RtlpCreateStack )
  59. #pragma alloc_text(PAGE,RtlpFreeStack )
  60. #pragma alloc_text(INIT,RtlCreateUserProcess )
  61. #pragma alloc_text(PAGE,RtlCreateUserThread )
  62. #pragma alloc_text(INIT,RtlExitUserThread )
  63. #endif
  64. #if defined(ALLOC_DATA_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  65. #pragma const_seg("INITCONST")
  66. #endif
  67. const UNICODE_STRING NullString = {0, 1, L""};
  68. VOID
  69. RtlpCopyProcString(
  70. IN OUT PWSTR *pDst,
  71. OUT PUNICODE_STRING DestString,
  72. IN PUNICODE_STRING SourceString,
  73. IN ULONG DstAlloc OPTIONAL
  74. )
  75. {
  76. if (!ARGUMENT_PRESENT( DstAlloc )) {
  77. DstAlloc = SourceString->MaximumLength;
  78. }
  79. ASSERT((SourceString->Length == 0) || (SourceString->Buffer != NULL));
  80. if (SourceString->Buffer != NULL && SourceString->Length != 0) {
  81. RtlCopyMemory (*pDst,
  82. SourceString->Buffer,
  83. SourceString->Length);
  84. }
  85. DestString->Buffer = *pDst;
  86. DestString->Length = SourceString->Length;
  87. DestString->MaximumLength = (USHORT)DstAlloc;
  88. if (DestString->Length < DestString->MaximumLength) {
  89. RtlZeroMemory (((PUCHAR)DestString->Buffer) + DestString->Length, DestString->MaximumLength - DestString->Length);
  90. }
  91. *pDst = (PWSTR)((PCHAR)(*pDst) + ROUND_UP( DstAlloc, sizeof( ULONG ) ) );
  92. return;
  93. }
  94. NTSTATUS
  95. RtlCreateProcessParameters(
  96. OUT PRTL_USER_PROCESS_PARAMETERS *pProcessParameters,
  97. IN PUNICODE_STRING ImagePathName,
  98. IN PUNICODE_STRING DllPath OPTIONAL,
  99. IN PUNICODE_STRING CurrentDirectory OPTIONAL,
  100. IN PUNICODE_STRING CommandLine OPTIONAL,
  101. IN PVOID Environment OPTIONAL,
  102. IN PUNICODE_STRING WindowTitle OPTIONAL,
  103. IN PUNICODE_STRING DesktopInfo OPTIONAL,
  104. IN PUNICODE_STRING ShellInfo OPTIONAL,
  105. IN PUNICODE_STRING RuntimeData OPTIONAL
  106. )
  107. /*++
  108. Routine Description:
  109. This function formats NT style RTL_USER_PROCESS_PARAMETERS
  110. record. The record is self-contained in a single block of memory
  111. allocated by this function. The allocation method is opaque and
  112. thus the record must be freed by calling the
  113. RtlDestroyProcessParameters function.
  114. The process parameters record is created in a de-normalized form,
  115. thus making it suitable for passing to the RtlCreateUserProcess
  116. function. It is expected that the caller will fill in additional
  117. fields in the process parameters record after this function returns,
  118. but prior to calling RtlCreateUserProcess.
  119. Arguments:
  120. pProcessParameters - Pointer to a variable that will receive the address
  121. of the process parameter structure created by this routinue. The
  122. memory for the structure is allocated in an opaque manner and must
  123. be freed by calling RtlDestroyProcessParameters.
  124. ImagePathName - Required parameter that is the fully qualified NT
  125. path name of the image file that will be used to create the process
  126. that will received these parameters.
  127. DllPath - An optional parameter that is an NT String variable pointing
  128. to the search path the NT Loader is to use in the target process
  129. when searching for Dll modules. If not specified, then the Dll
  130. search path is filled in from the current process's Dll search
  131. path.
  132. CurrentDirectory - An optional parameter that is an NT String variable
  133. pointing to the default directory string for the target process.
  134. If not specified, then the current directory string is filled in
  135. from the current process's current directory string.
  136. CommandLine - An optional parameter that is an NT String variable that
  137. will be passed to the target process as its command line. If not
  138. specified, then the command line passed to the target process will
  139. be a null string.
  140. Environment - An optional parameter that is an opaque pointer to an
  141. environment variable block of the type created by
  142. RtlCreateEnvironment routine. If not specified, then the target
  143. process will receive a copy of the calling process's environment
  144. variable block.
  145. WindowTitle - An optional parameter that is an NT String variable that
  146. points to the title string the target process is to use for its
  147. main window. If not specified, then a null string will be passed
  148. to the target process as its default window title.
  149. DesktopInfo - An optional parameter that is an NT String variable that
  150. contains uninterpreted data that is passed as is to the target
  151. process. If not specified, the target process will receive a
  152. pointer to an empty string.
  153. ShellInfo - An optional parameter that is an NT String variable that
  154. contains uninterpreted data that is passed as is to the target
  155. process. If not specified, the target process will receive a
  156. pointer to an empty string.
  157. RuntimeData - An optional parameter that is an NT String variable that
  158. contains uninterpreted data that is passed as is to the target
  159. process. If not specified, the target process will receive a
  160. pointer to an empty string.
  161. Return Value:
  162. STATUS_SUCCESS - The process parameters is De-Normalized and
  163. contains entries for each of the specified argument and variable
  164. strings.
  165. STATUS_BUFFER_TOO_SMALL - The specified process parameters buffer is
  166. too small to contain the argument and environment strings. The value
  167. of ProcessParameters->Length is modified to contain the buffer
  168. size needed to contain the argument and variable strings.
  169. --*/
  170. {
  171. PRTL_USER_PROCESS_PARAMETERS p;
  172. NTSTATUS Status;
  173. ULONG ByteCount;
  174. PWSTR pDst;
  175. PPEB Peb;
  176. PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  177. HANDLE CurDirHandle;
  178. BOOLEAN PebLockAcquired = FALSE;
  179. //
  180. // Acquire the Peb Lock for the duration while we copy information out
  181. // of it.
  182. //
  183. Peb = NtCurrentPeb();
  184. ProcessParameters = Peb->ProcessParameters;
  185. Status = STATUS_SUCCESS;
  186. p = NULL;
  187. CurDirHandle = NULL;
  188. try {
  189. //
  190. // Validate input parameters
  191. //
  192. #define VALIDATE_STRING_PARAMETER(_x) \
  193. do { \
  194. ASSERT(ARGUMENT_PRESENT((_x))); \
  195. if (!ARGUMENT_PRESENT((_x))) { \
  196. Status = STATUS_INVALID_PARAMETER; \
  197. leave; \
  198. } \
  199. if (ARGUMENT_PRESENT((_x))) { \
  200. ASSERT((_x)->MaximumLength >= (_x)->Length); \
  201. ASSERT(((_x)->Length == 0) || ((_x)->Buffer != NULL)); \
  202. if (((_x)->MaximumLength < (_x)->Length) || \
  203. (((_x)->Length != 0) && ((_x)->Buffer == NULL))) { \
  204. Status = STATUS_INVALID_PARAMETER; \
  205. leave; \
  206. } \
  207. } \
  208. } while (0)
  209. #define VALIDATE_OPTIONAL_STRING_PARAMETER(_x) \
  210. do { \
  211. if (ARGUMENT_PRESENT((_x))) { \
  212. ASSERT((_x)->MaximumLength >= (_x)->Length); \
  213. ASSERT(((_x)->Length == 0) || ((_x)->Buffer != NULL)); \
  214. if (((_x)->MaximumLength < (_x)->Length) || \
  215. (((_x)->Length != 0) && ((_x)->Buffer == NULL))) { \
  216. Status = STATUS_INVALID_PARAMETER; \
  217. leave; \
  218. } \
  219. } \
  220. } while (0)
  221. VALIDATE_STRING_PARAMETER (ImagePathName);
  222. VALIDATE_OPTIONAL_STRING_PARAMETER (DllPath);
  223. VALIDATE_OPTIONAL_STRING_PARAMETER (CurrentDirectory);
  224. VALIDATE_OPTIONAL_STRING_PARAMETER (CommandLine);
  225. VALIDATE_OPTIONAL_STRING_PARAMETER (WindowTitle);
  226. VALIDATE_OPTIONAL_STRING_PARAMETER (DesktopInfo);
  227. VALIDATE_OPTIONAL_STRING_PARAMETER (ShellInfo);
  228. VALIDATE_OPTIONAL_STRING_PARAMETER (RuntimeData);
  229. #undef VALIDATE_STRING_PARAMETER
  230. #undef VALIDATE_OPTIONAL_STRING_PARAMETER
  231. if (!ARGUMENT_PRESENT (CommandLine)) {
  232. CommandLine = ImagePathName;
  233. }
  234. if (!ARGUMENT_PRESENT (WindowTitle)) {
  235. WindowTitle = (PUNICODE_STRING)&NullString;
  236. }
  237. if (!ARGUMENT_PRESENT (DesktopInfo)) {
  238. DesktopInfo = (PUNICODE_STRING)&NullString;
  239. }
  240. if (!ARGUMENT_PRESENT (ShellInfo)) {
  241. ShellInfo = (PUNICODE_STRING)&NullString;
  242. }
  243. if (!ARGUMENT_PRESENT (RuntimeData)) {
  244. RuntimeData = (PUNICODE_STRING)&NullString;
  245. }
  246. //
  247. // Determine size need to contain the process parameter record
  248. // structure and all of the strings it will point to. Each string
  249. // will be aligned on a ULONG byte boundary.
  250. // We do the ones we can outside of the peb lock.
  251. //
  252. ByteCount = sizeof (*ProcessParameters);
  253. ByteCount += ROUND_UP (DOS_MAX_PATH_LENGTH*2, sizeof( ULONG ) );
  254. ByteCount += ROUND_UP (ImagePathName->Length + sizeof(UNICODE_NULL), sizeof( ULONG ) );
  255. ByteCount += ROUND_UP (CommandLine->Length + sizeof(UNICODE_NULL), sizeof( ULONG ) );
  256. ByteCount += ROUND_UP (WindowTitle->MaximumLength, sizeof( ULONG ) );
  257. ByteCount += ROUND_UP (DesktopInfo->MaximumLength, sizeof( ULONG ) );
  258. ByteCount += ROUND_UP (ShellInfo->MaximumLength, sizeof( ULONG ) );
  259. ByteCount += ROUND_UP (RuntimeData->MaximumLength, sizeof( ULONG ) );
  260. PebLockAcquired = TRUE;
  261. RtlAcquirePebLock ();
  262. //
  263. // For optional pointer parameters, default them to point to their
  264. // corresponding field in the current process's process parameter
  265. // structure or to a null string.
  266. //
  267. if (!ARGUMENT_PRESENT (DllPath)) {
  268. DllPath = &ProcessParameters->DllPath;
  269. }
  270. if (!ARGUMENT_PRESENT (CurrentDirectory)) {
  271. if (ProcessParameters->CurrentDirectory.Handle) {
  272. CurDirHandle = (HANDLE)((ULONG_PTR)ProcessParameters->CurrentDirectory.Handle & ~OBJ_HANDLE_TAGBITS);
  273. CurDirHandle = (HANDLE)((ULONG_PTR)CurDirHandle | RTL_USER_PROC_CURDIR_INHERIT);
  274. }
  275. CurrentDirectory = &ProcessParameters->CurrentDirectory.DosPath;
  276. } else {
  277. ASSERT(CurrentDirectory->MaximumLength >= CurrentDirectory->Length);
  278. ASSERT((CurrentDirectory->Length == 0) || (CurrentDirectory->Buffer != NULL));
  279. if (ProcessParameters->CurrentDirectory.Handle) {
  280. CurDirHandle = (HANDLE)((ULONG_PTR)ProcessParameters->CurrentDirectory.Handle & ~OBJ_HANDLE_TAGBITS);
  281. CurDirHandle = (HANDLE)((ULONG_PTR)CurDirHandle | RTL_USER_PROC_CURDIR_CLOSE);
  282. }
  283. }
  284. if (!ARGUMENT_PRESENT (Environment)) {
  285. Environment = ProcessParameters->Environment;
  286. }
  287. ByteCount += ROUND_UP (DllPath->MaximumLength, sizeof( ULONG ) );
  288. //
  289. // Allocate memory for the process parameter record.
  290. //
  291. p = RtlAllocateHeap (RtlProcessHeap (), 0, ByteCount);
  292. if (p == NULL) {
  293. Status = STATUS_INSUFFICIENT_RESOURCES;
  294. __leave;
  295. }
  296. RtlZeroMemory (p, sizeof (*p));
  297. p->MaximumLength = ByteCount;
  298. p->Length = ByteCount;
  299. p->Flags = RTL_USER_PROC_PARAMS_NORMALIZED;
  300. p->DebugFlags = 0;
  301. p->Environment = Environment;
  302. p->CurrentDirectory.Handle = CurDirHandle;
  303. //
  304. // Inherits ^C inhibit information
  305. //
  306. p->ConsoleFlags = ProcessParameters->ConsoleFlags;
  307. pDst = (PWSTR)(p + 1);
  308. RtlpCopyProcString (&pDst,
  309. &p->CurrentDirectory.DosPath,
  310. CurrentDirectory,
  311. DOS_MAX_PATH_LENGTH*2);
  312. RtlpCopyProcString (&pDst, &p->DllPath, DllPath, 0);
  313. RtlpCopyProcString (&pDst, &p->ImagePathName, ImagePathName, ImagePathName->Length + sizeof (UNICODE_NULL));
  314. if (CommandLine->Length == CommandLine->MaximumLength) {
  315. RtlpCopyProcString (&pDst, &p->CommandLine, CommandLine, 0);
  316. } else {
  317. RtlpCopyProcString (&pDst, &p->CommandLine, CommandLine, CommandLine->Length + sizeof (UNICODE_NULL));
  318. }
  319. RtlpCopyProcString (&pDst, &p->WindowTitle, WindowTitle, 0);
  320. RtlpCopyProcString (&pDst, &p->DesktopInfo, DesktopInfo, 0);
  321. RtlpCopyProcString (&pDst, &p->ShellInfo, ShellInfo, 0);
  322. if (RuntimeData->Length != 0) {
  323. RtlpCopyProcString (&pDst, &p->RuntimeData, RuntimeData, 0);
  324. }
  325. *pProcessParameters = RtlDeNormalizeProcessParams (p);
  326. p = NULL;
  327. } finally {
  328. if (PebLockAcquired) {
  329. RtlReleasePebLock();
  330. }
  331. if (AbnormalTermination ()) {
  332. Status = STATUS_ACCESS_VIOLATION;
  333. }
  334. if (p != NULL) {
  335. RtlDestroyProcessParameters (p);
  336. }
  337. }
  338. return Status;
  339. }
  340. NTSTATUS
  341. RtlDestroyProcessParameters(
  342. IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters
  343. )
  344. {
  345. RtlFreeHeap (RtlProcessHeap (), 0, ProcessParameters);
  346. return STATUS_SUCCESS;
  347. }
  348. #define RtlpNormalizeProcessParam( Base, p ) \
  349. if ((p) != NULL) { \
  350. (p) = (PWSTR)((PCHAR)(p) + (ULONG_PTR)(Base)); \
  351. } \
  352. #define RtlpDeNormalizeProcessParam( Base, p ) \
  353. if ((p) != NULL) { \
  354. (p) = (PWSTR)((PCHAR)(p) - (ULONG_PTR)(Base)); \
  355. } \
  356. PRTL_USER_PROCESS_PARAMETERS
  357. RtlNormalizeProcessParams(
  358. IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters
  359. )
  360. {
  361. if (!ARGUMENT_PRESENT( ProcessParameters )) {
  362. return( NULL );
  363. }
  364. if (ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED) {
  365. return( ProcessParameters );
  366. }
  367. RtlpNormalizeProcessParam( ProcessParameters,
  368. ProcessParameters->CurrentDirectory.DosPath.Buffer
  369. );
  370. RtlpNormalizeProcessParam( ProcessParameters,
  371. ProcessParameters->DllPath.Buffer
  372. );
  373. RtlpNormalizeProcessParam( ProcessParameters,
  374. ProcessParameters->ImagePathName.Buffer
  375. );
  376. RtlpNormalizeProcessParam( ProcessParameters,
  377. ProcessParameters->CommandLine.Buffer
  378. );
  379. RtlpNormalizeProcessParam( ProcessParameters,
  380. ProcessParameters->WindowTitle.Buffer
  381. );
  382. RtlpNormalizeProcessParam( ProcessParameters,
  383. ProcessParameters->DesktopInfo.Buffer
  384. );
  385. RtlpNormalizeProcessParam( ProcessParameters,
  386. ProcessParameters->ShellInfo.Buffer
  387. );
  388. RtlpNormalizeProcessParam( ProcessParameters,
  389. ProcessParameters->RuntimeData.Buffer
  390. );
  391. ProcessParameters->Flags |= RTL_USER_PROC_PARAMS_NORMALIZED;
  392. return( ProcessParameters );
  393. }
  394. PRTL_USER_PROCESS_PARAMETERS
  395. RtlDeNormalizeProcessParams(
  396. IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters
  397. )
  398. {
  399. if (!ARGUMENT_PRESENT( ProcessParameters )) {
  400. return( NULL );
  401. }
  402. if (!(ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) {
  403. return( ProcessParameters );
  404. }
  405. RtlpDeNormalizeProcessParam( ProcessParameters,
  406. ProcessParameters->CurrentDirectory.DosPath.Buffer
  407. );
  408. RtlpDeNormalizeProcessParam( ProcessParameters,
  409. ProcessParameters->DllPath.Buffer
  410. );
  411. RtlpDeNormalizeProcessParam( ProcessParameters,
  412. ProcessParameters->ImagePathName.Buffer
  413. );
  414. RtlpDeNormalizeProcessParam( ProcessParameters,
  415. ProcessParameters->CommandLine.Buffer
  416. );
  417. RtlpDeNormalizeProcessParam( ProcessParameters,
  418. ProcessParameters->WindowTitle.Buffer
  419. );
  420. RtlpDeNormalizeProcessParam( ProcessParameters,
  421. ProcessParameters->DesktopInfo.Buffer
  422. );
  423. RtlpDeNormalizeProcessParam( ProcessParameters,
  424. ProcessParameters->ShellInfo.Buffer
  425. );
  426. RtlpDeNormalizeProcessParam( ProcessParameters,
  427. ProcessParameters->RuntimeData.Buffer
  428. );
  429. ProcessParameters->Flags &= ~RTL_USER_PROC_PARAMS_NORMALIZED;
  430. return( ProcessParameters );
  431. }
  432. NTSTATUS
  433. RtlpOpenImageFile(
  434. IN PUNICODE_STRING ImagePathName,
  435. IN ULONG Attributes,
  436. OUT PHANDLE FileHandle,
  437. IN BOOLEAN ReportErrors
  438. )
  439. {
  440. NTSTATUS Status;
  441. OBJECT_ATTRIBUTES ObjectAttributes;
  442. HANDLE File;
  443. IO_STATUS_BLOCK IoStatus;
  444. *FileHandle = NULL;
  445. InitializeObjectAttributes( &ObjectAttributes,
  446. ImagePathName,
  447. Attributes,
  448. NULL,
  449. NULL
  450. );
  451. Status = ZwOpenFile( &File,
  452. SYNCHRONIZE | FILE_EXECUTE,
  453. &ObjectAttributes,
  454. &IoStatus,
  455. FILE_SHARE_READ | FILE_SHARE_DELETE,
  456. FILE_NON_DIRECTORY_FILE
  457. );
  458. if (!NT_SUCCESS( Status )) {
  459. #if DBG
  460. if (ReportErrors) {
  461. DbgPrint( "NTRTL: RtlpOpenImageFile - NtCreateFile( %wZ ) failed. Status == %X\n",
  462. ImagePathName,
  463. Status
  464. );
  465. }
  466. #endif // DBG
  467. return( Status );
  468. }
  469. *FileHandle = File;
  470. return( STATUS_SUCCESS );
  471. }
  472. NTSTATUS
  473. RtlpCreateStack(
  474. IN HANDLE Process,
  475. IN SIZE_T MaximumStackSize OPTIONAL,
  476. IN SIZE_T CommittedStackSize OPTIONAL,
  477. IN ULONG ZeroBits OPTIONAL,
  478. OUT PINITIAL_TEB InitialTeb
  479. )
  480. {
  481. NTSTATUS Status;
  482. PCH Stack;
  483. SYSTEM_BASIC_INFORMATION SysInfo;
  484. BOOLEAN GuardPage;
  485. SIZE_T RegionSize;
  486. ULONG OldProtect;
  487. #if defined(_IA64_)
  488. PCH Bstore;
  489. SIZE_T CommittedBstoreSize;
  490. SIZE_T MaximumBstoreSize;
  491. SIZE_T MstackPlusBstoreSize;
  492. #endif
  493. Status = ZwQuerySystemInformation( SystemBasicInformation,
  494. (PVOID)&SysInfo,
  495. sizeof( SysInfo ),
  496. NULL
  497. );
  498. if ( !NT_SUCCESS( Status ) ) {
  499. return( Status );
  500. }
  501. //
  502. // if stack is in the current process, then default to
  503. // the parameters from the image
  504. //
  505. if ( Process == NtCurrentProcess() ) {
  506. PPEB Peb;
  507. PIMAGE_NT_HEADERS NtHeaders;
  508. Peb = NtCurrentPeb();
  509. NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
  510. if (!NtHeaders) {
  511. return STATUS_INVALID_IMAGE_FORMAT;
  512. }
  513. if (!MaximumStackSize) {
  514. MaximumStackSize = NtHeaders->OptionalHeader.SizeOfStackReserve;
  515. }
  516. if (!CommittedStackSize) {
  517. CommittedStackSize = NtHeaders->OptionalHeader.SizeOfStackCommit;
  518. }
  519. }
  520. else {
  521. if (!CommittedStackSize) {
  522. CommittedStackSize = SysInfo.PageSize;
  523. }
  524. if (!MaximumStackSize) {
  525. MaximumStackSize = SysInfo.AllocationGranularity;
  526. }
  527. }
  528. //
  529. // Enforce a minimal stack commit if there is a PEB setting
  530. // for this.
  531. //
  532. #if !defined(NTOS_KERNEL_RUNTIME)
  533. {
  534. SIZE_T MinimumStackCommit;
  535. MinimumStackCommit = NtCurrentPeb()->MinimumStackCommit;
  536. if (MinimumStackCommit != 0 && CommittedStackSize < MinimumStackCommit) {
  537. CommittedStackSize = MinimumStackCommit;
  538. }
  539. }
  540. #endif
  541. if ( CommittedStackSize >= MaximumStackSize ) {
  542. MaximumStackSize = ROUND_UP(CommittedStackSize, (1024*1024));
  543. }
  544. CommittedStackSize = ROUND_UP( CommittedStackSize, SysInfo.PageSize );
  545. MaximumStackSize = ROUND_UP( MaximumStackSize,
  546. SysInfo.AllocationGranularity
  547. );
  548. Stack = NULL;
  549. #if defined(_IA64_)
  550. //
  551. // Piggyback the backing store with the memory stack
  552. //
  553. CommittedBstoreSize = CommittedStackSize;
  554. MaximumBstoreSize = MaximumStackSize;
  555. MstackPlusBstoreSize = MaximumBstoreSize + MaximumStackSize;
  556. Status = ZwAllocateVirtualMemory( Process,
  557. (PVOID *)&Stack,
  558. ZeroBits,
  559. &MstackPlusBstoreSize,
  560. MEM_RESERVE,
  561. PAGE_READWRITE
  562. );
  563. #else
  564. Status = ZwAllocateVirtualMemory( Process,
  565. (PVOID *)&Stack,
  566. ZeroBits,
  567. &MaximumStackSize,
  568. MEM_RESERVE,
  569. PAGE_READWRITE
  570. );
  571. #endif // defined(_IA64_)
  572. if ( !NT_SUCCESS( Status ) ) {
  573. #if DBG
  574. DbgPrint( "NTRTL: RtlpCreateStack( %lx ) failed. Stack Reservation Status == %X\n",
  575. Process,
  576. Status
  577. );
  578. #endif // DBG
  579. return( Status );
  580. }
  581. #if defined(_IA64_)
  582. InitialTeb->OldInitialTeb.OldBStoreLimit = NULL;
  583. #endif // defined(_IA64_)
  584. InitialTeb->OldInitialTeb.OldStackBase = NULL;
  585. InitialTeb->OldInitialTeb.OldStackLimit = NULL;
  586. InitialTeb->StackAllocationBase = Stack;
  587. InitialTeb->StackBase = Stack + MaximumStackSize;
  588. Stack += MaximumStackSize - CommittedStackSize;
  589. if (MaximumStackSize > CommittedStackSize) {
  590. Stack -= SysInfo.PageSize;
  591. CommittedStackSize += SysInfo.PageSize;
  592. GuardPage = TRUE;
  593. }
  594. else {
  595. GuardPage = FALSE;
  596. }
  597. Status = ZwAllocateVirtualMemory( Process,
  598. (PVOID *)&Stack,
  599. 0,
  600. &CommittedStackSize,
  601. MEM_COMMIT,
  602. PAGE_READWRITE
  603. );
  604. InitialTeb->StackLimit = Stack;
  605. if ( !NT_SUCCESS( Status ) ) {
  606. #if DBG
  607. DbgPrint( "NTRTL: RtlpCreateStack( %lx ) failed. Stack Commit Status == %X\n",
  608. Process,
  609. Status
  610. );
  611. #endif // DBG
  612. return( Status );
  613. }
  614. //
  615. // if we have space, create a guard page.
  616. //
  617. if (GuardPage) {
  618. RegionSize = SysInfo.PageSize;
  619. Status = ZwProtectVirtualMemory( Process,
  620. (PVOID *)&Stack,
  621. &RegionSize,
  622. PAGE_GUARD | PAGE_READWRITE,
  623. &OldProtect);
  624. if ( !NT_SUCCESS( Status ) ) {
  625. #if DBG
  626. DbgPrint( "NTRTL: RtlpCreateStack( %lx ) failed. Guard Page Creation Status == %X\n",
  627. Process,
  628. Status
  629. );
  630. #endif // DBG
  631. return( Status );
  632. }
  633. InitialTeb->StackLimit = (PVOID)((PUCHAR)InitialTeb->StackLimit + RegionSize);
  634. }
  635. #if defined(_IA64_)
  636. //
  637. // Commit backing store pages and create guard pages if there is space
  638. //
  639. Bstore = InitialTeb->StackBase;
  640. if (MaximumBstoreSize > CommittedBstoreSize) {
  641. CommittedBstoreSize += SysInfo.PageSize;
  642. GuardPage = TRUE;
  643. } else {
  644. GuardPage = FALSE;
  645. }
  646. Status = ZwAllocateVirtualMemory( Process,
  647. (PVOID *)&Bstore,
  648. 0,
  649. &CommittedBstoreSize,
  650. MEM_COMMIT,
  651. PAGE_READWRITE
  652. );
  653. InitialTeb->BStoreLimit = Bstore + CommittedBstoreSize;
  654. if ( !NT_SUCCESS(Status) ) {
  655. #if DBG
  656. DbgPrint("NTRTL: RtlpCreateStack( %lx ) failed. Backing Store Commit Status == %X\n",
  657. Process,
  658. Status
  659. );
  660. #endif // DBG
  661. return (Status);
  662. }
  663. if (GuardPage) {
  664. Bstore = (PCH)InitialTeb->BStoreLimit - SysInfo.PageSize;
  665. RegionSize = SysInfo.PageSize;
  666. Status = ZwProtectVirtualMemory(Process,
  667. (PVOID *)&Bstore,
  668. &RegionSize,
  669. PAGE_GUARD | PAGE_READWRITE,
  670. &OldProtect
  671. );
  672. if ( !NT_SUCCESS(Status) ) {
  673. #if DBG
  674. DbgPrint("NTRTL: RtlpCreateStack( %lx ) failed. Backing Store Guard Page Creation Status == %X\n",
  675. Process,
  676. Status
  677. );
  678. #endif // DBG
  679. return (Status);
  680. }
  681. InitialTeb->BStoreLimit = (PVOID)((PUCHAR)InitialTeb->BStoreLimit - RegionSize);
  682. }
  683. #endif // defined(_IA64_)
  684. return( STATUS_SUCCESS );
  685. }
  686. NTSTATUS
  687. RtlpFreeStack(
  688. IN HANDLE Process,
  689. IN PINITIAL_TEB InitialTeb
  690. )
  691. {
  692. NTSTATUS Status;
  693. SIZE_T Zero;
  694. Zero = 0;
  695. Status = ZwFreeVirtualMemory( Process,
  696. &InitialTeb->StackAllocationBase,
  697. &Zero,
  698. MEM_RELEASE
  699. );
  700. if ( !NT_SUCCESS( Status ) ) {
  701. #if DBG
  702. DbgPrint( "NTRTL: RtlpFreeStack( %lx ) failed. Stack DeCommit Status == %X\n",
  703. Process,
  704. Status
  705. );
  706. #endif // DBG
  707. return( Status );
  708. }
  709. RtlZeroMemory( InitialTeb, sizeof( *InitialTeb ) );
  710. return( STATUS_SUCCESS );
  711. }
  712. NTSTATUS
  713. RtlCreateUserProcess(
  714. IN PUNICODE_STRING NtImagePathName,
  715. IN ULONG Attributes,
  716. IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
  717. IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL,
  718. IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
  719. IN HANDLE ParentProcess OPTIONAL,
  720. IN BOOLEAN InheritHandles,
  721. IN HANDLE DebugPort OPTIONAL,
  722. IN HANDLE ExceptionPort OPTIONAL,
  723. OUT PRTL_USER_PROCESS_INFORMATION ProcessInformation
  724. )
  725. /*++
  726. Routine Description:
  727. This function creates a user mode process with a single thread with
  728. a suspend count of one. The address space of the new process is
  729. initialized with the contents of specified image file. The caller
  730. can specify the Access Control List for the new process and thread.
  731. The caller can also specify the parent process to inherit process
  732. priority and processor affinity from. The default is to inherit
  733. these from the current process. Finally the caller can specify
  734. whether the new process is to inherit any of the object handles
  735. from the specified parent process or not.
  736. Information about the new process and thread is returned via
  737. the ProcessInformation parameter.
  738. Arguments:
  739. NtImagePathName - A required pointer that points to the NT Path string
  740. that identifies the image file that is to be loaded into the
  741. child process.
  742. ProcessParameters - A required pointer that points to parameters that
  743. are to passed to the child process.
  744. ProcessSecurityDescriptor - An optional pointer to the Security Descriptor
  745. give to the new process.
  746. ThreadSecurityDescriptor - An optional pointer to the Security Descriptor
  747. give to the new thread.
  748. ParentProcess - An optional process handle that will used to inherit
  749. certain properties from.
  750. InheritHandles - A boolean value. TRUE specifies that object handles
  751. associated with the specified parent process are to be inherited
  752. by the new process, provided they have the OBJ_INHERIT attribute.
  753. FALSE specifies that the new process is to inherit no handles.
  754. DebugPort - An optional handle to the debug port associated with this
  755. process.
  756. ExceptionPort - An optional handle to the exception port associated with this
  757. process.
  758. ProcessInformation - A pointer to a variable that receives information
  759. about the new process and thread.
  760. Return Value:
  761. TBS.
  762. --*/
  763. {
  764. NTSTATUS Status;
  765. HANDLE Section, File;
  766. OBJECT_ATTRIBUTES ObjectAttributes;
  767. PRTL_USER_PROCESS_PARAMETERS Parameters;
  768. SIZE_T ParameterLength;
  769. PVOID Environment;
  770. PWCHAR s;
  771. SIZE_T EnvironmentLength;
  772. SIZE_T RegionSize;
  773. PROCESS_BASIC_INFORMATION ProcessInfo;
  774. PPEB Peb;
  775. UNICODE_STRING Unicode;
  776. //
  777. // Zero output parameter and probe the addresses at the same time
  778. //
  779. RtlZeroMemory( ProcessInformation, sizeof( *ProcessInformation ) );
  780. ProcessInformation->Length = sizeof( *ProcessInformation );
  781. //
  782. // Open the specified image file.
  783. //
  784. Status = RtlpOpenImageFile( NtImagePathName,
  785. Attributes & (OBJ_INHERIT | OBJ_CASE_INSENSITIVE),
  786. &File,
  787. TRUE
  788. );
  789. if (!NT_SUCCESS( Status )) {
  790. return( Status );
  791. }
  792. //
  793. // Create a memory section backed by the opened image file
  794. //
  795. Status = ZwCreateSection( &Section,
  796. SECTION_ALL_ACCESS,
  797. NULL,
  798. NULL,
  799. PAGE_EXECUTE,
  800. SEC_IMAGE,
  801. File
  802. );
  803. ZwClose( File );
  804. if ( !NT_SUCCESS( Status ) ) {
  805. return( Status );
  806. }
  807. //
  808. // Create the user mode process, defaulting the parent process to the
  809. // current process if one is not specified. The new process will not
  810. // have a name nor will the handle be inherited by other processes.
  811. //
  812. if (!ARGUMENT_PRESENT( ParentProcess )) {
  813. ParentProcess = NtCurrentProcess();
  814. }
  815. InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL,
  816. ProcessSecurityDescriptor );
  817. if ( RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG ) {
  818. if ( wcsstr(NtImagePathName->Buffer,L"csrss") ||
  819. wcsstr(NtImagePathName->Buffer,L"CSRSS")
  820. ) {
  821. //
  822. // For Hydra we don't name the CSRSS process to avoid name
  823. // collissions when multiple CSRSS's are started
  824. //
  825. if (ISTERMINALSERVER()) {
  826. InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL,
  827. ProcessSecurityDescriptor );
  828. } else {
  829. RtlInitUnicodeString(&Unicode,L"\\WindowsSS");
  830. InitializeObjectAttributes( &ObjectAttributes, &Unicode, 0, NULL,
  831. ProcessSecurityDescriptor );
  832. }
  833. }
  834. }
  835. if ( !InheritHandles ) {
  836. ProcessParameters->CurrentDirectory.Handle = NULL;
  837. }
  838. Status = ZwCreateProcess( &ProcessInformation->Process,
  839. PROCESS_ALL_ACCESS,
  840. &ObjectAttributes,
  841. ParentProcess,
  842. InheritHandles,
  843. Section,
  844. DebugPort,
  845. ExceptionPort
  846. );
  847. if ( !NT_SUCCESS( Status ) ) {
  848. ZwClose( Section );
  849. return( Status );
  850. }
  851. //
  852. // Retreive the interesting information from the image header
  853. //
  854. Status = ZwQuerySection( Section,
  855. SectionImageInformation,
  856. &ProcessInformation->ImageInformation,
  857. sizeof( ProcessInformation->ImageInformation ),
  858. NULL
  859. );
  860. if ( !NT_SUCCESS( Status ) ) {
  861. ZwClose( ProcessInformation->Process );
  862. ZwClose( Section );
  863. return( Status );
  864. }
  865. Status = ZwQueryInformationProcess( ProcessInformation->Process,
  866. ProcessBasicInformation,
  867. &ProcessInfo,
  868. sizeof( ProcessInfo ),
  869. NULL
  870. );
  871. if ( !NT_SUCCESS( Status ) ) {
  872. ZwClose( ProcessInformation->Process );
  873. ZwClose( Section );
  874. return( Status );
  875. }
  876. Peb = ProcessInfo.PebBaseAddress;
  877. //
  878. // Duplicate Native handles into new process if any specified.
  879. // Note that the duplicated handles will overlay the input values.
  880. //
  881. try {
  882. Status = STATUS_SUCCESS;
  883. if ( ProcessParameters->StandardInput ) {
  884. Status = ZwDuplicateObject(
  885. ParentProcess,
  886. ProcessParameters->StandardInput,
  887. ProcessInformation->Process,
  888. &ProcessParameters->StandardInput,
  889. 0L,
  890. 0L,
  891. DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES
  892. );
  893. if ( !NT_SUCCESS(Status) ) {
  894. __leave;
  895. }
  896. }
  897. if ( ProcessParameters->StandardOutput ) {
  898. Status = ZwDuplicateObject(
  899. ParentProcess,
  900. ProcessParameters->StandardOutput,
  901. ProcessInformation->Process,
  902. &ProcessParameters->StandardOutput,
  903. 0L,
  904. 0L,
  905. DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES
  906. );
  907. if ( !NT_SUCCESS(Status) ) {
  908. __leave;
  909. }
  910. }
  911. if ( ProcessParameters->StandardError ) {
  912. Status = ZwDuplicateObject(
  913. ParentProcess,
  914. ProcessParameters->StandardError,
  915. ProcessInformation->Process,
  916. &ProcessParameters->StandardError,
  917. 0L,
  918. 0L,
  919. DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES
  920. );
  921. if ( !NT_SUCCESS(Status) ) {
  922. __leave;
  923. }
  924. }
  925. } finally {
  926. if ( !NT_SUCCESS(Status) ) {
  927. ZwClose( ProcessInformation->Process );
  928. ZwClose( Section );
  929. }
  930. }
  931. if ( !NT_SUCCESS(Status) ) {
  932. return Status;
  933. }
  934. //
  935. // Possibly reserve some address space in the new process
  936. //
  937. if (ProcessInformation->ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_NATIVE ) {
  938. if ( ProcessParameters->Flags & RTL_USER_PROC_RESERVE_1MB ) {
  939. #if defined(_IA64_)
  940. Environment = (PVOID)(UADDRESS_BASE+4);
  941. #else
  942. Environment = (PVOID)(4);
  943. #endif
  944. RegionSize = (1024*1024)-(256);
  945. Status = ZwAllocateVirtualMemory( ProcessInformation->Process,
  946. (PVOID *)&Environment,
  947. 0,
  948. &RegionSize,
  949. MEM_RESERVE,
  950. PAGE_READWRITE
  951. );
  952. if ( !NT_SUCCESS( Status ) ) {
  953. ZwClose( ProcessInformation->Process );
  954. ZwClose( Section );
  955. return( Status );
  956. }
  957. }
  958. }
  959. //
  960. // Allocate virtual memory in the new process and use NtWriteVirtualMemory
  961. // to write a copy of the process environment block into the address
  962. // space of the new process. Save the address of the allocated block in
  963. // the process parameter block so the new process can access it.
  964. //
  965. if (s = (PWCHAR)ProcessParameters->Environment) {
  966. while (*s++) {
  967. while (*s++) {
  968. }
  969. }
  970. EnvironmentLength = (SIZE_T)(s - (PWCHAR)ProcessParameters->Environment) * sizeof(WCHAR);
  971. Environment = NULL;
  972. RegionSize = EnvironmentLength;
  973. Status = ZwAllocateVirtualMemory( ProcessInformation->Process,
  974. (PVOID *)&Environment,
  975. 0,
  976. &RegionSize,
  977. MEM_COMMIT,
  978. PAGE_READWRITE
  979. );
  980. if ( !NT_SUCCESS( Status ) ) {
  981. ZwClose( ProcessInformation->Process );
  982. ZwClose( Section );
  983. return( Status );
  984. }
  985. Status = ZwWriteVirtualMemory( ProcessInformation->Process,
  986. Environment,
  987. ProcessParameters->Environment,
  988. EnvironmentLength,
  989. NULL
  990. );
  991. if ( !NT_SUCCESS( Status ) ) {
  992. ZwClose( ProcessInformation->Process );
  993. ZwClose( Section );
  994. return( Status );
  995. }
  996. ProcessParameters->Environment = Environment;
  997. }
  998. //
  999. // Allocate virtual memory in the new process and use NtWriteVirtualMemory
  1000. // to write a copy of the process parameters block into the address
  1001. // space of the new process. Set the initial parameter to the new thread
  1002. // to be the address of the block in the new process's address space.
  1003. //
  1004. Parameters = NULL;
  1005. ParameterLength = ProcessParameters->MaximumLength;
  1006. Status = ZwAllocateVirtualMemory( ProcessInformation->Process,
  1007. (PVOID *)&Parameters,
  1008. 0,
  1009. &ParameterLength,
  1010. MEM_COMMIT,
  1011. PAGE_READWRITE
  1012. );
  1013. if ( !NT_SUCCESS( Status ) ) {
  1014. ZwClose( ProcessInformation->Process );
  1015. ZwClose( Section );
  1016. return( Status );
  1017. }
  1018. Status = ZwWriteVirtualMemory( ProcessInformation->Process,
  1019. Parameters,
  1020. ProcessParameters,
  1021. ProcessParameters->Length,
  1022. NULL
  1023. );
  1024. if ( !NT_SUCCESS( Status ) ) {
  1025. ZwClose( ProcessInformation->Process );
  1026. ZwClose( Section );
  1027. return( Status );
  1028. }
  1029. Status = ZwWriteVirtualMemory( ProcessInformation->Process,
  1030. &Peb->ProcessParameters,
  1031. &Parameters,
  1032. sizeof( Parameters ),
  1033. NULL
  1034. );
  1035. if ( !NT_SUCCESS( Status ) ) {
  1036. ZwClose( ProcessInformation->Process );
  1037. ZwClose( Section );
  1038. return( Status );
  1039. }
  1040. //
  1041. // Create a suspended thread in the new process. Specify the size and
  1042. // position of the stack, along with the start address, initial parameter
  1043. // and an SECURITY_DESCRIPTOR. The new thread will not have a name and its handle will
  1044. // not be inherited by other processes.
  1045. //
  1046. Status = RtlCreateUserThread(
  1047. ProcessInformation->Process,
  1048. ThreadSecurityDescriptor,
  1049. TRUE,
  1050. ProcessInformation->ImageInformation.ZeroBits,
  1051. ProcessInformation->ImageInformation.MaximumStackSize,
  1052. ProcessInformation->ImageInformation.CommittedStackSize,
  1053. (PUSER_THREAD_START_ROUTINE)
  1054. ProcessInformation->ImageInformation.TransferAddress,
  1055. (PVOID)Peb,
  1056. &ProcessInformation->Thread,
  1057. &ProcessInformation->ClientId
  1058. );
  1059. if ( !NT_SUCCESS( Status ) ) {
  1060. ZwClose( ProcessInformation->Process );
  1061. ZwClose( Section );
  1062. return( Status );
  1063. }
  1064. //
  1065. // Now close the section and file handles. The objects they represent
  1066. // will not actually go away until the process is destroyed.
  1067. //
  1068. ZwClose( Section );
  1069. //
  1070. // Return success status
  1071. //
  1072. return( STATUS_SUCCESS );
  1073. }
  1074. NTSTATUS
  1075. RtlCreateUserThread(
  1076. IN HANDLE Process,
  1077. IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
  1078. IN BOOLEAN CreateSuspended,
  1079. IN ULONG ZeroBits OPTIONAL,
  1080. IN SIZE_T MaximumStackSize OPTIONAL,
  1081. IN SIZE_T CommittedStackSize OPTIONAL,
  1082. IN PUSER_THREAD_START_ROUTINE StartAddress,
  1083. IN PVOID Parameter OPTIONAL,
  1084. OUT PHANDLE Thread OPTIONAL,
  1085. OUT PCLIENT_ID ClientId OPTIONAL
  1086. )
  1087. /*++
  1088. Routine Description:
  1089. This function creates a user mode thread in a user process. The caller
  1090. specifies the attributes of the new thread. A handle to the thread, along
  1091. with its Client Id are returned to the caller.
  1092. Arguments:
  1093. Process - Handle to the target process in which to create the new thread.
  1094. ThreadSecurityDescriptor - An optional pointer to the Security Descriptor
  1095. give to the new thread.
  1096. CreateSuspended - A boolean parameter that specifies whether or not the new
  1097. thread is to be created suspended or not. If TRUE, the new thread
  1098. will be created with an initial suspend count of 1. If FALSE then
  1099. the new thread will be ready to run when this call returns.
  1100. ZeroBits - This parameter is passed to the virtual memory manager
  1101. when the stack is allocated. Stacks are always allocated with the
  1102. MEM_TOP_DOWN allocation attribute.
  1103. MaximumStackSize - This is the maximum size of the stack. This size
  1104. will be rounded up to the next highest page boundary. If zero is
  1105. specified, then the default size will be 64K bytes.
  1106. CommittedStackSize - This is the initial committed size of the stack. This
  1107. size is rounded up to the next highest page boundary and then an
  1108. additional page is added for the guard page. The resulting size
  1109. will then be commited and the guard page protection initialized
  1110. for the last committed page in the stack.
  1111. StartAddress - The initial starting address of the thread.
  1112. Parameter - An optional pointer to a 32-bit pointer parameter that is
  1113. passed as a single argument to the procedure at the start address
  1114. location.
  1115. Thread - An optional pointer that, if specified, points to a variable that
  1116. will receive the handle of the new thread.
  1117. ClientId - An optional pointer that, if specified, points to a variable
  1118. that will receive the Client Id of the new thread.
  1119. Return Value:
  1120. TBS
  1121. --*/
  1122. {
  1123. NTSTATUS Status;
  1124. CONTEXT ThreadContext={0};
  1125. OBJECT_ATTRIBUTES ObjectAttributes;
  1126. INITIAL_TEB InitialTeb;
  1127. HANDLE ThreadHandle;
  1128. CLIENT_ID ThreadClientId;
  1129. //
  1130. // Allocate a stack for this thread in the address space of the target
  1131. // process.
  1132. //
  1133. Status = RtlpCreateStack( Process,
  1134. MaximumStackSize,
  1135. CommittedStackSize,
  1136. ZeroBits,
  1137. &InitialTeb
  1138. );
  1139. if ( !NT_SUCCESS( Status ) ) {
  1140. return( Status );
  1141. }
  1142. //
  1143. // Create an initial context for the new thread.
  1144. //
  1145. try {
  1146. RtlInitializeContext( Process,
  1147. &ThreadContext,
  1148. Parameter,
  1149. (PVOID)StartAddress,
  1150. InitialTeb.StackBase
  1151. );
  1152. } except (EXCEPTION_EXECUTE_HANDLER) {
  1153. RtlpFreeStack( Process, &InitialTeb );
  1154. return GetExceptionCode ();
  1155. }
  1156. //
  1157. // Now create a thread in the target process. The new thread will
  1158. // not have a name and its handle will not be inherited by other
  1159. // processes.
  1160. //
  1161. InitializeObjectAttributes( &ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL,
  1162. ThreadSecurityDescriptor );
  1163. Status = ZwCreateThread( &ThreadHandle,
  1164. THREAD_ALL_ACCESS,
  1165. &ObjectAttributes,
  1166. Process,
  1167. &ThreadClientId,
  1168. &ThreadContext,
  1169. &InitialTeb,
  1170. CreateSuspended
  1171. );
  1172. if (!NT_SUCCESS( Status )) {
  1173. #if DBG
  1174. DbgPrint( "NTRTL: RtlCreateUserThread Failed. NtCreateThread Status == %X\n",
  1175. Status );
  1176. #endif // DBG
  1177. RtlpFreeStack( Process, &InitialTeb );
  1178. } else {
  1179. if (ARGUMENT_PRESENT( Thread )) {
  1180. *Thread = ThreadHandle;
  1181. } else {
  1182. ZwClose (ThreadHandle);
  1183. }
  1184. if (ARGUMENT_PRESENT( ClientId )) {
  1185. *ClientId = ThreadClientId;
  1186. }
  1187. }
  1188. //
  1189. // Return status
  1190. //
  1191. return( Status );
  1192. }
  1193. DECLSPEC_NORETURN
  1194. NTSYSAPI
  1195. VOID
  1196. NTAPI
  1197. RtlExitUserThread (
  1198. IN NTSTATUS ExitStatus
  1199. )
  1200. /*++
  1201. Routine Description:
  1202. This function exits a thread created by RtlCreateUserThread in such a way as the stack is deallocated
  1203. as well as the thread terminated.
  1204. Arguments:
  1205. ExitStatus - Final exit status
  1206. Return Value:
  1207. None
  1208. --*/
  1209. {
  1210. NtCurrentTeb ()->FreeStackOnTermination = TRUE;
  1211. NtTerminateThread (NtCurrentThread (), ExitStatus);
  1212. }
  1213. VOID
  1214. RtlFreeUserThreadStack(
  1215. HANDLE hProcess,
  1216. HANDLE hThread
  1217. )
  1218. {
  1219. NTSTATUS Status;
  1220. PTEB Teb;
  1221. THREAD_BASIC_INFORMATION ThreadInfo;
  1222. PVOID StackDeallocationBase;
  1223. SIZE_T Size;
  1224. Status = NtQueryInformationThread (hThread,
  1225. ThreadBasicInformation,
  1226. &ThreadInfo,
  1227. sizeof (ThreadInfo),
  1228. NULL);
  1229. Teb = ThreadInfo.TebBaseAddress;
  1230. if (!NT_SUCCESS (Status) || !Teb) {
  1231. return;
  1232. }
  1233. Status = NtReadVirtualMemory (hProcess,
  1234. &Teb->DeallocationStack,
  1235. &StackDeallocationBase,
  1236. sizeof (StackDeallocationBase),
  1237. NULL);
  1238. if (!NT_SUCCESS (Status) || !StackDeallocationBase) {
  1239. return;
  1240. }
  1241. Size = 0;
  1242. NtFreeVirtualMemory (hProcess, &StackDeallocationBase, &Size, MEM_RELEASE);
  1243. return;
  1244. }
  1245. #if defined(ALLOC_DATA_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  1246. #pragma const_seg()
  1247. #endif