mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 13:56:05 +00:00
[SMSS][NTOS:MM] Implement the architecture-specific pagefile size limits + code review. (#4843)
What we have: - Maximum number of pagefiles: 16 - Minimum pagefile size: 256 pages (1 MB when page size = 4096 bytes) - Maximum pagefile size: * 32-bit platforms: (1024 * 1024 - 1) pages (~ 4095 MB) * x86 with PAE support: same size as for AMD x64 * x64 platform: (4 * 1024 * 1024 * 1024 - 1) pages (~ 16 TB) * IA64 platform: (8 * 1024 * 1024 * 1024 - 1) pages (~ 32 TB) Those are the values as supported and verified by the NT kernel. Now, user-mode programs (including SMSS.EXE) have different opinions on these, namely, they consider estimates directly in MB, respectively: 4095 MB, (16 * 1024 * 1024) MB, and (32 * 1024 * 1024) MB (verified on Win2k3 and Win7 32 and 64 bits). Also here, the minimum pagefile size is set to 2 MB. Starting Windows 8+ (and 10), those values change slightly, and are still not fully synchronized between NTOS:MM and SMSS. Finally, while (x86 PAE and) AMD64 and ARM64 seem to share the maximum pagefile size limit, 32-bit ARMv7 appears to use different limits than regular x86 (2 GB instead of 4). Please keep those values as they are for NT compatibility! See the following references: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/mm/modwrite/create.htm https://techcommunity.microsoft.com/t5/ask-the-performance-team/what-is-the-page-file-for-anyway/ba-p/372608 + Manual extraction of the values from different NT 6.2,6.3,10 builds. [SMSS] Fill out in particular the x86-specific case for PAE. [NTOS:MM] Some cleanup in the NtCreatePagingFile() code, namely: - Clarify some comments; - Validate the lower and upper bounds of the Minimum and Maximum sizes (based on Windows behaviour as explained by Geoff + manual tests). - Open the pagefile in case-insensitive; - Simplify the loop that finds an existing matching pagefile; - Simplify some failure exit paths; - Add a "Missing validation steps TODO" comment block explaining the existing code-hole.
This commit is contained in:
parent
5dc43c0f32
commit
a4274ad548
2 changed files with 191 additions and 135 deletions
|
@ -20,8 +20,63 @@
|
||||||
//
|
//
|
||||||
#define STANDARD_PAGING_FILE_NAME L"\\??\\?:\\pagefile.sys"
|
#define STANDARD_PAGING_FILE_NAME L"\\??\\?:\\pagefile.sys"
|
||||||
#define STANDARD_DRIVE_LETTER_OFFSET 4
|
#define STANDARD_DRIVE_LETTER_OFFSET 4
|
||||||
#define MEGABYTE 0x100000UL
|
#define MAX_PAGING_FILES 16 // See also ntoskrnl/include/internal/mm.h
|
||||||
#define MAXIMUM_PAGEFILE_SIZE (4095 * MEGABYTE)
|
#define MEGABYTE (1024 * 1024)
|
||||||
|
|
||||||
|
/* Minimum pagefile size is 256 pages (1 MB) */
|
||||||
|
// #define MINIMUM_PAGEFILE_SIZE (256ULL * PAGE_SIZE)
|
||||||
|
|
||||||
|
/* Maximum pagefile sizes for different architectures */
|
||||||
|
#define GIGABYTE (1024ULL * MEGABYTE)
|
||||||
|
#define TERABYTE (1024ULL * GIGABYTE)
|
||||||
|
|
||||||
|
// NOTE: No changes for NTDDI_WIN10
|
||||||
|
#if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE32 ((1ULL * 1024 * 1024 - 1) * PAGE_SIZE)
|
||||||
|
// PAGE_ROUND_DOWN(4ULL * GIGABYTE - 1)
|
||||||
|
#else
|
||||||
|
/* 4095 MB */
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE32 (4095ULL * MEGABYTE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// NOTE: No changes for NTDDI_WIN10
|
||||||
|
#if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE64 ((4ULL * 1024 * 1024 * 1024 - 1) * PAGE_SIZE)
|
||||||
|
// PAGE_ROUND_DOWN(16ULL * TERABYTE - 1)
|
||||||
|
#else
|
||||||
|
/* 16 TB */
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE64 (16ULL * TERABYTE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_M_IX86)
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE32
|
||||||
|
/* PAE uses the same size as x64 */
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE_PAE MAXIMUM_PAGEFILE_SIZE64
|
||||||
|
#elif defined (_M_AMD64) || defined(_M_ARM64)
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE64
|
||||||
|
#elif defined (_M_IA64)
|
||||||
|
/* 32 TB */
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE (32ULL * TERABYTE)
|
||||||
|
#elif defined(_M_ARM)
|
||||||
|
/* Around 2 GB */
|
||||||
|
// NOTE: No changes for NTDDI_WIN10
|
||||||
|
#if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE ((512ULL * 1024 - 1) * PAGE_SIZE)
|
||||||
|
// PAGE_ROUND_DOWN(2ULL * GIGABYTE - 1)
|
||||||
|
#else
|
||||||
|
/* 4095 MB */
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE32
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
/* On unknown architectures, default to either one of the 32 or 64 bit sizes */
|
||||||
|
#pragma message("Unknown architecture")
|
||||||
|
#ifdef _WIN64
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE64
|
||||||
|
#else
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE MAXIMUM_PAGEFILE_SIZE32
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This should be 32 MB, but we need more than that for 2nd stage setup */
|
/* This should be 32 MB, but we need more than that for 2nd stage setup */
|
||||||
#define MINIMUM_TO_KEEP_FREE (256 * MEGABYTE)
|
#define MINIMUM_TO_KEEP_FREE (256 * MEGABYTE)
|
||||||
#define FUZZ_FACTOR (16 * MEGABYTE)
|
#define FUZZ_FACTOR (16 * MEGABYTE)
|
||||||
|
@ -93,7 +148,7 @@ SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken)
|
||||||
UNICODE_STRING PageFileName, Arguments, SecondArgument;
|
UNICODE_STRING PageFileName, Arguments, SecondArgument;
|
||||||
|
|
||||||
/* Make sure we don't have too many */
|
/* Make sure we don't have too many */
|
||||||
if (SmpNumberOfPagingFiles >= 16)
|
if (SmpNumberOfPagingFiles >= MAX_PAGING_FILES)
|
||||||
{
|
{
|
||||||
DPRINT1("SMSS:PFILE: Too many paging files specified - %lu\n",
|
DPRINT1("SMSS:PFILE: Too many paging files specified - %lu\n",
|
||||||
SmpNumberOfPagingFiles);
|
SmpNumberOfPagingFiles);
|
||||||
|
@ -110,7 +165,7 @@ SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken)
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
/* Fail */
|
/* Fail */
|
||||||
DPRINT1("SMSS:PFILE: SmpParseCommandLine( %wZ ) failed - Status == %lx\n",
|
DPRINT1("SMSS:PFILE: SmpParseCommandLine(%wZ) failed - Status == %lx\n",
|
||||||
PageFileToken, Status);
|
PageFileToken, Status);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
@ -198,7 +253,8 @@ SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken)
|
||||||
Descriptor->Name = PageFileName;
|
Descriptor->Name = PageFileName;
|
||||||
Descriptor->MinSize.QuadPart = MinSize * MEGABYTE;
|
Descriptor->MinSize.QuadPart = MinSize * MEGABYTE;
|
||||||
Descriptor->MaxSize.QuadPart = MaxSize * MEGABYTE;
|
Descriptor->MaxSize.QuadPart = MaxSize * MEGABYTE;
|
||||||
if (SystemManaged) Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED;
|
if (SystemManaged)
|
||||||
|
Descriptor->Flags |= SMP_PAGEFILE_SYSTEM_MANAGED;
|
||||||
Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] =
|
Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] =
|
||||||
RtlUpcaseUnicodeChar(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET]);
|
RtlUpcaseUnicodeChar(Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET]);
|
||||||
if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == '?')
|
if (Descriptor->Name.Buffer[STANDARD_DRIVE_LETTER_OFFSET] == '?')
|
||||||
|
@ -659,7 +715,7 @@ NTAPI
|
||||||
SmpMakeSystemManagedPagingFileDescriptor(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)
|
SmpMakeSystemManagedPagingFileDescriptor(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
LONGLONG MinimumSize, MaximumSize, Ram;
|
ULONGLONG MinimumSize, MaximumSize, Ram;
|
||||||
SYSTEM_BASIC_INFORMATION BasicInfo;
|
SYSTEM_BASIC_INFORMATION BasicInfo;
|
||||||
|
|
||||||
/* Query the page size of the system, and the amount of RAM */
|
/* Query the page size of the system, and the amount of RAM */
|
||||||
|
@ -693,8 +749,15 @@ NTAPI
|
||||||
SmpValidatePagingFileSizes(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)
|
SmpValidatePagingFileSizes(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)
|
||||||
{
|
{
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
ULONGLONG MinSize, MaxSize;
|
|
||||||
BOOLEAN WasTooBig = FALSE;
|
BOOLEAN WasTooBig = FALSE;
|
||||||
|
ULONGLONG MinSize, MaxSize;
|
||||||
|
#ifdef _M_IX86
|
||||||
|
ULONGLONG MaxPageFileSize =
|
||||||
|
(SharedUserData->ProcessorFeatures[PF_PAE_ENABLED])
|
||||||
|
? MAXIMUM_PAGEFILE_SIZE_PAE : MAXIMUM_PAGEFILE_SIZE;
|
||||||
|
#else
|
||||||
|
static const ULONGLONG MaxPageFileSize = MAXIMUM_PAGEFILE_SIZE;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Capture the min and max */
|
/* Capture the min and max */
|
||||||
MinSize = Descriptor->MinSize.QuadPart;
|
MinSize = Descriptor->MinSize.QuadPart;
|
||||||
|
@ -704,28 +767,19 @@ SmpValidatePagingFileSizes(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)
|
||||||
&Descriptor->Name, MinSize, MaxSize);
|
&Descriptor->Name, MinSize, MaxSize);
|
||||||
|
|
||||||
/* Don't let minimum be bigger than maximum */
|
/* Don't let minimum be bigger than maximum */
|
||||||
if (MinSize > MaxSize) MaxSize = MinSize;
|
if (MinSize > MaxSize)
|
||||||
|
MaxSize = MinSize;
|
||||||
|
|
||||||
/* On PAE we can have bigger pagefiles... */
|
/* Validate the minimum and maximum and trim them if they are too large */
|
||||||
if (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED])
|
if (MinSize > MaxPageFileSize)
|
||||||
{
|
{
|
||||||
/* But we don't support that yet */
|
WasTooBig = TRUE;
|
||||||
DPRINT1("ReactOS does not support PAE yet... assuming sizes OK\n");
|
MinSize = MaxPageFileSize;
|
||||||
}
|
}
|
||||||
else
|
if (MaxSize > MaxPageFileSize)
|
||||||
{
|
{
|
||||||
/* Validate the minimum and maximum and trim them if they are too large */
|
WasTooBig = TRUE;
|
||||||
if (MinSize > MAXIMUM_PAGEFILE_SIZE)
|
MaxSize = MaxPageFileSize;
|
||||||
{
|
|
||||||
WasTooBig = TRUE;
|
|
||||||
MinSize = MAXIMUM_PAGEFILE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MaxSize > MAXIMUM_PAGEFILE_SIZE)
|
|
||||||
{
|
|
||||||
WasTooBig = TRUE;
|
|
||||||
MaxSize = MAXIMUM_PAGEFILE_SIZE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we trimmed, write a flag in the descriptor */
|
/* If we trimmed, write a flag in the descriptor */
|
||||||
|
@ -752,7 +806,7 @@ SmpCreateSystemManagedPagingFile(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor,
|
||||||
/* Make sure there is at least 1 paging file and that we are system-managed */
|
/* Make sure there is at least 1 paging file and that we are system-managed */
|
||||||
ASSERT(SmpNumberOfPagingFiles >= 1);
|
ASSERT(SmpNumberOfPagingFiles >= 1);
|
||||||
ASSERT(!IsListEmpty(&SmpPagingFileDescriptorList));
|
ASSERT(!IsListEmpty(&SmpPagingFileDescriptorList));
|
||||||
ASSERT(Descriptor->Flags & SMP_PAGEFILE_SYSTEM_MANAGED); // Descriptor->SystemManaged == 1 in ASSERT.
|
ASSERT(Descriptor->Flags & SMP_PAGEFILE_SYSTEM_MANAGED);
|
||||||
|
|
||||||
/* Keep decreasing the pagefile by this amount if we run out of space */
|
/* Keep decreasing the pagefile by this amount if we run out of space */
|
||||||
FuzzFactor.QuadPart = FUZZ_FACTOR;
|
FuzzFactor.QuadPart = FUZZ_FACTOR;
|
||||||
|
|
|
@ -1,29 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* ReactOS kernel
|
* PROJECT: ReactOS Kernel
|
||||||
* Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
*
|
* PURPOSE: Paging file functions
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* COPYRIGHT: Copyright 1998-2003 David Welch <welch@mcmail.com>
|
||||||
* it under the terms of the GNU General Public License as published by
|
* Copyright 2010-2018 Pierre Schweitzer <pierre@reactos.org>
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* PROJECT: ReactOS kernel
|
|
||||||
* FILE: ntoskrnl/mm/pagefile.c
|
|
||||||
* PURPOSE: Paging file functions
|
|
||||||
* PROGRAMMER: David Welch (welch@mcmail.com)
|
|
||||||
* Pierre Schweitzer
|
|
||||||
* UPDATE HISTORY:
|
|
||||||
* Created 22/05/98
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES *****************************************************************/
|
||||||
|
@ -34,7 +14,44 @@
|
||||||
|
|
||||||
/* GLOBALS *******************************************************************/
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
#define PAIRS_PER_RUN (1024)
|
/* Minimum pagefile size is 256 pages (1 MB) */
|
||||||
|
#define MINIMUM_PAGEFILE_SIZE (256ULL * PAGE_SIZE)
|
||||||
|
|
||||||
|
/* Maximum pagefile sizes for different architectures */
|
||||||
|
#if defined(_M_IX86) && !defined(_X86PAE_)
|
||||||
|
/* Around 4 GB */
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE ((1ULL * 1024 * 1024 - 1) * PAGE_SIZE)
|
||||||
|
// PAGE_ROUND_DOWN(4ULL * GIGABYTE - 1)
|
||||||
|
/* PAE uses the same size as x64 */
|
||||||
|
#elif (defined(_M_IX86) && defined(_X86PAE_)) || defined (_M_AMD64) || defined(_M_ARM64)
|
||||||
|
/* Around 16 TB */
|
||||||
|
#if (NTDDI_VERSION >= NTDDI_WIN10)
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE ((4ULL * 1024 * 1024 * 1024 - 2) * PAGE_SIZE)
|
||||||
|
// PAGE_ROUND_DOWN(16ULL * TERABYTE - PAGE_SIZE - 1)
|
||||||
|
#else
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE ((4ULL * 1024 * 1024 * 1024 - 1) * PAGE_SIZE)
|
||||||
|
// PAGE_ROUND_DOWN(16ULL * TERABYTE - 1)
|
||||||
|
#endif
|
||||||
|
#elif defined (_M_IA64)
|
||||||
|
/* Around 32 TB */
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE ((8ULL * 1024 * 1024 * 1024 - 1) * PAGE_SIZE)
|
||||||
|
// PAGE_ROUND_DOWN(32ULL * TERABYTE - 1)
|
||||||
|
#elif defined(_M_ARM)
|
||||||
|
/* Around 2 GB */
|
||||||
|
#if (NTDDI_VERSION >= NTDDI_WIN10)
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE ((512ULL * 1024 - 2) * PAGE_SIZE)
|
||||||
|
// PAGE_ROUND_DOWN(2ULL * GIGABYTE - PAGE_SIZE - 1)
|
||||||
|
#elif (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE ((512ULL * 1024 - 1) * PAGE_SIZE)
|
||||||
|
// PAGE_ROUND_DOWN(2ULL * GIGABYTE - 1)
|
||||||
|
#else
|
||||||
|
/* Around 4 GB */
|
||||||
|
#define MAXIMUM_PAGEFILE_SIZE ((1ULL * 1024 * 1024 - 1) * PAGE_SIZE)
|
||||||
|
// PAGE_ROUND_DOWN(4ULL * GIGABYTE - 1)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#error Unknown architecture
|
||||||
|
#endif
|
||||||
|
|
||||||
/* List of paging files, both used and free */
|
/* List of paging files, both used and free */
|
||||||
PMMPAGING_FILE MmPagingFile[MAX_PAGING_FILES];
|
PMMPAGING_FILE MmPagingFile[MAX_PAGING_FILES];
|
||||||
|
@ -409,33 +426,32 @@ NtCreatePagingFile(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pagefiles can't be larger than 4GB and of course
|
* Pagefiles cannot be larger than the platform-specific memory addressable
|
||||||
* the minimum should be smaller than the maximum.
|
* limits, and of course the minimum should be smaller than the maximum.
|
||||||
*/
|
*/
|
||||||
// TODO: Actually validate the lower bound of these sizes!
|
if (SafeMinimumSize.QuadPart < MINIMUM_PAGEFILE_SIZE ||
|
||||||
if (0 != SafeMinimumSize.u.HighPart)
|
SafeMinimumSize.QuadPart > MAXIMUM_PAGEFILE_SIZE)
|
||||||
{
|
{
|
||||||
return STATUS_INVALID_PARAMETER_2;
|
return STATUS_INVALID_PARAMETER_2;
|
||||||
}
|
}
|
||||||
if (0 != SafeMaximumSize.u.HighPart)
|
if (SafeMaximumSize.QuadPart < SafeMinimumSize.QuadPart ||
|
||||||
|
SafeMaximumSize.QuadPart > MAXIMUM_PAGEFILE_SIZE)
|
||||||
{
|
{
|
||||||
return STATUS_INVALID_PARAMETER_3;
|
return STATUS_INVALID_PARAMETER_3;
|
||||||
}
|
}
|
||||||
if (SafeMaximumSize.u.LowPart < SafeMinimumSize.u.LowPart)
|
|
||||||
{
|
|
||||||
return STATUS_INVALID_PARAMETER_MIX;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Validate the name length */
|
/* Validate the name length */
|
||||||
if ((PageFileName.Length == 0) ||
|
if ((PageFileName.Length == 0) ||
|
||||||
(PageFileName.Length > 128 * sizeof(WCHAR)))
|
(PageFileName.Length > MAXIMUM_FILENAME_LENGTH))
|
||||||
{
|
{
|
||||||
return STATUS_OBJECT_NAME_INVALID;
|
return STATUS_OBJECT_NAME_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We don't care about any potential UNICODE_NULL */
|
/* Allocate a buffer to keep the name copy. Note that it is kept only
|
||||||
|
* for information purposes, so it gets allocated in the paged pool,
|
||||||
|
* even if it will be stored in the PagingFile structure, that is
|
||||||
|
* allocated from non-paged pool (see below). */
|
||||||
PageFileName.MaximumLength = PageFileName.Length;
|
PageFileName.MaximumLength = PageFileName.Length;
|
||||||
/* Allocate a buffer to keep the name copy */
|
|
||||||
Buffer = ExAllocatePoolWithTag(PagedPool, PageFileName.Length, TAG_MM);
|
Buffer = ExAllocatePoolWithTag(PagedPool, PageFileName.Length, TAG_MM);
|
||||||
if (Buffer == NULL)
|
if (Buffer == NULL)
|
||||||
{
|
{
|
||||||
|
@ -488,42 +504,26 @@ NtCreatePagingFile(
|
||||||
/* Initialize the DACL */
|
/* Initialize the DACL */
|
||||||
Status = RtlCreateAcl(Dacl, Count, ACL_REVISION);
|
Status = RtlCreateAcl(Dacl, Count, ACL_REVISION);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
goto EarlyQuit;
|
||||||
ExFreePoolWithTag(Dacl, TAG_DACL);
|
|
||||||
ExFreePoolWithTag(Buffer, TAG_MM);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Grant full access to admins */
|
/* Grant full access to admins */
|
||||||
Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeAliasAdminsSid);
|
Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeAliasAdminsSid);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
goto EarlyQuit;
|
||||||
ExFreePoolWithTag(Dacl, TAG_DACL);
|
|
||||||
ExFreePoolWithTag(Buffer, TAG_MM);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Grant full access to SYSTEM */
|
/* Grant full access to SYSTEM */
|
||||||
Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeLocalSystemSid);
|
Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeLocalSystemSid);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
goto EarlyQuit;
|
||||||
ExFreePoolWithTag(Dacl, TAG_DACL);
|
|
||||||
ExFreePoolWithTag(Buffer, TAG_MM);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Attach the DACL to the security descriptor */
|
/* Attach the DACL to the security descriptor */
|
||||||
Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE);
|
Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
goto EarlyQuit;
|
||||||
ExFreePoolWithTag(Dacl, TAG_DACL);
|
|
||||||
ExFreePoolWithTag(Buffer, TAG_MM);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
&PageFileName,
|
&PageFileName,
|
||||||
OBJ_KERNEL_HANDLE,
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||||||
NULL,
|
NULL,
|
||||||
&SecurityDescriptor);
|
&SecurityDescriptor);
|
||||||
|
|
||||||
|
@ -549,10 +549,10 @@ NtCreatePagingFile(
|
||||||
0,
|
0,
|
||||||
CreateFileTypeNone,
|
CreateFileTypeNone,
|
||||||
NULL,
|
NULL,
|
||||||
SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
|
IO_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
|
||||||
/* If we failed, relax a bit constraints, someone may be already holding the
|
/* If we failed, relax a bit constraints, someone may be already holding the
|
||||||
* the file, so share write, don't attempt to replace and don't delete on close
|
* the file, so share write, don't attempt to replace and don't delete on close
|
||||||
* (basically, don't do anything conflicting)
|
* (basically, don't do anything conflicting).
|
||||||
* This can happen if the caller attempts to extend a page file.
|
* This can happen if the caller attempts to extend a page file.
|
||||||
*/
|
*/
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
|
@ -572,13 +572,9 @@ NtCreatePagingFile(
|
||||||
0,
|
0,
|
||||||
CreateFileTypeNone,
|
CreateFileTypeNone,
|
||||||
NULL,
|
NULL,
|
||||||
SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
|
IO_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
goto EarlyQuit;
|
||||||
ExFreePoolWithTag(Dacl, TAG_DACL);
|
|
||||||
ExFreePoolWithTag(Buffer, TAG_MM);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We opened it! Check we are that "someone" ;-)
|
/* We opened it! Check we are that "someone" ;-)
|
||||||
* First, get the opened file object.
|
* First, get the opened file object.
|
||||||
|
@ -592,33 +588,22 @@ NtCreatePagingFile(
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ZwClose(FileHandle);
|
ZwClose(FileHandle);
|
||||||
ExFreePoolWithTag(Dacl, TAG_DACL);
|
goto EarlyQuit;
|
||||||
ExFreePoolWithTag(Buffer, TAG_MM);
|
|
||||||
return Status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find if it matches a previous page file */
|
/* Find if it matches a previous page file */
|
||||||
PagingFile = NULL;
|
PagingFile = NULL;
|
||||||
|
|
||||||
/* FIXME: should be calling unsafe instead,
|
|
||||||
* we should already be in a guarded region
|
|
||||||
*/
|
|
||||||
KeAcquireGuardedMutex(&MmPageFileCreationLock);
|
KeAcquireGuardedMutex(&MmPageFileCreationLock);
|
||||||
if (MmNumberOfPagingFiles > 0)
|
|
||||||
|
for (i = 0; i < MmNumberOfPagingFiles; ++i)
|
||||||
{
|
{
|
||||||
i = 0;
|
if (MmPagingFile[i]->FileObject->SectionObjectPointer == FileObject->SectionObjectPointer)
|
||||||
|
|
||||||
while (MmPagingFile[i]->FileObject->SectionObjectPointer != FileObject->SectionObjectPointer)
|
|
||||||
{
|
{
|
||||||
++i;
|
/* Same object pointer: this is the matching page file */
|
||||||
if (i >= MmNumberOfPagingFiles)
|
PagingFile = MmPagingFile[i];
|
||||||
{
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is the matching page file */
|
|
||||||
PagingFile = MmPagingFile[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we didn't find the page file, fail */
|
/* If we didn't find the page file, fail */
|
||||||
|
@ -627,9 +612,8 @@ NtCreatePagingFile(
|
||||||
KeReleaseGuardedMutex(&MmPageFileCreationLock);
|
KeReleaseGuardedMutex(&MmPageFileCreationLock);
|
||||||
ObDereferenceObject(FileObject);
|
ObDereferenceObject(FileObject);
|
||||||
ZwClose(FileHandle);
|
ZwClose(FileHandle);
|
||||||
ExFreePoolWithTag(Dacl, TAG_DACL);
|
Status = STATUS_NOT_FOUND;
|
||||||
ExFreePoolWithTag(Buffer, TAG_MM);
|
goto EarlyQuit;
|
||||||
return STATUS_NOT_FOUND;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't allow page file shrinking */
|
/* Don't allow page file shrinking */
|
||||||
|
@ -638,9 +622,8 @@ NtCreatePagingFile(
|
||||||
KeReleaseGuardedMutex(&MmPageFileCreationLock);
|
KeReleaseGuardedMutex(&MmPageFileCreationLock);
|
||||||
ObDereferenceObject(FileObject);
|
ObDereferenceObject(FileObject);
|
||||||
ZwClose(FileHandle);
|
ZwClose(FileHandle);
|
||||||
ExFreePoolWithTag(Dacl, TAG_DACL);
|
Status = STATUS_INVALID_PARAMETER_2;
|
||||||
ExFreePoolWithTag(Buffer, TAG_MM);
|
goto EarlyQuit;
|
||||||
return STATUS_INVALID_PARAMETER_2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((SafeMaximumSize.QuadPart >> PAGE_SHIFT) < PagingFile->MaximumSize)
|
if ((SafeMaximumSize.QuadPart >> PAGE_SHIFT) < PagingFile->MaximumSize)
|
||||||
|
@ -648,9 +631,8 @@ NtCreatePagingFile(
|
||||||
KeReleaseGuardedMutex(&MmPageFileCreationLock);
|
KeReleaseGuardedMutex(&MmPageFileCreationLock);
|
||||||
ObDereferenceObject(FileObject);
|
ObDereferenceObject(FileObject);
|
||||||
ZwClose(FileHandle);
|
ZwClose(FileHandle);
|
||||||
ExFreePoolWithTag(Dacl, TAG_DACL);
|
Status = STATUS_INVALID_PARAMETER_3;
|
||||||
ExFreePoolWithTag(Buffer, TAG_MM);
|
goto EarlyQuit;
|
||||||
return STATUS_INVALID_PARAMETER_3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: implement parameters checking and page file extension */
|
/* FIXME: implement parameters checking and page file extension */
|
||||||
|
@ -659,13 +641,13 @@ NtCreatePagingFile(
|
||||||
KeReleaseGuardedMutex(&MmPageFileCreationLock);
|
KeReleaseGuardedMutex(&MmPageFileCreationLock);
|
||||||
ObDereferenceObject(FileObject);
|
ObDereferenceObject(FileObject);
|
||||||
ZwClose(FileHandle);
|
ZwClose(FileHandle);
|
||||||
ExFreePoolWithTag(Dacl, TAG_DACL);
|
Status = STATUS_NOT_IMPLEMENTED;
|
||||||
ExFreePoolWithTag(Buffer, TAG_MM);
|
goto EarlyQuit;
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
|
EarlyQuit:
|
||||||
DPRINT1("Failed creating page file: %lx\n", Status);
|
DPRINT1("Failed creating page file: %lx\n", Status);
|
||||||
ExFreePoolWithTag(Dacl, TAG_DACL);
|
ExFreePoolWithTag(Dacl, TAG_DACL);
|
||||||
ExFreePoolWithTag(Buffer, TAG_MM);
|
ExFreePoolWithTag(Buffer, TAG_MM);
|
||||||
|
@ -727,8 +709,10 @@ NtCreatePagingFile(
|
||||||
|
|
||||||
/* Only allow page file on a few device types */
|
/* Only allow page file on a few device types */
|
||||||
DeviceType = IoGetRelatedDeviceObject(FileObject)->DeviceType;
|
DeviceType = IoGetRelatedDeviceObject(FileObject)->DeviceType;
|
||||||
if (DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM && DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM &&
|
if (DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM &&
|
||||||
DeviceType != FILE_DEVICE_DFS_VOLUME && DeviceType != FILE_DEVICE_DFS_FILE_SYSTEM)
|
DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM &&
|
||||||
|
DeviceType != FILE_DEVICE_DFS_VOLUME &&
|
||||||
|
DeviceType != FILE_DEVICE_DFS_FILE_SYSTEM)
|
||||||
{
|
{
|
||||||
ObDereferenceObject(FileObject);
|
ObDereferenceObject(FileObject);
|
||||||
ZwClose(FileHandle);
|
ZwClose(FileHandle);
|
||||||
|
@ -738,7 +722,8 @@ NtCreatePagingFile(
|
||||||
|
|
||||||
/* Deny page file creation on a floppy disk */
|
/* Deny page file creation on a floppy disk */
|
||||||
FsDeviceInfo.Characteristics = 0;
|
FsDeviceInfo.Characteristics = 0;
|
||||||
IoQueryVolumeInformation(FileObject, FileFsDeviceInformation, sizeof(FsDeviceInfo), &FsDeviceInfo, &Count);
|
IoQueryVolumeInformation(FileObject, FileFsDeviceInformation,
|
||||||
|
sizeof(FsDeviceInfo), &FsDeviceInfo, &Count);
|
||||||
if (BooleanFlagOn(FsDeviceInfo.Characteristics, FILE_FLOPPY_DISKETTE))
|
if (BooleanFlagOn(FsDeviceInfo.Characteristics, FILE_FLOPPY_DISKETTE))
|
||||||
{
|
{
|
||||||
ObDereferenceObject(FileObject);
|
ObDereferenceObject(FileObject);
|
||||||
|
@ -747,7 +732,27 @@ NtCreatePagingFile(
|
||||||
return STATUS_FLOPPY_VOLUME;
|
return STATUS_FLOPPY_VOLUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
PagingFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(*PagingFile), TAG_MM);
|
/*
|
||||||
|
* Missing validation steps TODO:
|
||||||
|
* (see https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/mm/modwrite/create.htm )
|
||||||
|
*
|
||||||
|
* - Verify that no file system driver or any filter driver has done file
|
||||||
|
* I/O while opening the file.
|
||||||
|
* Verify that nothing of the paging file is yet in memory. Specifically,
|
||||||
|
* the file object must either have no SectionObjectPointer or the latter
|
||||||
|
* must have neither a DataSectionObject nor an ImageSectionObject.
|
||||||
|
* Otherwise, we should fail, returning STATUS_INCOMPATIBLE_FILE_MAP.
|
||||||
|
*
|
||||||
|
* - Inform all the applicable drivers to prepare for the possibility of
|
||||||
|
* paging I/O. Much of the point to paging I/O is to resolve page faults.
|
||||||
|
* Especially important is that drivers that handle paging I/O do not
|
||||||
|
* cause more page faults. All the code and data that each driver might
|
||||||
|
* ever use for access to the paging file must be locked into physical
|
||||||
|
* memory. This can’t be left until paging I/O actually occurs.
|
||||||
|
* It must be done in advance.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PagingFile = ExAllocatePoolZero(NonPagedPool, sizeof(*PagingFile), TAG_MM);
|
||||||
if (PagingFile == NULL)
|
if (PagingFile == NULL)
|
||||||
{
|
{
|
||||||
ObDereferenceObject(FileObject);
|
ObDereferenceObject(FileObject);
|
||||||
|
@ -756,17 +761,15 @@ NtCreatePagingFile(
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
RtlZeroMemory(PagingFile, sizeof(*PagingFile));
|
|
||||||
|
|
||||||
PagingFile->FileHandle = FileHandle;
|
PagingFile->FileHandle = FileHandle;
|
||||||
PagingFile->FileObject = FileObject;
|
PagingFile->FileObject = FileObject;
|
||||||
PagingFile->MaximumSize = (SafeMaximumSize.QuadPart >> PAGE_SHIFT);
|
|
||||||
PagingFile->Size = (SafeMinimumSize.QuadPart >> PAGE_SHIFT);
|
PagingFile->Size = (SafeMinimumSize.QuadPart >> PAGE_SHIFT);
|
||||||
PagingFile->MinimumSize = (SafeMinimumSize.QuadPart >> PAGE_SHIFT);
|
PagingFile->MinimumSize = PagingFile->Size;
|
||||||
|
PagingFile->MaximumSize = (SafeMaximumSize.QuadPart >> PAGE_SHIFT);
|
||||||
/* First page is never used: it's the header
|
/* First page is never used: it's the header
|
||||||
* TODO: write it
|
* TODO: write it
|
||||||
*/
|
*/
|
||||||
PagingFile->FreeSpace = (ULONG)(SafeMinimumSize.QuadPart / PAGE_SIZE) - 1;
|
PagingFile->FreeSpace = PagingFile->Size - 1;
|
||||||
PagingFile->CurrentUsage = 0;
|
PagingFile->CurrentUsage = 0;
|
||||||
PagingFile->PageFileName = PageFileName;
|
PagingFile->PageFileName = PageFileName;
|
||||||
ASSERT(PagingFile->Size == PagingFile->FreeSpace + PagingFile->CurrentUsage + 1);
|
ASSERT(PagingFile->Size == PagingFile->FreeSpace + PagingFile->CurrentUsage + 1);
|
||||||
|
@ -789,10 +792,9 @@ NtCreatePagingFile(
|
||||||
(ULONG)(PagingFile->MaximumSize));
|
(ULONG)(PagingFile->MaximumSize));
|
||||||
RtlClearAllBits(PagingFile->Bitmap);
|
RtlClearAllBits(PagingFile->Bitmap);
|
||||||
|
|
||||||
/* FIXME: should be calling unsafe instead,
|
/* Insert the new paging file information into the list */
|
||||||
* we should already be in a guarded region
|
|
||||||
*/
|
|
||||||
KeAcquireGuardedMutex(&MmPageFileCreationLock);
|
KeAcquireGuardedMutex(&MmPageFileCreationLock);
|
||||||
|
/* Ensure the corresponding slot is empty yet */
|
||||||
ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL);
|
ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL);
|
||||||
MmPagingFile[MmNumberOfPagingFiles] = PagingFile;
|
MmPagingFile[MmNumberOfPagingFiles] = PagingFile;
|
||||||
MmNumberOfPagingFiles++;
|
MmNumberOfPagingFiles++;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue