Geoff Chappell - Software Analyst
SKETCH OF HOW RESEARCH MIGHT CONTINUE AND RESULTS BE PRESENTED
This function performs a variety of operations on one or two memory partitions.
NTSTATUS NtManagePartition ( HANDLE TargetHandle, HANDLE SourceHandle, PARTITION_INFORMATION_CLASS PartitionInformationClass, PVOID PartitionInformation, ULONG PartitionInformationLength);
but slightly different before Version 1709:
NTSTATUS NtManagePartition ( HANDLE TargetHandle, HANDLE SourceHandle, MEMORY_PARTITION_INFORMATION_CLASS PartitionInformationClass, PVOID PartitionInformation, ULONG PartitionInformationLength);
The SourceHandle and TargetHandle arguments specify which partitions to operate on, as source and target. All operations require a target. Some, presently just one, require a source. For others, supplying a source is an error.
The operation is selected by the PartitionInformationClass argument.
The PartitionInformation and PartitionInformationLength arguments are respectively the address and size (in bytes) of a buffer that either provides information to the function or receives it as output. What the function interprets of the buffer or puts into it depends on the information class.
The function returns STATUS_SUCCESS if successful, else a negative error code.
The NtManagePartition function and its alias ZwManagePartition are exported by name from NTDLL in version 10.0 and higher. In kernel mode, where ZwManagePartition is a stub and NtManagePartition is the implementation, neither is exported until the 1607 release of Windows 10 exports the stub.
For all practical effect before Version 1703, the functions are available only in 64-bit Windows: the functions are exported in 32-bit Windows but the 32-bit kernel’s implementation in the early versions of Windows 10 trivially returns STATUS_NOT_SUPPORTED.
Neither NtManagePartition nor its alias is documented. As ZwManagePartition, it is declared in a header named ZWAPI.H which Microsoft published, possibly by mistake, in the Windows Driver Kit (WDK) for the original and 1511 editions of Windows 10.
The following implementation notes are from inspection of the kernel from the original release of Windows 10.
If executing for a user-mode request, the function has some general defensiveness about addresses passed as arguments. Failure at any of these defences is failure for the function, typically showing as a return of STATUS_DATATYPE_MISALIGNMENT or STATUS_ACCESS_VIOLATION.
If an information buffer is given, meaning here that PartitionInformationLength is non-zero, then its address PartitionInformation must have 8-byte alignment and the whole buffer must be in user-mode address space.
The PartitionInformationClass is the primary determinant of what the function is to do. A table below lists the valid information classes. For all others, the function can do nothing buf fail. The error code is STATUS_INVALID_INFO_CLASS.
The information classes SystemMemoryPartitionMoveMemory (1) and SystemMemoryPartitionInitialAddMemory (4) require SeLockMemoryPrivilege. If the caller does not have this privilege, the function fails, returning STATUS_PRIVILEGE_NOT_HELD.
Each information class has a corresponding fixed-size structure for its input or output, shown in the table below. If the PartitionInformationLength is not exactly the size of this corresponding structure, the function fails, returning STATUS_INFO_LENGTH_MISMATCH.
Information Class | Structure | Input or Output |
---|---|---|
SystemMemoryPartitionInformation (0) | MEMORY_PARTITION_CONFIGURATION_INFORMATION | output |
SystemMemoryPartitionMoveMemory (1) | MEMORY_PARTITION_TRANSFER_INFORMATION | simple input |
SystemMemoryPartitionAddPagefile (2) | MEMORY_PARTITION_PAGEFILE_INFORMATION | complex input |
SystemMemoryPartitionCombineMemory (3) | MEMORY_PARTITION_PAGE_COMBINE_INFORMATION | simple input; output |
SystemMemoryPartitionInitialAddMemory (4) | MEMORY_PARTITION_INITIAL_ADD_INFORMATION | simple input; output |
For those information classes that expect input that contains no pointers, designated simple input above, the function captures the input immediately. If executing for a user-mode request, occurrence of an exception while capturing the input is fatal to the function, which returns the exception code as its own result.
All information classes require a target partition to operate on. The given TargetHandle must resolve to a partition object. For most information classes, the handle must allow MEMORY_PARTITION_MODIFY_ACCESS (0x0002). For SystemMemoryPartitionInformation, the required permission is MEMORY_PARTITION_QUERY_ACCESS (0x0001). Failure to reference the target partition is failure for the function.
For most information classes, the selected operation works on only the target partition. Supplying a SourceHandle is an error, specifically STATUS_INVALID_PARAMETER_2.
A source partition is required for SystemMemoryPartitionMoveMemory. The SourceHandle must resolve to a partition object and allow MEMORY_PARTITION_MODIFY_ACCESS. Failure to reference the source partition is failure for the function.
All remaining behaviour is highly particular to the information class.
The whole point to SystemMemoryPartitionInformation is to fill the information buffer with a MEMORY_PARTITION_CONFIGURATION_INFORMATION, thus giving the caller some description of the target partition.
If executing for a user-mode request, occurrence of an exception while writing to the buffer is fatal for the function, which returns the exception code as its own result. If executing for a kernel-mode request (not that this seems possible at present), an unhandled exception during this write is left unhandled, which will typically be fatal to Windows.
The operation selected by SystemMemoryPartitionMoveMemory is the moving of pages from a Non-Uniform Memory Access (NUMA) node at the source partition to the target partition. The information buffer supplies a MEMORY_PARTITION_TRANSFER_INFORMATION structure which specifies the number of pages and the node.
Success is trivial if the NumberOfPages is zero. If the NumaNode is invalid or if the Flags are not zero, the function fails, returning STATUS_INVALID_PARAMETER. Note, however, that NumaNode can be 0xFFFFFFFF to mean the node for the current thread’s ideal processor.
When given SystemMemoryPartitionAddPagefile as the information class, the function is to create a paging file for the target partition. It becomes essentially the NtCreatePagingFile function but without being tied to the system partition. What would be individual arguments for NtCreatePagingFile are instead supplied to NtManagePartition as a MEMORY_PARTITION_PAGEFILE_INFORMATION structure in the information buffer.
For SystemMemoryPartitionCombineMemory the function is to combine identical pages on the target partition. The information buffer supplies a MEMORY_PARTITION_PAGE_COMBINE_INFORMATION structure for both input and output.
As input, the structure provides the function with a StopHandle and Flags. Among the flags, only 0x01 is presently valid. If any other is set or if the 0x01 flag is set but the target partition is not the system partition, the function fails, returning STATUS_INVALID_PARAMETER.
As output, the structure’s TotalNumberOfPages receives the number of pages that have been combined as identical.
The information class SystemMemoryPartitionInitialAddMemory directs the function to assign one block of physically contiguous pages to the target partition. The information buffer supplies a MEMORY_PARTITION_INITIAL_ADD_INFORMATION structure for both input and output.
As input, the structure provides the function with the page number of the block’s first page and with the number of pages. If this NumberOfPages is zero or if the Flags are not zero, the function fails, returning STATUS_INVALID_PARAMETER.