test: rtlexec.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# rtlexec.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     rtlexec.c
    00008
    00009 Abstract:
    00010
    00011     User Mode routines for creating user mode processes and threads.
    00012
    00013 Author:
    00014
    00015     Steve Wood (stevewo) 18-Aug-1989
    00016
    00017 Environment:
    00018
    00019     User Mode or Kernel Mode
    00020
    00021 Revision History:
    00022
    00023 --*/
    00024
    00025 #include "ntrtlp.h"
    00026 #include <nturtl.h>
    00027 #include <string.h>
    00028 #include "init.h"
    00029 #include "ntos.h"
    00030 #define ROUND_UP( x, y )  ((ULONG)(x) + ((y)-1) & ~((y)-1))
    00031 #ifdef KERNEL
    00032 #define ISTERMINALSERVER() (SharedUserData->SuiteMask & (1 << TerminalServer))
    00033 #else
    00034 #define ISTERMINALSERVER() (USER_SHARED_DATA->SuiteMask & (1 << TerminalServer))
    00035 #endif
    00036
    00037 VOID
    00038 RtlpCopyProcString(
    00039     IN OUT PWSTR *pDst,
    00040     OUT PUNICODE_STRING DestString,
    00041     IN PUNICODE_STRING SourceString,
    00042     IN ULONG DstAlloc OPTIONAL
    00043     );
    00044
    00045 NTSTATUS
    00046 RtlpOpenImageFile(
    00047     IN PUNICODE_STRING ImagePathName,
    00048     IN ULONG Attributes,
    00049     OUT PHANDLE FileHandle,
    00050     IN BOOLEAN ReportErrors
    00051     );
    00052
    00053 NTSTATUS
    00054 RtlpFreeStack(
    00055     IN HANDLE Process,
    00056     IN PINITIAL_TEB InitialTeb
    00057     );
    00058
    00059 NTSTATUS
    00060 RtlpCreateStack(
    00061     IN HANDLE Process,
    00062     IN SIZE_T MaximumStackSize OPTIONAL,
    00063     IN SIZE_T CommittedStackSize OPTIONAL,
    00064     IN ULONG ZeroBits OPTIONAL,
    00065     OUT PINITIAL_TEB InitialTeb
    00066     );
    00067
    00068 #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
    00069 #pragma alloc_text(INIT,RtlpCopyProcString          )
    00070 #pragma alloc_text(INIT,RtlCreateProcessParameters  )
    00071 #pragma alloc_text(INIT,RtlDestroyProcessParameters )
    00072 #pragma alloc_text(INIT,RtlNormalizeProcessParams   )
    00073 #pragma alloc_text(INIT,RtlDeNormalizeProcessParams )
    00074 #pragma alloc_text(INIT,RtlpOpenImageFile           )
    00075 #pragma alloc_text(INIT,RtlpCreateStack             )
    00076 #pragma alloc_text(INIT,RtlpFreeStack               )
    00077 #pragma alloc_text(INIT,RtlCreateUserProcess        )
    00078 #pragma alloc_text(INIT,RtlCreateUserThread         )
    00079 #endif
    00080
    00081
    00082 VOID
    00083 RtlpCopyProcString(
    00084     IN OUT PWSTR *pDst,
    00085     OUT PUNICODE_STRING DestString,
    00086     IN PUNICODE_STRING SourceString,
    00087     IN ULONG DstAlloc OPTIONAL
    00088     )
    00089 {
    00090     if (!ARGUMENT_PRESENT( (ULONG_PTR)DstAlloc )) {
    00091         DstAlloc = SourceString->MaximumLength;
    00092         }
    00093
    00094     if (SourceString->Buffer != NULL && SourceString->Length != 0) {
    00095         RtlMoveMemory( *pDst,
    00096                        SourceString->Buffer,
    00097                        SourceString->Length
    00098                      );
    00099         }
    00100
    00101     DestString->Buffer = *pDst;
    00102     DestString->Length = SourceString->Length;
    00103     DestString->MaximumLength = (USHORT)DstAlloc;
    00104
    00105     *pDst = (PWSTR)((PCHAR)(*pDst) + ROUND_UP( DstAlloc, sizeof( ULONG ) ) );
    00106     return;
    00107 }
    00108
    00109 NTSTATUS
    00110 RtlCreateProcessParameters(
    00111     OUT PRTL_USER_PROCESS_PARAMETERS *ProcessParameters,
    00112     IN PUNICODE_STRING ImagePathName,
    00113     IN PUNICODE_STRING DllPath OPTIONAL,
    00114     IN PUNICODE_STRING CurrentDirectory OPTIONAL,
    00115     IN PUNICODE_STRING CommandLine OPTIONAL,
    00116     IN PVOID Environment OPTIONAL,
    00117     IN PUNICODE_STRING WindowTitle OPTIONAL,
    00118     IN PUNICODE_STRING DesktopInfo OPTIONAL,
    00119     IN PUNICODE_STRING ShellInfo OPTIONAL,
    00120     IN PUNICODE_STRING RuntimeData OPTIONAL
    00121     )
    00122
    00123 /*++
    00124
    00125 Routine Description:
    00126
    00127     This function formats NT style RTL_USER_PROCESS_PARAMETERS
    00128     record.  The record is self-contained in a single block of memory
    00129     allocated by this function.  The allocation method is opaque and
    00130     thus the record must be freed by calling the
    00131     RtlDestroyProcessParameters function.
    00132
    00133     The process parameters record is created in a de-normalized form,
    00134     thus making it suitable for passing to the RtlCreateUserProcess
    00135     function.  It is expected that the caller will fill in additional
    00136     fields in the process parameters record after this function returns,
    00137     but prior to calling RtlCreateUserProcess.
    00138
    00139 Arguments:
    00140
    00141     ProcessParameters - Pointer to a variable that will receive the address
    00142         of the process parameter structure created by this routinue.  The
    00143         memory for the structure is allocated in an opaque manner and must
    00144         be freed by calling RtlDestroyProcessParameters.
    00145
    00146     ImagePathName - Required parameter that is the fully qualified NT
    00147         path name of the image file that will be used to create the process
    00148         that will received these parameters.
    00149
    00150     DllPath - An optional parameter that is an NT String variable pointing
    00151         to the search path the NT Loader is to use in the target process
    00152         when searching for Dll modules.  If not specified, then the Dll
    00153         search path is filled in from the current process's Dll search
    00154         path.
    00155
    00156     CurrentDirectory - An optional parameter that is an NT String variable
    00157         pointing to the default directory string for the target process.
    00158         If not specified, then the current directory string is filled in
    00159         from the current process's current directory string.
    00160
    00161     CommandLine - An optional parameter that is an NT String variable that
    00162         will be passed to the target process as its command line.  If not
    00163         specified, then the command line passed to the target process will
    00164         be a null string.
    00165
    00166     Environment - An optional parameter that is an opaque pointer to an
    00167         environment variable block of the type created by
    00168         RtlCreateEnvironment routine.  If not specified, then the target
    00169         process will receive a copy of the calling process's environment
    00170         variable block.
    00171
    00172     WindowTitle - An optional parameter that is an NT String variable that
    00173         points to the title string the target process is to use for its
    00174         main window.  If not specified, then a null string will be passed
    00175         to the target process as its default window title.
    00176
    00177     DesktopInfo - An optional parameter that is an NT String variable that
    00178         contains uninterpreted data that is passed as is to the target
    00179         process.  If not specified, the target process will receive a
    00180         pointer to an empty string.
    00181
    00182     ShellInfo - An optional parameter that is an NT String variable that
    00183         contains uninterpreted data that is passed as is to the target
    00184         process.  If not specified, the target process will receive a
    00185         pointer to an empty string.
    00186
    00187     RuntimeData - An optional parameter that is an NT String variable that
    00188         contains uninterpreted data that is passed as is to the target
    00189         process.  If not specified, the target process will receive a
    00190         pointer to an empty string.
    00191
    00192 Return Value:
    00193
    00194     STATUS_SUCCESS - The process parameters is De-Normalized and
    00195         contains entries for each of the specified argument and variable
    00196         strings.
    00197
    00198     STATUS_BUFFER_TOO_SMALL - The specified process parameters buffer is
    00199         too small to contain the argument and environment strings. The value
    00200         of ProcessParameters->Length is modified to contain the buffer
    00201         size needed to contain the argument and variable strings.
    00202
    00203 --*/
    00204
    00205 {
    00206     PRTL_USER_PROCESS_PARAMETERS p;
    00207     NTSTATUS Status;
    00208     UNICODE_STRING NullString = {0, 1, L""};
    00209     ULONG ByteCount;
    00210     SIZE_T MaxByteCount;
    00211     PWSTR pDst;
    00212     PPEB Peb = NtCurrentPeb();
    00213     HANDLE CurDirHandle;
    00214
    00215     //
    00216     // Acquire the Peb Lock for the duration while we copy information out
    00217     // of it.
    00218     //
    00219
    00220     RtlAcquirePebLock();
    00221     Status = STATUS_SUCCESS;
    00222     p = NULL;
    00223     CurDirHandle = NULL;
    00224     try {
    00225         //
    00226         // For optional pointer parameters, default them to point to their
    00227         // corresponding field in the current process's process parameter
    00228         // structure or to a null string.
    00229         //
    00230
    00231         if (!ARGUMENT_PRESENT( DllPath )) {
    00232             DllPath = &Peb->ProcessParameters->DllPath;
    00233             }
    00234
    00235         if (!ARGUMENT_PRESENT( CurrentDirectory )) {
    00236
    00237             if ( Peb->ProcessParameters->CurrentDirectory.Handle ) {
    00238                 CurDirHandle = (HANDLE)((ULONG_PTR)Peb->ProcessParameters->CurrentDirectory.Handle & ~OBJ_HANDLE_TAGBITS);
    00239                 CurDirHandle = (HANDLE)((ULONG_PTR)CurDirHandle | RTL_USER_PROC_CURDIR_INHERIT);
    00240                 }
    00241             CurrentDirectory = &Peb->ProcessParameters->CurrentDirectory.DosPath;
    00242             }
    00243         else {
    00244             if ( Peb->ProcessParameters->CurrentDirectory.Handle ) {
    00245                 CurDirHandle = (HANDLE)((ULONG_PTR)Peb->ProcessParameters->CurrentDirectory.Handle & ~OBJ_HANDLE_TAGBITS);
    00246                 CurDirHandle = (HANDLE)((ULONG_PTR)CurDirHandle | RTL_USER_PROC_CURDIR_CLOSE);
    00247                 }
    00248             }
    00249
    00250         if (!ARGUMENT_PRESENT( CommandLine )) {
    00251             CommandLine = ImagePathName;
    00252             }
    00253
    00254         if (!ARGUMENT_PRESENT( Environment )) {
    00255             Environment = Peb->ProcessParameters->Environment;
    00256             }
    00257
    00258         if (!ARGUMENT_PRESENT( WindowTitle )) {
    00259             WindowTitle = &NullString;
    00260             }
    00261
    00262         if (!ARGUMENT_PRESENT( DesktopInfo )) {
    00263             DesktopInfo = &NullString;
    00264             }
    00265
    00266         if (!ARGUMENT_PRESENT( ShellInfo )) {
    00267             ShellInfo = &NullString;
    00268             }
    00269
    00270         if (!ARGUMENT_PRESENT( RuntimeData )) {
    00271             RuntimeData = &NullString;
    00272             }
    00273
    00274         //
    00275         // Determine size need to contain the process parameter record
    00276         // structure and all of the strings it will point to.  Each string
    00277         // will be aligned on a ULONG byte boundary.
    00278         //
    00279
    00280         ByteCount = sizeof( **ProcessParameters );
    00281         ByteCount += ROUND_UP( ImagePathName->Length + sizeof(UNICODE_NULL),    sizeof( ULONG ) );
    00282         ByteCount += ROUND_UP( DllPath->MaximumLength,       sizeof( ULONG ) );
    00283         ByteCount += ROUND_UP( DOS_MAX_PATH_LENGTH*2,        sizeof( ULONG ) );
    00284         ByteCount += ROUND_UP( CommandLine->Length + sizeof(UNICODE_NULL),      sizeof( ULONG ) );
    00285         ByteCount += ROUND_UP( WindowTitle->MaximumLength,   sizeof( ULONG ) );
    00286         ByteCount += ROUND_UP( DesktopInfo->MaximumLength,   sizeof( ULONG ) );
    00287         ByteCount += ROUND_UP( ShellInfo->MaximumLength,     sizeof( ULONG ) );
    00288         ByteCount += ROUND_UP( RuntimeData->MaximumLength,   sizeof( ULONG ) );
    00289
    00290         //
    00291         // Allocate memory for the process parameter record.
    00292         //
    00293
    00294         MaxByteCount = ByteCount;
    00295         Status = ZwAllocateVirtualMemory( NtCurrentProcess(),
    00296                                           (PVOID *)&p,
    00297                                           0,
    00298                                           &MaxByteCount,
    00299                                           MEM_COMMIT,
    00300                                           PAGE_READWRITE
    00301                                         );
    00302         if (!NT_SUCCESS( Status )) {
    00303             return( Status );
    00304             }
    00305
    00306         p->MaximumLength = (ULONG) MaxByteCount;
    00307         p->Length = ByteCount;
    00308         p->Flags = RTL_USER_PROC_PARAMS_NORMALIZED;
    00309         p->Environment = Environment;
    00310         p->CurrentDirectory.Handle = CurDirHandle;
    00311
    00312         //
    00313         // Inherits ^C inhibit information
    00314         //
    00315
    00316         p->ConsoleFlags = Peb->ProcessParameters->ConsoleFlags;
    00317
    00318         pDst = (PWSTR)(p + 1);
    00319         RtlpCopyProcString( &pDst,
    00320                             &p->CurrentDirectory.DosPath,
    00321                             CurrentDirectory,
    00322                             DOS_MAX_PATH_LENGTH*2
    00323                           );
    00324
    00325         RtlpCopyProcString( &pDst, &p->DllPath, DllPath, 0 );
    00326         RtlpCopyProcString( &pDst, &p->ImagePathName, ImagePathName, ImagePathName->Length + sizeof(UNICODE_NULL) );
    00327         if (CommandLine->Length == CommandLine->MaximumLength) {
    00328             RtlpCopyProcString( &pDst, &p->CommandLine, CommandLine, 0 );
    00329             }
    00330         else {
    00331             RtlpCopyProcString( &pDst, &p->CommandLine, CommandLine, CommandLine->Length + sizeof(UNICODE_NULL) );
    00332             }
    00333         RtlpCopyProcString( &pDst, &p->WindowTitle, WindowTitle, 0 );
    00334         RtlpCopyProcString( &pDst, &p->DesktopInfo, DesktopInfo, 0 );
    00335         RtlpCopyProcString( &pDst, &p->ShellInfo,   ShellInfo, 0 );
    00336         if (RuntimeData->Length != 0) {
    00337             RtlpCopyProcString( &pDst, &p->RuntimeData, RuntimeData, 0 );
    00338             }
    00339         else {
    00340             p->RuntimeData.Buffer = NULL;
    00341             p->RuntimeData.Length = 0;
    00342             p->RuntimeData.MaximumLength = 0;
    00343             }
    00344         *ProcessParameters = RtlDeNormalizeProcessParams( p );
    00345         p = NULL;
    00346         }
    00347     finally {
    00348         if (AbnormalTermination()) {
    00349             Status = STATUS_ACCESS_VIOLATION;
    00350             }
    00351
    00352         if (p != NULL) {
    00353             RtlDestroyProcessParameters( p );
    00354             }
    00355
    00356         RtlReleasePebLock();
    00357         }
    00358
    00359     return( Status );
    00360 }
    00361
    00362
    00363
    00364 NTSTATUS
    00365 RtlDestroyProcessParameters(
    00366     IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters
    00367     )
    00368 {
    00369     NTSTATUS Status;
    00370     SIZE_T RegionSize;
    00371
    00372     RegionSize = 0;
    00373     Status = ZwFreeVirtualMemory( NtCurrentProcess(),
    00374                                   (PVOID *)&ProcessParameters,
    00375                                   &RegionSize,
    00376                                   MEM_RELEASE
    00377                                 );
    00378
    00379     return( Status );
    00380 }
    00381
    00382
    00383 #define RtlpNormalizeProcessParam( Base, p )        \
    00384     if ((p) != NULL) {                              \
    00385         (p) = (PWSTR)((PCHAR)(p) + (ULONG_PTR)(Base));  \
    00386         }                                           \
    00387
    00388 #define RtlpDeNormalizeProcessParam( Base, p )      \
    00389     if ((p) != NULL) {                              \
    00390         (p) = (PWSTR)((PCHAR)(p) - (ULONG_PTR)(Base));  \
    00391         }                                           \
    00392
    00393
    00394 PRTL_USER_PROCESS_PARAMETERS
    00395 RtlNormalizeProcessParams(
    00396     IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters
    00397     )
    00398 {
    00399     if (!ARGUMENT_PRESENT( ProcessParameters )) {
    00400         return( NULL );
    00401         }
    00402
    00403     if (ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED) {
    00404         return( ProcessParameters );
    00405         }
    00406
    00407     RtlpNormalizeProcessParam( ProcessParameters,
    00408                                ProcessParameters->CurrentDirectory.DosPath.Buffer
    00409                              );
    00410
    00411     RtlpNormalizeProcessParam( ProcessParameters,
    00412                                ProcessParameters->DllPath.Buffer
    00413                              );
    00414
    00415     RtlpNormalizeProcessParam( ProcessParameters,
    00416                                ProcessParameters->ImagePathName.Buffer
    00417                              );
    00418
    00419     RtlpNormalizeProcessParam( ProcessParameters,
    00420                                ProcessParameters->CommandLine.Buffer
    00421                              );
    00422
    00423     RtlpNormalizeProcessParam( ProcessParameters,
    00424                                ProcessParameters->WindowTitle.Buffer
    00425                              );
    00426
    00427     RtlpNormalizeProcessParam( ProcessParameters,
    00428                                ProcessParameters->DesktopInfo.Buffer
    00429                              );
    00430
    00431     RtlpNormalizeProcessParam( ProcessParameters,
    00432                                ProcessParameters->ShellInfo.Buffer
    00433                              );
    00434
    00435     RtlpNormalizeProcessParam( ProcessParameters,
    00436                                ProcessParameters->RuntimeData.Buffer
    00437                              );
    00438     ProcessParameters->Flags |= RTL_USER_PROC_PARAMS_NORMALIZED;
    00439
    00440     return( ProcessParameters );
    00441 }
    00442
    00443 PRTL_USER_PROCESS_PARAMETERS
    00444 RtlDeNormalizeProcessParams(
    00445     IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters
    00446     )
    00447 {
    00448     if (!ARGUMENT_PRESENT( ProcessParameters )) {
    00449         return( NULL );
    00450         }
    00451
    00452     if (!(ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) {
    00453         return( ProcessParameters );
    00454         }
    00455
    00456     RtlpDeNormalizeProcessParam( ProcessParameters,
    00457                                  ProcessParameters->CurrentDirectory.DosPath.Buffer
    00458                                );
    00459
    00460     RtlpDeNormalizeProcessParam( ProcessParameters,
    00461                                  ProcessParameters->DllPath.Buffer
    00462                                );
    00463
    00464     RtlpDeNormalizeProcessParam( ProcessParameters,
    00465                                  ProcessParameters->ImagePathName.Buffer
    00466                                );
    00467
    00468     RtlpDeNormalizeProcessParam( ProcessParameters,
    00469                                  ProcessParameters->CommandLine.Buffer
    00470                                );
    00471
    00472     RtlpDeNormalizeProcessParam( ProcessParameters,
    00473                                  ProcessParameters->WindowTitle.Buffer
    00474                                );
    00475
    00476     RtlpDeNormalizeProcessParam( ProcessParameters,
    00477                                  ProcessParameters->DesktopInfo.Buffer
    00478                                );
    00479
    00480     RtlpDeNormalizeProcessParam( ProcessParameters,
    00481                                  ProcessParameters->ShellInfo.Buffer
    00482                                );
    00483
    00484     RtlpDeNormalizeProcessParam( ProcessParameters,
    00485                                  ProcessParameters->RuntimeData.Buffer
    00486                                );
    00487
    00488     ProcessParameters->Flags &= ~RTL_USER_PROC_PARAMS_NORMALIZED;
    00489     return( ProcessParameters );
    00490 }
    00491
    00492 NTSTATUS
    00493 RtlpOpenImageFile(
    00494     IN PUNICODE_STRING ImagePathName,
    00495     IN ULONG Attributes,
    00496     OUT PHANDLE FileHandle,
    00497     IN BOOLEAN ReportErrors
    00498     )
    00499 {
    00500     NTSTATUS Status;
    00501     OBJECT_ATTRIBUTES ObjectAttributes;
    00502     HANDLE File;
    00503     IO_STATUS_BLOCK IoStatus;
    00504
    00505     *FileHandle = NULL;
    00506
    00507     InitializeObjectAttributes( &ObjectAttributes,
    00508                                 ImagePathName,
    00509                                 Attributes,
    00510                                 NULL,
    00511                                 NULL
    00512                               );
    00513     Status = ZwOpenFile( &File,
    00514                          SYNCHRONIZE | FILE_EXECUTE,
    00515                          &ObjectAttributes,
    00516                          &IoStatus,
    00517                          FILE_SHARE_READ | FILE_SHARE_DELETE,
    00518                          FILE_NON_DIRECTORY_FILE
    00519                          );
    00520
    00521     if (!NT_SUCCESS( Status )) {
    00522 #if DBG
    00523         if (ReportErrors) {
    00524             DbgPrint( "NTRTL: RtlpOpenImageFile - NtCreateFile( %wZ ) failed.  Status == %X\n",
    00525                       ImagePathName,
    00526                       Status
    00527                     );
    00528             }
    00529 #endif // DBG
    00530         return( Status );
    00531         }
    00532
    00533     *FileHandle = File;
    00534     return( STATUS_SUCCESS );
    00535 }
    00536
    00537
    00538 NTSTATUS
    00539 RtlpCreateStack(
    00540     IN HANDLE Process,
    00541     IN SIZE_T MaximumStackSize OPTIONAL,
    00542     IN SIZE_T CommittedStackSize OPTIONAL,
    00543     IN ULONG ZeroBits OPTIONAL,
    00544     OUT PINITIAL_TEB InitialTeb
    00545     )
    00546 {
    00547     NTSTATUS Status;
    00548     PCH Stack;
    00549     SYSTEM_BASIC_INFORMATION SysInfo;
    00550     BOOLEAN GuardPage;
    00551     SIZE_T RegionSize;
    00552     ULONG OldProtect;
    00553 #if defined(_IA64_)
    00554     PCH Bstore;
    00555     SIZE_T CommittedBstoreSize;
    00556     SIZE_T MaximumBstoreSize;
    00557     SIZE_T MstackPlusBstoreSize;
    00558 #endif
    00559
    00560     Status = ZwQuerySystemInformation( SystemBasicInformation,
    00561                                        (PVOID)&SysInfo,
    00562                                        sizeof( SysInfo ),
    00563                                        NULL
    00564                                      );
    00565     if ( !NT_SUCCESS( Status ) ) {
    00566         return( Status );
    00567         }
    00568
    00569     //
    00570     // if stack is in the current process, then default to
    00571     // the parameters from the image
    00572     //
    00573
    00574     if ( Process == NtCurrentProcess() ) {
    00575         PPEB Peb;
    00576         PIMAGE_NT_HEADERS NtHeaders;
    00577
    00578
    00579         Peb = NtCurrentPeb();
    00580         NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
    00581
    00582
    00583         if (!MaximumStackSize) {
    00584             MaximumStackSize = NtHeaders->OptionalHeader.SizeOfStackReserve;
    00585             }
    00586
    00587         if (!CommittedStackSize) {
    00588             CommittedStackSize = NtHeaders->OptionalHeader.SizeOfStackCommit;
    00589             }
    00590
    00591         }
    00592     else {
    00593
    00594         if (!CommittedStackSize) {
    00595             CommittedStackSize = SysInfo.PageSize;
    00596             }
    00597
    00598         if (!MaximumStackSize) {
    00599             MaximumStackSize = SysInfo.AllocationGranularity;
    00600             }
    00601
    00602         }
    00603
    00604
    00605     if ( CommittedStackSize >= MaximumStackSize ) {
    00606         MaximumStackSize = ROUND_UP(CommittedStackSize, (1024*1024));
    00607         }
    00608
    00609
    00610     CommittedStackSize = ROUND_UP( CommittedStackSize, SysInfo.PageSize );
    00611     MaximumStackSize = ROUND_UP( MaximumStackSize,
    00612                                  SysInfo.AllocationGranularity
    00613                                );
    00614
    00615     Stack = NULL,
    00616
    00617 #if defined(_IA64_)
    00618
    00619     //
    00620     // Piggyback the backing store with the memory stack
    00621     //
    00622
    00623     CommittedBstoreSize = CommittedStackSize;
    00624     MaximumBstoreSize = MaximumStackSize;
    00625     MstackPlusBstoreSize = MaximumBstoreSize + MaximumStackSize;
    00626
    00627     Status = ZwAllocateVirtualMemory( Process,
    00628                                       (PVOID *)&Stack,
    00629                                       ZeroBits,
    00630                                       &MstackPlusBstoreSize,
    00631                                       MEM_RESERVE,
    00632                                       PAGE_READWRITE
    00633                                     );
    00634 #else
    00635
    00636     Status = ZwAllocateVirtualMemory( Process,
    00637                                       (PVOID *)&Stack,
    00638                                       ZeroBits,
    00639                                       &MaximumStackSize,
    00640                                       MEM_RESERVE,
    00641                                       PAGE_READWRITE
    00642                                     );
    00643 #endif // defined(_IA64_)
    00644
    00645     if ( !NT_SUCCESS( Status ) ) {
    00646 #if DBG
    00647         DbgPrint( "NTRTL: RtlpCreateStack( %lx ) failed.  Stack Reservation Status == %X\n",
    00648                   Process,
    00649                   Status
    00650                 );
    00651 #endif // DBG
    00652         return( Status );
    00653         }
    00654
    00655 #if defined(_IA64_)
    00656     InitialTeb->OldInitialTeb.OldBStoreLimit = NULL;
    00657 #endif // defined(_IA64_)
    00658
    00659     InitialTeb->OldInitialTeb.OldStackBase = NULL;
    00660     InitialTeb->OldInitialTeb.OldStackLimit = NULL;
    00661     InitialTeb->StackAllocationBase = Stack;
    00662     InitialTeb->StackBase = Stack + MaximumStackSize;
    00663
    00664     Stack += MaximumStackSize - CommittedStackSize;
    00665     if (MaximumStackSize > CommittedStackSize) {
    00666         Stack -= SysInfo.PageSize;
    00667         CommittedStackSize += SysInfo.PageSize;
    00668         GuardPage = TRUE;
    00669         }
    00670     else {
    00671         GuardPage = FALSE;
    00672         }
    00673     Status = ZwAllocateVirtualMemory( Process,
    00674                                       (PVOID *)&Stack,
    00675                                       0,
    00676                                       &CommittedStackSize,
    00677                                       MEM_COMMIT,
    00678                                       PAGE_READWRITE
    00679                                     );
    00680     InitialTeb->StackLimit = Stack;
    00681
    00682     if ( !NT_SUCCESS( Status ) ) {
    00683 #if DBG
    00684         DbgPrint( "NTRTL: RtlpCreateStack( %lx ) failed.  Stack Commit Status == %X\n",
    00685                   Process,
    00686                   Status
    00687                 );
    00688 #endif // DBG
    00689         return( Status );
    00690         }
    00691
    00692     //
    00693     // if we have space, create a guard page.
    00694     //
    00695
    00696     if (GuardPage) {
    00697         RegionSize =  SysInfo.PageSize;
    00698         Status = ZwProtectVirtualMemory( Process,
    00699                                          (PVOID *)&Stack,
    00700                                          &RegionSize,
    00701                                          PAGE_GUARD | PAGE_READWRITE,
    00702                                          &OldProtect);
    00703
    00704
    00705         if ( !NT_SUCCESS( Status ) ) {
    00706 #if DBG
    00707             DbgPrint( "NTRTL: RtlpCreateStack( %lx ) failed.  Guard Page Creation Status == %X\n",
    00708                       Process,
    00709                       Status
    00710                     );
    00711 #endif // DBG
    00712             return( Status );
    00713             }
    00714 #if defined(_IA64_)
    00715         InitialTeb->StackLimit = (PVOID)((PUCHAR)InitialTeb->StackLimit + RegionSize);
    00716 #else
    00717         InitialTeb->StackLimit = (PVOID)((PUCHAR)InitialTeb->StackLimit - RegionSize);
    00718 #endif // defined(_IA64_)
    00719         }
    00720
    00721 #if defined(_IA64_)
    00722
    00723     //
    00724     // Commit backing store pages and create guard pages if there is space
    00725     //
    00726
    00727     Bstore = InitialTeb->StackBase;
    00728     if (MaximumBstoreSize > CommittedBstoreSize) {
    00729         CommittedBstoreSize += SysInfo.PageSize;
    00730         GuardPage = TRUE;
    00731     } else {
    00732         GuardPage = FALSE;
    00733     }
    00734
    00735     Status = ZwAllocateVirtualMemory( Process,
    00736                                       (PVOID *)&Bstore,
    00737                                       0,
    00738                                       &CommittedBstoreSize,
    00739                                       MEM_COMMIT,
    00740                                       PAGE_READWRITE
    00741                                     );
    00742
    00743     InitialTeb->BStoreLimit = Bstore + CommittedBstoreSize;
    00744
    00745     if ( !NT_SUCCESS(Status) ) {
    00746 #if DBG
    00747         DbgPrint("NTRTL: RtlpCreateStack( %lx ) failed. Backing Store Commit Status == %X\n",
    00748                  Process,
    00749                  Status
    00750                 );
    00751 #endif // DBG
    00752         return (Status);
    00753     }
    00754
    00755     if (GuardPage) {
    00756         Bstore = (PCH)InitialTeb->BStoreLimit - SysInfo.PageSize;
    00757         RegionSize = SysInfo.PageSize;
    00758         Status = ZwProtectVirtualMemory(Process,
    00759                                         (PVOID *)&Bstore,
    00760                                         &RegionSize,
    00761                                         PAGE_GUARD | PAGE_READWRITE,
    00762                                         &OldProtect
    00763                                        );
    00764         if ( !NT_SUCCESS(Status) ) {
    00765 #if DBG
    00766             DbgPrint("NTRTL: RtlpCreateStack( %lx ) failed.  Backing Store Guard Page Creation Status == %X\n",
    00767                      Process,
    00768                      Status
    00769                     );
    00770 #endif // DBG
    00771             return (Status);
    00772         }
    00773         InitialTeb->BStoreLimit = (PVOID)((PUCHAR)InitialTeb->BStoreLimit - RegionSize);
    00774     }
    00775
    00776 #endif // defined(_IA64_)
    00777
    00778     return( STATUS_SUCCESS );
    00779 }
    00780
    00781
    00782 NTSTATUS
    00783 RtlpFreeStack(
    00784     IN HANDLE Process,
    00785     IN PINITIAL_TEB InitialTeb
    00786     )
    00787 {
    00788     NTSTATUS Status;
    00789     SIZE_T Zero;
    00790
    00791     Zero = 0;
    00792     Status = ZwFreeVirtualMemory( Process,
    00793                                   &InitialTeb->StackAllocationBase,
    00794                                   &Zero,
    00795                                   MEM_RELEASE
    00796                                 );
    00797     if ( !NT_SUCCESS( Status ) ) {
    00798 #if DBG
    00799         DbgPrint( "NTRTL: RtlpFreeStack( %lx ) failed.  Stack DeCommit Status == %X\n",
    00800                   Process,
    00801                   Status
    00802                 );
    00803 #endif // DBG
    00804         return( Status );
    00805         }
    00806
    00807     RtlZeroMemory( InitialTeb, sizeof( *InitialTeb ) );
    00808     return( STATUS_SUCCESS );
    00809 }
    00810
    00811
    00812 NTSTATUS
    00813 RtlCreateUserProcess(
    00814     IN PUNICODE_STRING NtImagePathName,
    00815     IN ULONG Attributes,
    00816     IN PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
    00817     IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL,
    00818     IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
    00819     IN HANDLE ParentProcess OPTIONAL,
    00820     IN BOOLEAN InheritHandles,
    00821     IN HANDLE DebugPort OPTIONAL,
    00822     IN HANDLE ExceptionPort OPTIONAL,
    00823     OUT PRTL_USER_PROCESS_INFORMATION ProcessInformation
    00824     )
    00825
    00826 /*++
    00827
    00828 Routine Description:
    00829
    00830     This function creates a user mode process with a single thread with
    00831     a suspend count of one.  The address space of the new process is
    00832     initialized with the contents of specified image file.  The caller
    00833     can specify the Access Control List for the new process and thread.
    00834     The caller can also specify the parent process to inherit process
    00835     priority and processor affinity from.  The default is to inherit
    00836     these from the current process.  Finally the caller can specify
    00837     whether the new process is to inherit any of the object handles
    00838     from the specified parent process or not.
    00839
    00840     Information about the new process and thread is returned via
    00841     the ProcessInformation parameter.
    00842
    00843 Arguments:
    00844
    00845     NtImagePathName - A required pointer that points to the NT Path string
    00846         that identifies the image file that is to be loaded into the
    00847         child process.
    00848
    00849     ProcessParameters - A required pointer that points to parameters that
    00850         are to passed to the child process.
    00851
    00852     ProcessSecurityDescriptor - An optional pointer to the Security Descriptor
    00853         give to the new process.
    00854
    00855     ThreadSecurityDescriptor - An optional pointer to the Security Descriptor
    00856         give to the new thread.
    00857
    00858     ParentProcess - An optional process handle that will used to inherit
    00859         certain properties from.
    00860
    00861     InheritHandles - A boolean value.  TRUE specifies that object handles
    00862         associated with the specified parent process are to be inherited
    00863         by the new process, provided they have the OBJ_INHERIT attribute.
    00864         FALSE specifies that the new process is to inherit no handles.
    00865
    00866     DebugPort - An optional handle to the debug port associated with this
    00867         process.
    00868
    00869     ExceptionPort - An optional handle to the exception port associated with this
    00870         process.
    00871
    00872     ProcessInformation - A pointer to a variable that receives information
    00873         about the new process and thread.
    00874
    00875 Return Value:
    00876
    00877     TBS.
    00878
    00879 --*/
    00880
    00881 {
    00882     NTSTATUS Status;
    00883     HANDLE Section, File;
    00884     OBJECT_ATTRIBUTES ObjectAttributes;
    00885     PRTL_USER_PROCESS_PARAMETERS Parameters;
    00886     SIZE_T ParameterLength;
    00887     PVOID Environment;
    00888     PWCHAR s;
    00889     ULONG EnvironmentLength;
    00890     SIZE_T RegionSize;
    00891     PROCESS_BASIC_INFORMATION ProcessInfo;
    00892     PPEB Peb;
    00893     UNICODE_STRING Unicode;
    00894
    00895     //
    00896     // Zero output parameter and probe the addresses at the same time
    00897     //
    00898
    00899     RtlZeroMemory( ProcessInformation, sizeof( *ProcessInformation ) );
    00900     ProcessInformation->Length = sizeof( *ProcessInformation );
    00901
    00902     //
    00903     // Open the specified image file.
    00904     //
    00905
    00906     Status = RtlpOpenImageFile( NtImagePathName,
    00907                                 Attributes & (OBJ_INHERIT | OBJ_CASE_INSENSITIVE),
    00908                                 &File,
    00909                                 TRUE
    00910                               );
    00911     if (!NT_SUCCESS( Status )) {
    00912         return( Status );
    00913         }
    00914
    00915
    00916     //
    00917     // Create a memory section backed by the opened image file
    00918     //
    00919
    00920     Status = ZwCreateSection( &Section,
    00921                               SECTION_ALL_ACCESS,
    00922                               NULL,
    00923                               NULL,
    00924                               PAGE_EXECUTE,
    00925                               SEC_IMAGE,
    00926                               File
    00927                             );
    00928     ZwClose( File );
    00929     if ( !NT_SUCCESS( Status ) ) {
    00930         return( Status );
    00931         }
    00932
    00933
    00934     //
    00935     // Create the user mode process, defaulting the parent process to the
    00936     // current process if one is not specified.  The new process will not
    00937     // have a name nor will the handle be inherited by other processes.
    00938     //
    00939
    00940     if (!ARGUMENT_PRESENT( ParentProcess )) {
    00941         ParentProcess = NtCurrentProcess();
    00942         }
    00943
    00944     InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL,
    00945                                 ProcessSecurityDescriptor );
    00946     if ( RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG ) {
    00947         if ( wcsstr(NtImagePathName->Buffer,L"csrss") ||
    00948              wcsstr(NtImagePathName->Buffer,L"CSRSS")
    00949            ) {
    00950
    00951             //
    00952             // For Hydra we don't name the CSRSS process to avoid name
    00953             // collissions when multiple CSRSS's are started
    00954             //
    00955             if (ISTERMINALSERVER()) {
    00956
    00957                 InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL,
    00958                                             ProcessSecurityDescriptor );
    00959             } else {
    00960
    00961                 RtlInitUnicodeString(&Unicode,L"\\WindowsSS");
    00962                 InitializeObjectAttributes( &ObjectAttributes, &Unicode, 0, NULL,
    00963                                             ProcessSecurityDescriptor );
    00964             }
    00965
    00966             }
    00967         }
    00968
    00969     if ( !InheritHandles ) {
    00970         ProcessParameters->CurrentDirectory.Handle = NULL;
    00971         }
    00972     Status = ZwCreateProcess( &ProcessInformation->Process,
    00973                               PROCESS_ALL_ACCESS,
    00974                               &ObjectAttributes,
    00975                               ParentProcess,
    00976                               InheritHandles,
    00977                               Section,
    00978                               DebugPort,
    00979                               ExceptionPort
    00980                             );
    00981     if ( !NT_SUCCESS( Status ) ) {
    00982         ZwClose( Section );
    00983         return( Status );
    00984         }
    00985
    00986
    00987     //
    00988     // Retreive the interesting information from the image header
    00989     //
    00990
    00991     Status = ZwQuerySection( Section,
    00992                              SectionImageInformation,
    00993                              &ProcessInformation->ImageInformation,
    00994                              sizeof( ProcessInformation->ImageInformation ),
    00995                              NULL
    00996                            );
    00997     if ( !NT_SUCCESS( Status ) ) {
    00998         ZwClose( ProcessInformation->Process );
    00999         ZwClose( Section );
    01000         return( Status );
    01001         }
    01002
    01003     Status = ZwQueryInformationProcess( ProcessInformation->Process,
    01004                                         ProcessBasicInformation,
    01005                                         &ProcessInfo,
    01006                                         sizeof( ProcessInfo ),
    01007                                         NULL
    01008                                       );
    01009     if ( !NT_SUCCESS( Status ) ) {
    01010         ZwClose( ProcessInformation->Process );
    01011         ZwClose( Section );
    01012         return( Status );
    01013         }
    01014
    01015     Peb = ProcessInfo.PebBaseAddress;
    01016
    01017     //
    01018     // Duplicate Native handles into new process if any specified.
    01019     // Note that the duplicated handles will overlay the input values.
    01020     //
    01021
    01022     try {
    01023         Status = STATUS_SUCCESS;
    01024
    01025         if ( ProcessParameters->StandardInput ) {
    01026
    01027             Status = ZwDuplicateObject(
    01028                         ParentProcess,
    01029                         ProcessParameters->StandardInput,
    01030                         ProcessInformation->Process,
    01031                         &ProcessParameters->StandardInput,
    01032                         0L,
    01033                         0L,
    01034                         DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES
    01035                         );
    01036             if ( !NT_SUCCESS(Status) ) {
    01037                 return Status;
    01038             }
    01039         }
    01040
    01041         if ( ProcessParameters->StandardOutput ) {
    01042
    01043             Status = ZwDuplicateObject(
    01044                         ParentProcess,
    01045                         ProcessParameters->StandardOutput,
    01046                         ProcessInformation->Process,
    01047                         &ProcessParameters->StandardOutput,
    01048                         0L,
    01049                         0L,
    01050                         DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES
    01051                         );
    01052             if ( !NT_SUCCESS(Status) ) {
    01053                 return Status;
    01054             }
    01055         }
    01056
    01057         if ( ProcessParameters->StandardError ) {
    01058
    01059             Status = ZwDuplicateObject(
    01060                         ParentProcess,
    01061                         ProcessParameters->StandardError,
    01062                         ProcessInformation->Process,
    01063                         &ProcessParameters->StandardError,
    01064                         0L,
    01065                         0L,
    01066                         DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES
    01067                         );
    01068             if ( !NT_SUCCESS(Status) ) {
    01069                 return Status;
    01070             }
    01071         }
    01072
    01073     } finally {
    01074         if ( !NT_SUCCESS(Status) ) {
    01075             ZwClose( ProcessInformation->Process );
    01076             ZwClose( Section );
    01077             }
    01078         }
    01079
    01080     //
    01081     // Possibly reserve some address space in the new process
    01082     //
    01083
    01084     if (ProcessInformation->ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_NATIVE ) {
    01085         if ( ProcessParameters->Flags & RTL_USER_PROC_RESERVE_1MB ) {
    01086
    01087 #if defined(_IA64_)
    01088             Environment = (PVOID)(UADDRESS_BASE+4);
    01089 #else
    01090             Environment = (PVOID)(4);
    01091 #endif
    01092             RegionSize = (1024*1024)-(256);
    01093
    01094             Status = ZwAllocateVirtualMemory( ProcessInformation->Process,
    01095                                               (PVOID *)&Environment,
    01096                                               0,
    01097                                               &RegionSize,
    01098                                               MEM_RESERVE,
    01099                                               PAGE_READWRITE
    01100                                             );
    01101             if ( !NT_SUCCESS( Status ) ) {
    01102                 ZwClose( ProcessInformation->Process );
    01103                 ZwClose( Section );
    01104                 return( Status );
    01105                 }
    01106             }
    01107         }
    01108
    01109     //
    01110     // Allocate virtual memory in the new process and use NtWriteVirtualMemory
    01111     // to write a copy of the process environment block into the address
    01112     // space of the new process.  Save the address of the allocated block in
    01113     // the process parameter block so the new process can access it.
    01114     //
    01115
    01116     if (s = (PWCHAR)ProcessParameters->Environment) {
    01117         while (*s++) {
    01118             while (*s++) {
    01119                 }
    01120             }
    01121         EnvironmentLength = (ULONG)(s - (PWCHAR)ProcessParameters->Environment) * sizeof(WCHAR);
    01122
    01123         Environment = NULL;
    01124         RegionSize = EnvironmentLength;
    01125         Status = ZwAllocateVirtualMemory( ProcessInformation->Process,
    01126                                           (PVOID *)&Environment,
    01127                                           0,
    01128                                           &RegionSize,
    01129                                           MEM_COMMIT,
    01130                                           PAGE_READWRITE
    01131                                         );
    01132         if ( !NT_SUCCESS( Status ) ) {
    01133             ZwClose( ProcessInformation->Process );
    01134             ZwClose( Section );
    01135             return( Status );
    01136             }
    01137
    01138         Status = ZwWriteVirtualMemory( ProcessInformation->Process,
    01139                                        Environment,
    01140                                        ProcessParameters->Environment,
    01141                                        EnvironmentLength,
    01142                                        NULL
    01143                                      );
    01144         if ( !NT_SUCCESS( Status ) ) {
    01145             ZwClose( ProcessInformation->Process );
    01146             ZwClose( Section );
    01147             return( Status );
    01148             }
    01149
    01150         ProcessParameters->Environment = Environment;
    01151         }
    01152
    01153     //
    01154     // Allocate virtual memory in the new process and use NtWriteVirtualMemory
    01155     // to write a copy of the process parameters block into the address
    01156     // space of the new process.  Set the initial parameter to the new thread
    01157     // to be the address of the block in the new process's address space.
    01158     //
    01159
    01160     Parameters = NULL;
    01161     ParameterLength = ProcessParameters->MaximumLength;
    01162     Status = ZwAllocateVirtualMemory( ProcessInformation->Process,
    01163                                       (PVOID *)&Parameters,
    01164                                       0,
    01165                                       &ParameterLength,
    01166                                       MEM_COMMIT,
    01167                                       PAGE_READWRITE
    01168                                     );
    01169     if ( !NT_SUCCESS( Status ) ) {
    01170         ZwClose( ProcessInformation->Process );
    01171         ZwClose( Section );
    01172         return( Status );
    01173         }
    01174
    01175     Status = ZwWriteVirtualMemory( ProcessInformation->Process,
    01176                                    Parameters,
    01177                                    ProcessParameters,
    01178                                    ProcessParameters->Length,
    01179                                    NULL
    01180                                  );
    01181     if ( !NT_SUCCESS( Status ) ) {
    01182             ZwClose( ProcessInformation->Process );
    01183             ZwClose( Section );
    01184             return( Status );
    01185             }
    01186
    01187     Status = ZwWriteVirtualMemory( ProcessInformation->Process,
    01188                                    &Peb->ProcessParameters,
    01189                                    &Parameters,
    01190                                    sizeof( Parameters ),
    01191                                    NULL
    01192                                  );
    01193     if ( !NT_SUCCESS( Status ) ) {
    01194         ZwClose( ProcessInformation->Process );
    01195         ZwClose( Section );
    01196         return( Status );
    01197         }
    01198
    01199     //
    01200     // Create a suspended thread in the new process.  Specify the size and
    01201     // position of the stack, along with the start address, initial parameter
    01202     // and an SECURITY_DESCRIPTOR.  The new thread will not have a name and its handle will
    01203     // not be inherited by other processes.
    01204     //
    01205
    01206     Status = RtlCreateUserThread(
    01207                  ProcessInformation->Process,
    01208                  ThreadSecurityDescriptor,
    01209                  TRUE,
    01210                  ProcessInformation->ImageInformation.ZeroBits,
    01211                  ProcessInformation->ImageInformation.MaximumStackSize,
    01212                  ProcessInformation->ImageInformation.CommittedStackSize,
    01213                  (PUSER_THREAD_START_ROUTINE)
    01214                      ProcessInformation->ImageInformation.TransferAddress,
    01215                  (PVOID)Peb,
    01216                  &ProcessInformation->Thread,
    01217                  &ProcessInformation->ClientId
    01218                  );
    01219     if ( !NT_SUCCESS( Status ) ) {
    01220         ZwClose( ProcessInformation->Process );
    01221         ZwClose( Section );
    01222         return( Status );
    01223         }
    01224
    01225     //
    01226     // Now close the section and file handles.  The objects they represent
    01227     // will not actually go away until the process is destroyed.
    01228     //
    01229
    01230     ZwClose( Section );
    01231
    01232     //
    01233     // Return success status
    01234     //
    01235
    01236     return( STATUS_SUCCESS );
    01237 }
    01238
    01239
    01240 NTSTATUS
    01241 RtlCreateUserThread(
    01242     IN HANDLE Process,
    01243     IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
    01244     IN BOOLEAN CreateSuspended,
    01245     IN ULONG ZeroBits OPTIONAL,
    01246     IN SIZE_T MaximumStackSize OPTIONAL,
    01247     IN SIZE_T CommittedStackSize OPTIONAL,
    01248     IN PUSER_THREAD_START_ROUTINE StartAddress,
    01249     IN PVOID Parameter OPTIONAL,
    01250     OUT PHANDLE Thread OPTIONAL,
    01251     OUT PCLIENT_ID ClientId OPTIONAL
    01252     )
    01253
    01254 /*++
    01255
    01256 Routine Description:
    01257
    01258     This function creates a user mode thread in a user process.  The caller
    01259     specifies the attributes of the new thread.  A handle to the thread, along
    01260     with its Client Id are returned to the caller.
    01261
    01262 Arguments:
    01263
    01264     Process - Handle to the target process in which to create the new thread.
    01265
    01266     ThreadSecurityDescriptor - An optional pointer to the Security Descriptor
    01267         give to the new thread.
    01268
    01269     CreateSuspended - A boolean parameter that specifies whether or not the new
    01270         thread is to be created suspended or not.  If TRUE, the new thread
    01271         will be created with an initial suspend count of 1.  If FALSE then
    01272         the new thread will be ready to run when this call returns.
    01273
    01274     ZeroBits - This parameter is passed to the virtual memory manager
    01275         when the stack is allocated.  Stacks are always allocated with the
    01276         MEM_TOP_DOWN allocation attribute.
    01277
    01278     MaximumStackSize - This is the maximum size of the stack.  This size
    01279         will be rounded up to the next highest page boundary.  If zero is
    01280         specified, then the default size will be 64K bytes.
    01281
    01282     CommittedStackSize - This is the initial committed size of the stack.  This
    01283         size is rounded up to the next highest page boundary and then an
    01284         additional page is added for the guard page.  The resulting size
    01285         will then be commited and the guard page protection initialized
    01286         for the last committed page in the stack.
    01287
    01288     StartAddress - The initial starting address of the thread.
    01289
    01290     Parameter - An optional pointer to a 32-bit pointer parameter that is
    01291         passed as a single argument to the procedure at the start address
    01292         location.
    01293
    01294     Thread - An optional pointer that, if specified, points to a variable that
    01295         will receive the handle of the new thread.
    01296
    01297     ClientId - An optional pointer that, if specified, points to a variable
    01298         that will receive the Client Id of the new thread.
    01299
    01300 Return Value:
    01301
    01302     TBS
    01303
    01304 --*/
    01305
    01306 {
    01307     NTSTATUS Status;
    01308     CONTEXT ThreadContext;
    01309     OBJECT_ATTRIBUTES ObjectAttributes;
    01310     INITIAL_TEB InitialTeb;
    01311     HANDLE ThreadHandle;
    01312     CLIENT_ID ThreadClientId;
    01313
    01314     //
    01315     // Allocate a stack for this thread in the address space of the target
    01316     // process.
    01317     //
    01318
    01319     Status = RtlpCreateStack( Process,
    01320                               MaximumStackSize,
    01321                               CommittedStackSize,
    01322                               ZeroBits,
    01323                               &InitialTeb
    01324                             );
    01325     if ( !NT_SUCCESS( Status ) ) {
    01326         return( Status );
    01327         }
    01328
    01329     //
    01330     // Create an initial context for the new thread.
    01331     //
    01332
    01333
    01334     RtlInitializeContext( Process,
    01335                           &ThreadContext,
    01336                           Parameter,
    01337                           (PVOID)StartAddress,
    01338                           InitialTeb.StackBase
    01339                         );
    01340
    01341     //
    01342     // Now create a thread in the target process.  The new thread will
    01343     // not have a name and its handle will not be inherited by other
    01344     // processes.
    01345     //
    01346
    01347     InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL,
    01348                                 ThreadSecurityDescriptor );
    01349     Status = ZwCreateThread( &ThreadHandle,
    01350                              THREAD_ALL_ACCESS,
    01351                              &ObjectAttributes,
    01352                              Process,
    01353                              &ThreadClientId,
    01354                              &ThreadContext,
    01355                              &InitialTeb,
    01356                              CreateSuspended
    01357                            );
    01358     if (!NT_SUCCESS( Status )) {
    01359 #if DBG
    01360         DbgPrint( "NTRTL: RtlCreateUserThread Failed. NtCreateThread Status == %X\n",
    01361                   Status );
    01362 #endif // DBG
    01363         RtlpFreeStack( Process, &InitialTeb );
    01364         }
    01365     else {
    01366         if (ARGUMENT_PRESENT( Thread )) {
    01367             *Thread = ThreadHandle;
    01368             }
    01369
    01370         if (ARGUMENT_PRESENT( ClientId )) {
    01371             *ClientId = ThreadClientId;
    01372             }
    01373
    01374         }
    01375
    01376     //
    01377     // Return status
    01378     //
    01379
    01380     return( Status );
    01381 }
    01382
    01383
    01384 VOID
    01385 RtlFreeUserThreadStack(
    01386     HANDLE hProcess,
    01387     HANDLE hThread
    01388     )
    01389 {
    01390     NTSTATUS Status;
    01391     PTEB Teb;
    01392     THREAD_BASIC_INFORMATION ThreadInfo;
    01393     PVOID StackDeallocationBase;
    01394     ULONG Length;
    01395     SIZE_T Size;
    01396
    01397     Status = NtQueryInformationThread( hThread,
    01398                                        ThreadBasicInformation,
    01399                                        &ThreadInfo,
    01400                                        sizeof( ThreadInfo ),
    01401                                        NULL
    01402                                      );
    01403     Teb = ThreadInfo.TebBaseAddress;
    01404     if (!NT_SUCCESS( Status ) || !Teb) {
    01405         return;
    01406         }
    01407
    01408     Status = NtReadVirtualMemory( hProcess,
    01409                                   &Teb->DeallocationStack,
    01410                                   &StackDeallocationBase,
    01411                                   sizeof( StackDeallocationBase ),
    01412                                   &Length
    01413                                 );
    01414     if (!NT_SUCCESS( Status ) || !StackDeallocationBase) {
    01415         return;
    01416         }
    01417
    01418     Size = 0;
    01419     NtFreeVirtualMemory( hProcess, &StackDeallocationBase, &Size, MEM_RELEASE );
    01420     return;
    01421 }