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

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