https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a4274ad54837287bca58c…
commit a4274ad54837287bca58ca698b5a0ce237d0fd9d
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Thu Nov 3 00:12:09 2022 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Wed Nov 16 21:54:31 2022 +0100
[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/c…
https://techcommunity.microsoft.com/t5/ask-the-performance-team/what-is-the…
+ 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.
---
base/system/smss/pagefile.c | 106 +++++++++++++++------
ntoskrnl/mm/pagefile.c | 220 ++++++++++++++++++++++----------------------
2 files changed, 191 insertions(+), 135 deletions(-)
diff --git a/base/system/smss/pagefile.c b/base/system/smss/pagefile.c
index 2eed8a7236d..c8115955c4f 100644
--- a/base/system/smss/pagefile.c
+++ b/base/system/smss/pagefile.c
@@ -20,8 +20,63 @@
//
#define STANDARD_PAGING_FILE_NAME L"\\??\\?:\\pagefile.sys"
#define STANDARD_DRIVE_LETTER_OFFSET 4
-#define MEGABYTE 0x100000UL
-#define MAXIMUM_PAGEFILE_SIZE (4095 * MEGABYTE)
+#define MAX_PAGING_FILES 16 // See also ntoskrnl/include/internal/mm.h
+#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 */
#define MINIMUM_TO_KEEP_FREE (256 * MEGABYTE)
#define FUZZ_FACTOR (16 * MEGABYTE)
@@ -93,7 +148,7 @@ SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken)
UNICODE_STRING PageFileName, Arguments, SecondArgument;
/* 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",
SmpNumberOfPagingFiles);
@@ -110,7 +165,7 @@ SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken)
if (!NT_SUCCESS(Status))
{
/* Fail */
- DPRINT1("SMSS:PFILE: SmpParseCommandLine( %wZ ) failed - Status ==
%lx\n",
+ DPRINT1("SMSS:PFILE: SmpParseCommandLine(%wZ) failed - Status ==
%lx\n",
PageFileToken, Status);
return Status;
}
@@ -198,7 +253,8 @@ SmpCreatePagingFileDescriptor(IN PUNICODE_STRING PageFileToken)
Descriptor->Name = PageFileName;
Descriptor->MinSize.QuadPart = MinSize * 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] =
RtlUpcaseUnicodeChar(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)
{
NTSTATUS Status;
- LONGLONG MinimumSize, MaximumSize, Ram;
+ ULONGLONG MinimumSize, MaximumSize, Ram;
SYSTEM_BASIC_INFORMATION BasicInfo;
/* Query the page size of the system, and the amount of RAM */
@@ -693,8 +749,15 @@ NTAPI
SmpValidatePagingFileSizes(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)
{
NTSTATUS Status = STATUS_SUCCESS;
- ULONGLONG MinSize, MaxSize;
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 */
MinSize = Descriptor->MinSize.QuadPart;
@@ -704,28 +767,19 @@ SmpValidatePagingFileSizes(IN PSMP_PAGEFILE_DESCRIPTOR Descriptor)
&Descriptor->Name, MinSize, MaxSize);
/* 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... */
- if (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED])
+ /* Validate the minimum and maximum and trim them if they are too large */
+ if (MinSize > MaxPageFileSize)
{
- /* But we don't support that yet */
- DPRINT1("ReactOS does not support PAE yet... assuming sizes OK\n");
+ WasTooBig = TRUE;
+ MinSize = MaxPageFileSize;
}
- else
+ if (MaxSize > MaxPageFileSize)
{
- /* Validate the minimum and maximum and trim them if they are too large */
- if (MinSize > MAXIMUM_PAGEFILE_SIZE)
- {
- WasTooBig = TRUE;
- MinSize = MAXIMUM_PAGEFILE_SIZE;
- }
-
- if (MaxSize > MAXIMUM_PAGEFILE_SIZE)
- {
- WasTooBig = TRUE;
- MaxSize = MAXIMUM_PAGEFILE_SIZE;
- }
+ WasTooBig = TRUE;
+ MaxSize = MaxPageFileSize;
}
/* 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 */
ASSERT(SmpNumberOfPagingFiles >= 1);
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 */
FuzzFactor.QuadPart = FUZZ_FACTOR;
diff --git a/ntoskrnl/mm/pagefile.c b/ntoskrnl/mm/pagefile.c
index 1387a38527b..a57c4de0304 100644
--- a/ntoskrnl/mm/pagefile.c
+++ b/ntoskrnl/mm/pagefile.c
@@ -1,29 +1,9 @@
/*
- * ReactOS kernel
- * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * 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(a)mcmail.com)
- * Pierre Schweitzer
- * UPDATE HISTORY:
- * Created 22/05/98
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Paging file functions
+ * COPYRIGHT: Copyright 1998-2003 David Welch <welch(a)mcmail.com>
+ * Copyright 2010-2018 Pierre Schweitzer <pierre(a)reactos.org>
*/
/* INCLUDES *****************************************************************/
@@ -34,7 +14,44 @@
/* 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 */
PMMPAGING_FILE MmPagingFile[MAX_PAGING_FILES];
@@ -409,33 +426,32 @@ NtCreatePagingFile(
}
/*
- * Pagefiles can't be larger than 4GB and of course
- * the minimum should be smaller than the maximum.
+ * Pagefiles cannot be larger than the platform-specific memory addressable
+ * limits, and of course the minimum should be smaller than the maximum.
*/
- // TODO: Actually validate the lower bound of these sizes!
- if (0 != SafeMinimumSize.u.HighPart)
+ if (SafeMinimumSize.QuadPart < MINIMUM_PAGEFILE_SIZE ||
+ SafeMinimumSize.QuadPart > MAXIMUM_PAGEFILE_SIZE)
{
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;
}
- if (SafeMaximumSize.u.LowPart < SafeMinimumSize.u.LowPart)
- {
- return STATUS_INVALID_PARAMETER_MIX;
- }
/* Validate the name length */
if ((PageFileName.Length == 0) ||
- (PageFileName.Length > 128 * sizeof(WCHAR)))
+ (PageFileName.Length > MAXIMUM_FILENAME_LENGTH))
{
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;
- /* Allocate a buffer to keep the name copy */
Buffer = ExAllocatePoolWithTag(PagedPool, PageFileName.Length, TAG_MM);
if (Buffer == NULL)
{
@@ -488,42 +504,26 @@ NtCreatePagingFile(
/* Initialize the DACL */
Status = RtlCreateAcl(Dacl, Count, ACL_REVISION);
if (!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(Dacl, TAG_DACL);
- ExFreePoolWithTag(Buffer, TAG_MM);
- return Status;
- }
+ goto EarlyQuit;
/* Grant full access to admins */
Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS,
SeAliasAdminsSid);
if (!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(Dacl, TAG_DACL);
- ExFreePoolWithTag(Buffer, TAG_MM);
- return Status;
- }
+ goto EarlyQuit;
/* Grant full access to SYSTEM */
Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS,
SeLocalSystemSid);
if (!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(Dacl, TAG_DACL);
- ExFreePoolWithTag(Buffer, TAG_MM);
- return Status;
- }
+ goto EarlyQuit;
/* Attach the DACL to the security descriptor */
Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE);
if (!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(Dacl, TAG_DACL);
- ExFreePoolWithTag(Buffer, TAG_MM);
- return Status;
- }
+ goto EarlyQuit;
InitializeObjectAttributes(&ObjectAttributes,
&PageFileName,
- OBJ_KERNEL_HANDLE,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
&SecurityDescriptor);
@@ -549,10 +549,10 @@ NtCreatePagingFile(
0,
CreateFileTypeNone,
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
* 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.
*/
if (!NT_SUCCESS(Status))
@@ -572,13 +572,9 @@ NtCreatePagingFile(
0,
CreateFileTypeNone,
NULL,
- SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
+ IO_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
if (!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(Dacl, TAG_DACL);
- ExFreePoolWithTag(Buffer, TAG_MM);
- return Status;
- }
+ goto EarlyQuit;
/* We opened it! Check we are that "someone" ;-)
* First, get the opened file object.
@@ -592,33 +588,22 @@ NtCreatePagingFile(
if (!NT_SUCCESS(Status))
{
ZwClose(FileHandle);
- ExFreePoolWithTag(Dacl, TAG_DACL);
- ExFreePoolWithTag(Buffer, TAG_MM);
- return Status;
+ goto EarlyQuit;
}
/* Find if it matches a previous page file */
PagingFile = NULL;
- /* FIXME: should be calling unsafe instead,
- * we should already be in a guarded region
- */
KeAcquireGuardedMutex(&MmPageFileCreationLock);
- if (MmNumberOfPagingFiles > 0)
- {
- i = 0;
- while (MmPagingFile[i]->FileObject->SectionObjectPointer !=
FileObject->SectionObjectPointer)
+ for (i = 0; i < MmNumberOfPagingFiles; ++i)
+ {
+ if (MmPagingFile[i]->FileObject->SectionObjectPointer ==
FileObject->SectionObjectPointer)
{
- ++i;
- if (i >= MmNumberOfPagingFiles)
- {
- break;
- }
+ /* Same object pointer: this is the matching page file */
+ PagingFile = MmPagingFile[i];
+ break;
}
-
- /* This is the matching page file */
- PagingFile = MmPagingFile[i];
}
/* If we didn't find the page file, fail */
@@ -627,9 +612,8 @@ NtCreatePagingFile(
KeReleaseGuardedMutex(&MmPageFileCreationLock);
ObDereferenceObject(FileObject);
ZwClose(FileHandle);
- ExFreePoolWithTag(Dacl, TAG_DACL);
- ExFreePoolWithTag(Buffer, TAG_MM);
- return STATUS_NOT_FOUND;
+ Status = STATUS_NOT_FOUND;
+ goto EarlyQuit;
}
/* Don't allow page file shrinking */
@@ -638,9 +622,8 @@ NtCreatePagingFile(
KeReleaseGuardedMutex(&MmPageFileCreationLock);
ObDereferenceObject(FileObject);
ZwClose(FileHandle);
- ExFreePoolWithTag(Dacl, TAG_DACL);
- ExFreePoolWithTag(Buffer, TAG_MM);
- return STATUS_INVALID_PARAMETER_2;
+ Status = STATUS_INVALID_PARAMETER_2;
+ goto EarlyQuit;
}
if ((SafeMaximumSize.QuadPart >> PAGE_SHIFT) <
PagingFile->MaximumSize)
@@ -648,9 +631,8 @@ NtCreatePagingFile(
KeReleaseGuardedMutex(&MmPageFileCreationLock);
ObDereferenceObject(FileObject);
ZwClose(FileHandle);
- ExFreePoolWithTag(Dacl, TAG_DACL);
- ExFreePoolWithTag(Buffer, TAG_MM);
- return STATUS_INVALID_PARAMETER_3;
+ Status = STATUS_INVALID_PARAMETER_3;
+ goto EarlyQuit;
}
/* FIXME: implement parameters checking and page file extension */
@@ -659,13 +641,13 @@ NtCreatePagingFile(
KeReleaseGuardedMutex(&MmPageFileCreationLock);
ObDereferenceObject(FileObject);
ZwClose(FileHandle);
- ExFreePoolWithTag(Dacl, TAG_DACL);
- ExFreePoolWithTag(Buffer, TAG_MM);
- return STATUS_NOT_IMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto EarlyQuit;
}
if (!NT_SUCCESS(Status))
{
+EarlyQuit:
DPRINT1("Failed creating page file: %lx\n", Status);
ExFreePoolWithTag(Dacl, TAG_DACL);
ExFreePoolWithTag(Buffer, TAG_MM);
@@ -727,8 +709,10 @@ NtCreatePagingFile(
/* Only allow page file on a few device types */
DeviceType = IoGetRelatedDeviceObject(FileObject)->DeviceType;
- if (DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM && DeviceType !=
FILE_DEVICE_NETWORK_FILE_SYSTEM &&
- DeviceType != FILE_DEVICE_DFS_VOLUME && DeviceType !=
FILE_DEVICE_DFS_FILE_SYSTEM)
+ if (DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM &&
+ DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM &&
+ DeviceType != FILE_DEVICE_DFS_VOLUME &&
+ DeviceType != FILE_DEVICE_DFS_FILE_SYSTEM)
{
ObDereferenceObject(FileObject);
ZwClose(FileHandle);
@@ -738,7 +722,8 @@ NtCreatePagingFile(
/* Deny page file creation on a floppy disk */
FsDeviceInfo.Characteristics = 0;
- IoQueryVolumeInformation(FileObject, FileFsDeviceInformation, sizeof(FsDeviceInfo),
&FsDeviceInfo, &Count);
+ IoQueryVolumeInformation(FileObject, FileFsDeviceInformation,
+ sizeof(FsDeviceInfo), &FsDeviceInfo, &Count);
if (BooleanFlagOn(FsDeviceInfo.Characteristics, FILE_FLOPPY_DISKETTE))
{
ObDereferenceObject(FileObject);
@@ -747,7 +732,27 @@ NtCreatePagingFile(
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/c… )
+ *
+ * - 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)
{
ObDereferenceObject(FileObject);
@@ -756,17 +761,15 @@ NtCreatePagingFile(
return STATUS_INSUFFICIENT_RESOURCES;
}
- RtlZeroMemory(PagingFile, sizeof(*PagingFile));
-
PagingFile->FileHandle = FileHandle;
PagingFile->FileObject = FileObject;
- PagingFile->MaximumSize = (SafeMaximumSize.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
* TODO: write it
*/
- PagingFile->FreeSpace = (ULONG)(SafeMinimumSize.QuadPart / PAGE_SIZE) - 1;
+ PagingFile->FreeSpace = PagingFile->Size - 1;
PagingFile->CurrentUsage = 0;
PagingFile->PageFileName = PageFileName;
ASSERT(PagingFile->Size == PagingFile->FreeSpace + PagingFile->CurrentUsage
+ 1);
@@ -789,10 +792,9 @@ NtCreatePagingFile(
(ULONG)(PagingFile->MaximumSize));
RtlClearAllBits(PagingFile->Bitmap);
- /* FIXME: should be calling unsafe instead,
- * we should already be in a guarded region
- */
+ /* Insert the new paging file information into the list */
KeAcquireGuardedMutex(&MmPageFileCreationLock);
+ /* Ensure the corresponding slot is empty yet */
ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL);
MmPagingFile[MmNumberOfPagingFiles] = PagingFile;
MmNumberOfPagingFiles++;