[KERNEL32][RTL] Diverse fixes/improvements for thread stack creation code. (#802)

- kernel32!BaseCreateStack() is compatible with ntdll!RtlpCreateUserStack().
- When checking whether a stack guard page can be added, its size has to
  be accounted for in the checking logic.
- We have to satisfy the PEB::MinimumStackCommit constraint.
- We cannot use PEB::GuaranteedStackBytes in BaseCreateStack() since it is
  nowhere initialized (default is 0). It gets initialized to a non-zero
  value when the user manually calls SetThreadStackGuarantee().
  https://www.installsetupconfig.com/win32programming/windowsthreadsprocessapis7_6.html

- RtlpCreateUserStack(): Fix memory leak in failure case.
- RtlpFreeUserStack() doesn't need to return anything.

See also commit 1bc59379 (r59868).

CORE-11319
This commit is contained in:
Hermès Bélusca-Maïto 2016-05-26 04:44:25 +02:00
parent 4895f21efa
commit effdb6f232
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
4 changed files with 102 additions and 75 deletions

View file

@ -346,22 +346,25 @@ BaseFormatObjectAttributes(OUT POBJECT_ATTRIBUTES ObjectAttributes,
}
/*
* Creates a stack for a thread or fiber
* Creates a stack for a thread or fiber.
* NOTE: Adapted from sdk/lib/rtl/thread.c:RtlpCreateUserStack().
*/
NTSTATUS
WINAPI
BaseCreateStack(HANDLE hProcess,
SIZE_T StackCommit,
SIZE_T StackReserve,
PINITIAL_TEB InitialTeb)
BaseCreateStack(
_In_ HANDLE hProcess,
_In_opt_ SIZE_T StackCommit,
_In_opt_ SIZE_T StackReserve,
_Out_ PINITIAL_TEB InitialTeb)
{
NTSTATUS Status;
PIMAGE_NT_HEADERS Headers;
ULONG_PTR Stack;
BOOLEAN UseGuard;
ULONG PageSize, Dummy, AllocationGranularity;
SIZE_T StackReserveHeader, StackCommitHeader, GuardPageSize, GuaranteedStackCommit;
DPRINT("BaseCreateStack (hProcess: %p, Max: %lx, Current: %lx)\n",
ULONG PageSize, AllocationGranularity, Dummy;
SIZE_T MinimumStackCommit, GuardPageSize;
DPRINT("BaseCreateStack(hProcess: 0x%p, Max: 0x%lx, Current: 0x%lx)\n",
hProcess, StackReserve, StackCommit);
/* Read page size */
@ -372,34 +375,38 @@ BaseCreateStack(HANDLE hProcess,
Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
if (!Headers) return STATUS_INVALID_IMAGE_FORMAT;
StackCommitHeader = Headers->OptionalHeader.SizeOfStackCommit;
StackReserveHeader = Headers->OptionalHeader.SizeOfStackReserve;
if (StackReserve == 0)
StackReserve = Headers->OptionalHeader.SizeOfStackReserve;
if (!StackReserve) StackReserve = StackReserveHeader;
if (!StackCommit)
if (StackCommit == 0)
{
StackCommit = StackCommitHeader;
StackCommit = Headers->OptionalHeader.SizeOfStackCommit;
}
/* Check if the commit is higher than the reserve */
else if (StackCommit >= StackReserve)
{
/* Grow the reserve beyond the commit, up to 1MB alignment */
StackReserve = ROUND_UP(StackCommit, 1024 * 1024);
}
/* Align everything to Page Size */
StackCommit = ROUND_UP(StackCommit, PageSize);
StackReserve = ROUND_UP(StackReserve, AllocationGranularity);
GuaranteedStackCommit = NtCurrentTeb()->GuaranteedStackBytes;
if ((GuaranteedStackCommit) && (StackCommit < GuaranteedStackCommit))
MinimumStackCommit = NtCurrentPeb()->MinimumStackCommit;
if ((MinimumStackCommit != 0) && (StackCommit < MinimumStackCommit))
{
StackCommit = GuaranteedStackCommit;
StackCommit = MinimumStackCommit;
}
/* Check if the commit is higher than the reserve */
if (StackCommit >= StackReserve)
{
/* Grow the reserve beyond the commit, up to 1MB alignment */
StackReserve = ROUND_UP(StackCommit, 1024 * 1024);
}
/* Align everything to Page Size */
StackCommit = ROUND_UP(StackCommit, PageSize);
StackReserve = ROUND_UP(StackReserve, AllocationGranularity);
@ -423,11 +430,11 @@ BaseCreateStack(HANDLE hProcess,
InitialTeb->PreviousStackBase = NULL;
InitialTeb->PreviousStackLimit = NULL;
/* Update the Stack Position */
/* Update the stack position */
Stack += StackReserve - StackCommit;
/* Check if we will need a guard page */
if (StackReserve > StackCommit)
/* Check if we can add a guard page */
if (StackReserve >= StackCommit + PageSize)
{
Stack -= PageSize;
StackCommit += PageSize;
@ -456,11 +463,10 @@ BaseCreateStack(HANDLE hProcess,
/* Now set the current Stack Limit */
InitialTeb->StackLimit = (PVOID)Stack;
/* Create a guard page */
/* Create a guard page if needed */
if (UseGuard)
{
/* Set the guard page */
GuardPageSize = PAGE_SIZE;
GuardPageSize = PageSize;
Status = NtProtectVirtualMemory(hProcess,
(PVOID*)&Stack,
&GuardPageSize,
@ -481,10 +487,14 @@ BaseCreateStack(HANDLE hProcess,
return STATUS_SUCCESS;
}
/*
* NOTE: Adapted from sdk/lib/rtl/thread.c:RtlpFreeUserStack().
*/
VOID
WINAPI
BaseFreeThreadStack(IN HANDLE hProcess,
IN PINITIAL_TEB InitialTeb)
BaseFreeThreadStack(
_In_ HANDLE hProcess,
_In_ PINITIAL_TEB InitialTeb)
{
SIZE_T Dummy = 0;
@ -501,10 +511,10 @@ BaseFreeThreadStack(IN HANDLE hProcess,
VOID
WINAPI
BaseInitializeContext(IN PCONTEXT Context,
IN PVOID Parameter,
IN PVOID StartAddress,
IN PVOID StackAddress,
IN ULONG ContextType)
IN PVOID Parameter,
IN PVOID StartAddress,
IN PVOID StackAddress,
IN ULONG ContextType)
{
#ifdef _M_IX86
ULONG ContextFlags;