[KERNEL32]: Fix multiple issues in BaseCreateStack:

- StackLimit was set incorrectly.
- Code was not using BaseStaticServerdata, but querying NT instead.
- Fix memory leak in failure case.
- StackCommit and StackReserved values were not aligned correctly.
- Windows Server 2003+ feature of "Guaranteed Stack Commit Size" was not respected.
- Some math was screwy.
- Failure to get NT headers was not handled.

svn path=/trunk/; revision=54285
This commit is contained in:
Alex Ionescu 2011-11-03 06:46:22 +00:00
parent e5f31ab0a9
commit 4ba4fdcb2c
5 changed files with 60 additions and 51 deletions

View file

@ -201,7 +201,7 @@ CreateFiberEx(SIZE_T dwStackCommitSize,
} }
/* Create the stack for the fiber */ /* Create the stack for the fiber */
Status = BasepCreateStack(NtCurrentProcess(), Status = BaseCreateStack(NtCurrentProcess(),
dwStackCommitSize, dwStackCommitSize,
dwStackReserveSize, dwStackReserveSize,
&InitialTeb); &InitialTeb);

View file

@ -187,7 +187,7 @@ BasepCreateFirstThread(HANDLE ProcessHandle,
DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle); DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle);
/* Create the Thread's Stack */ /* Create the Thread's Stack */
BasepCreateStack(ProcessHandle, BaseCreateStack(ProcessHandle,
SectionImageInfo->MaximumStackSize, SectionImageInfo->MaximumStackSize,
SectionImageInfo->CommittedStackSize, SectionImageInfo->CommittedStackSize,
&InitialTeb); &InitialTeb);

View file

@ -137,7 +137,7 @@ CreateRemoteThread(HANDLE hProcess,
ClientId.UniqueProcess = hProcess; ClientId.UniqueProcess = hProcess;
/* Create the Stack */ /* Create the Stack */
Status = BasepCreateStack(hProcess, Status = BaseCreateStack(hProcess,
dwStackSize, dwStackSize,
dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION ? dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION ?
dwStackSize : 0, dwStackSize : 0,

View file

@ -247,60 +247,64 @@ BaseFormatObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes,
*/ */
NTSTATUS NTSTATUS
WINAPI WINAPI
BasepCreateStack(HANDLE hProcess, BaseCreateStack(HANDLE hProcess,
SIZE_T StackReserve, SIZE_T StackReserve,
SIZE_T StackCommit, SIZE_T StackCommit,
PINITIAL_TEB InitialTeb) PINITIAL_TEB InitialTeb)
{ {
NTSTATUS Status; NTSTATUS Status;
SYSTEM_BASIC_INFORMATION SystemBasicInfo;
PIMAGE_NT_HEADERS Headers; PIMAGE_NT_HEADERS Headers;
ULONG_PTR Stack = 0; ULONG_PTR Stack;
BOOLEAN UseGuard = FALSE; BOOLEAN UseGuard;
ULONG PageSize, Dummy, AllocationGranularity;
DPRINT("BasepCreateStack (hProcess: %lx, Max: %lx, Current: %lx)\n", SIZE_T StackReserveHeader, StackCommitHeader, GuardPageSize, GuaranteedStackCommit;
DPRINT("BaseCreateStack (hProcess: %lx, Max: %lx, Current: %lx)\n",
hProcess, StackReserve, StackCommit); hProcess, StackReserve, StackCommit);
/* Get some memory information */ /* Read page size */
Status = NtQuerySystemInformation(SystemBasicInformation, PageSize = BaseStaticServerData->SysInfo.PageSize;
&SystemBasicInfo, AllocationGranularity = BaseStaticServerData->SysInfo.AllocationGranularity;
sizeof(SYSTEM_BASIC_INFORMATION),
NULL); /* Get the Image Headers */
if (!NT_SUCCESS(Status)) Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
if (!Headers) return STATUS_INVALID_IMAGE_FORMAT;
StackCommitHeader = Headers->OptionalHeader.SizeOfStackCommit;
StackReserveHeader = Headers->OptionalHeader.SizeOfStackReserve;
if (!StackReserve) StackReserve = StackReserveHeader;
if (!StackCommit)
{ {
DPRINT1("Failure to query system info\n"); StackCommit = StackCommitHeader;
return Status; }
else if (StackCommit >= StackReserve)
{
StackReserve = ROUND_UP(StackCommit, 1024 * 1024);
}
StackCommit = ROUND_UP(StackCommit, PageSize);
StackReserve = ROUND_UP(StackReserve, AllocationGranularity);
GuaranteedStackCommit = NtCurrentTeb()->GuaranteedStackBytes;
if ((GuaranteedStackCommit) && (StackCommit < GuaranteedStackCommit))
{
StackCommit = GuaranteedStackCommit;
} }
/* Use the Image Settings if we are dealing with the current Process */ if (StackCommit >= StackReserve)
if (hProcess == NtCurrentProcess())
{ {
/* Get the Image Headers */ StackReserve = ROUND_UP(StackCommit, 1024 * 1024);
Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
/* If we didn't get the parameters, find them ourselves */
StackReserve = (StackReserve) ?
StackReserve : Headers->OptionalHeader.SizeOfStackReserve;
StackCommit = (StackCommit) ?
StackCommit : Headers->OptionalHeader.SizeOfStackCommit;
}
else
{
/* Use the System Settings if needed */
StackReserve = (StackReserve) ? StackReserve :
SystemBasicInfo.AllocationGranularity;
StackCommit = (StackCommit) ? StackCommit : SystemBasicInfo.PageSize;
} }
/* Align everything to Page Size */ StackCommit = ROUND_UP(StackCommit, PageSize);
StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity); StackReserve = ROUND_UP(StackReserve, AllocationGranularity);
StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize);
#if 1 // FIXME: Remove once Guard Page support is here /* ROS Hack until we support guard page stack expansion */
StackCommit = StackReserve; StackCommit = StackReserve;
#endif
DPRINT("StackReserve: %lx, StackCommit: %lx\n", StackReserve, StackCommit);
/* Reserve memory for the stack */ /* Reserve memory for the stack */
Stack = 0;
Status = ZwAllocateVirtualMemory(hProcess, Status = ZwAllocateVirtualMemory(hProcess,
(PVOID*)&Stack, (PVOID*)&Stack,
0, 0,
@ -309,7 +313,7 @@ BasepCreateStack(HANDLE hProcess,
PAGE_READWRITE); PAGE_READWRITE);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failure to reserve stack\n"); DPRINT1("Failure to reserve stack: %lx\n", Status);
return Status; return Status;
} }
@ -325,11 +329,15 @@ BasepCreateStack(HANDLE hProcess,
/* Check if we will need a guard page */ /* Check if we will need a guard page */
if (StackReserve > StackCommit) if (StackReserve > StackCommit)
{ {
Stack -= SystemBasicInfo.PageSize; Stack -= PageSize;
StackCommit += SystemBasicInfo.PageSize; StackCommit += PageSize;
UseGuard = TRUE; UseGuard = TRUE;
} }
else
{
UseGuard = FALSE;
}
/* Allocate memory for the stack */ /* Allocate memory for the stack */
Status = ZwAllocateVirtualMemory(hProcess, Status = ZwAllocateVirtualMemory(hProcess,
(PVOID*)&Stack, (PVOID*)&Stack,
@ -340,6 +348,8 @@ BasepCreateStack(HANDLE hProcess,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failure to allocate stack\n"); DPRINT1("Failure to allocate stack\n");
GuardPageSize = 0;
ZwFreeVirtualMemory(hProcess, (PVOID*)&Stack, &GuardPageSize, MEM_RELEASE);
return Status; return Status;
} }
@ -349,10 +359,8 @@ BasepCreateStack(HANDLE hProcess,
/* Create a guard page */ /* Create a guard page */
if (UseGuard) if (UseGuard)
{ {
SIZE_T GuardPageSize = SystemBasicInfo.PageSize; /* Set the guard page */
ULONG Dummy; GuardPageSize = PAGE_SIZE;
/* Attempt maximum space possible */
Status = ZwProtectVirtualMemory(hProcess, Status = ZwProtectVirtualMemory(hProcess,
(PVOID*)&Stack, (PVOID*)&Stack,
&GuardPageSize, &GuardPageSize,
@ -360,12 +368,13 @@ BasepCreateStack(HANDLE hProcess,
&Dummy); &Dummy);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failure to create guard page\n"); DPRINT1("Failure to set guard page\n");
return Status; return Status;
} }
/* Update the Stack Limit keeping in mind the Guard Page */ /* Update the Stack Limit keeping in mind the Guard Page */
InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit - GuardPageSize); InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit +
GuardPageSize);
} }
/* We are done! */ /* We are done! */

View file

@ -173,7 +173,7 @@ BaseFormatObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes,
NTSTATUS NTSTATUS
WINAPI WINAPI
BasepCreateStack(HANDLE hProcess, BaseCreateStack(HANDLE hProcess,
SIZE_T StackReserve, SIZE_T StackReserve,
SIZE_T StackCommit, SIZE_T StackCommit,
PINITIAL_TEB InitialTeb); PINITIAL_TEB InitialTeb);