Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

874 lines
27 KiB

/*++
Copyright (c) Microsoft Corporation
Module Name:
rtlmmapio.c
Abstract:
Functions to aid in
rigorously safe
reasonably efficient
reasonably easy to code
memory mapped i/o that captures with "tight" __try/__excepts to
catch status_in_page_errors, and captures only as much as is needed,
like only individual struct fields, to keep stack usage low.
Author:
Jay Krell (JayKrell) January 2002
Revision History:
Environment:
Pretty much anywhere memory mapped i/o is available.
Initial client is win32k.sys font loading "rewrite".
--*/
#pragma warning(disable:4214) /* bit field types other than int */
#pragma warning(disable:4201) /* nameless struct/union */
#pragma warning(disable:4115) /* named type definition in parentheses */
#pragma warning(disable:4127) /* condition expression is constant */
#include "nt.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "ntrtlmmapio.h"
#include "ntrtloverflow.h"
#if defined(__cplusplus)
extern "C" {
#endif
#define NOT_YET_USED 1
#define RTLP_STRINGIZE_(x) #x
#define RTLP_STRINGIZE(x) RTLP_STRINGIZE_(x)
#define RTLP_LINE_AS_STRING() RTLP_STRINGIZE(__LINE__)
#define RTLP_PREPEND_LINE_SPACE_TO_STRING(x) RTLP_LINE_AS_STRING() " " x
#define RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE (0x00000001)
#define RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_TO_RANGE (0x00000002)
NTSTATUS
RtlpAddWithOverflowCheckUlongPtr(
ULONG_PTR *pc,
ULONG_PTR a,
ULONG_PTR b
)
{
return RtlAddWithCarryOutUlongPtr(pc, a, b) ? STATUS_INTEGER_OVERFLOW : STATUS_SUCCESS;
}
NTSTATUS
RtlpAddWithOverflowCheckSizet(
SIZE_T *pc,
SIZE_T a,
SIZE_T b
)
{
return RtlAddWithCarryOutSizet(pc, a, b) ? STATUS_INTEGER_OVERFLOW : STATUS_SUCCESS;
}
LONG
RtlpCopyMappedMemoryEx_ExceptionFilter(
ULONG Flags,
PVOID ToAddress,
PCVOID FromAddress,
SIZE_T Size,
OUT PSIZE_T BytesCopiedOut OPTIONAL,
OUT PEXCEPTION_RECORD ExceptionRecordOut OPTIONAL,
IN PEXCEPTION_POINTERS ExceptionPointers,
OUT PNTSTATUS StatusOut OPTIONAL
)
/*++
Routine Description:
This routine serves as an exception filter and has the special job of
extracting the "real" I/O error when Mm raises STATUS_IN_PAGE_ERROR
beneath us. This is based on CcCopyReadExceptionFilter / MiGetExceptionInfo / RtlUnhandledExceptionFilter
Arguments:
ExceptionPointers - A pointer to the context and
the exception record that contains the real Io Status.
ExceptionCode - A pointer to an NTSTATUS that is to receive the real
status.
Return Value:
EXCEPTION_EXECUTE_HANDLER for inpage errors in the "expected" range
otherwise EXCEPTION_CONTINUE_SEARCH
--*/
{
const PEXCEPTION_RECORD ExceptionRecord = ExceptionPointers->ExceptionRecord;
NTSTATUS ExceptionCode = ExceptionRecord->ExceptionCode;
LONG Disposition = EXCEPTION_CONTINUE_SEARCH;
SIZE_T BytesCopied = 0;
if (ExceptionCode == STATUS_IN_PAGE_ERROR) {
const ULONG NumberParameters = ExceptionRecord->NumberParameters;
if (RTL_IN_PAGE_ERROR_EXCEPTION_INFO_FAULTING_VA_INDEX < NumberParameters) {
const ULONG_PTR ExceptionAddress = ExceptionRecord->ExceptionInformation[RTL_IN_PAGE_ERROR_EXCEPTION_INFO_FAULTING_VA_INDEX];
if ((Flags & RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE) != 0
&& ExceptionAddress >= ((ULONG_PTR)FromAddress)
&& ExceptionAddress < (((ULONG_PTR)FromAddress) + Size)) {
Disposition = EXCEPTION_EXECUTE_HANDLER;
BytesCopied = (SIZE_T)(ExceptionAddress - (ULONG_PTR)FromAddress);
} else if ((Flags & RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_TO_RANGE) != 0
&& ExceptionAddress >= ((ULONG_PTR)ToAddress)
&& ExceptionAddress < (((ULONG_PTR)ToAddress) + Size)) {
Disposition = EXCEPTION_EXECUTE_HANDLER;
BytesCopied = (SIZE_T)(ExceptionAddress - (ULONG_PTR)ToAddress);
}
} else {
//
// We don't have the information to do the range check. What to do?
// We return continue_search.
//
// Comments in code indicate this can happen, that the iomgr reraises
// inpage errors without the additional parameters.
//
}
if (RTL_IN_PAGE_ERROR_EXCEPTION_INFO_UNDERLYING_STATUS_INDEX < NumberParameters) {
ExceptionCode = (NTSTATUS) ExceptionRecord->ExceptionInformation[RTL_IN_PAGE_ERROR_EXCEPTION_INFO_UNDERLYING_STATUS_INDEX];
}
}
if (ARGUMENT_PRESENT(ExceptionRecordOut)) {
*ExceptionRecordOut = *ExceptionRecord;
}
if (ARGUMENT_PRESENT(StatusOut)) {
*StatusOut = ExceptionCode;
}
if (ARGUMENT_PRESENT(BytesCopiedOut)) {
*BytesCopiedOut = BytesCopied;
}
return Disposition;
}
NTSTATUS
NTAPI
RtlpCopyMappedMemoryEx(
ULONG Flags,
PVOID ToAddress,
PCVOID FromAddress,
SIZE_T Size,
PSIZE_T BytesCopied OPTIONAL,
PEXCEPTION_RECORD ExceptionRecordOut OPTIONAL
)
{
NTSTATUS Status;
if (ARGUMENT_PRESENT(BytesCopied)) {
*BytesCopied = 0;
}
__try {
RtlCopyMemory(ToAddress, FromAddress, Size);
if (ARGUMENT_PRESENT(BytesCopied)) {
*BytesCopied = Size;
}
Status = STATUS_SUCCESS;
} __except(
RtlpCopyMappedMemoryEx_ExceptionFilter(
Flags,
ToAddress,
FromAddress,
Size,
BytesCopied,
ExceptionRecordOut,
GetExceptionInformation(),
&Status)) {
}
return Status;
}
NTSTATUS
NTAPI
RtlCopyMappedMemory(
PVOID ToAddress,
PCVOID FromAddress,
SIZE_T Size
)
{
return
RtlpCopyMappedMemoryEx(
RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE
| RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_TO_RANGE,
ToAddress,
FromAddress,
Size,
NULL, // BytesCopied OPTIONAL,
NULL // ExceptionRecordOut OPTIONAL
);
}
#if NOT_YET_USED
NTSTATUS
NTAPI
RtlCopyMemoryFromMappedView(
PCVOID ViewBase,
SIZE_T ViewSize,
PVOID ToAddress,
PCVOID FromAddress,
SIZE_T Size,
PSIZE_T BytesCopied OPTIONAL,
PEXCEPTION_RECORD ExceptionRecordOut OPTIONAL
)
/*++
Routine Description:
Arguments:
ViewBase - the base of a memory mapped view
ViewSize - the size of the memory mapped view mapped at ViewBase
ToAddress - where to copy memory to, like the first parameter to RtlCopyMemory
This assumed to point to memory for which inpage errors are "not possible"
like backed by the pagefile or nonpaged pool
If copying to mapped files or from and to mapped files, see RtlpCopyMappedMemoryEx.
FromAddress - where to copy memory from, like the second parameter to RtlCopyMemory
this must be within [ViewBase, ViewBase + ViewSize)
Size - the number of bytes to copy, like the third parameter to RtlCopyMemory
BytesCopied - optional out parameter that tells the number of bytes
successfully copied; in this case of partial success, this
is computed based in information in GetExceptionInformation
ExceptionRecordOut - optional out parameter so the caller can pick apart
the full details an exception, like to get the error
underlying a status_inpage_error in the exception handler
Return Value:
STATUS_SUCCESS - everything is groovy
STATUS_ACCESS_VIOLATION - the memory is not within the mapped view
STATUS_IN_PAGE_ERROR - the memory could not be paged in
the details as to why can be found via ExceptionRecordOut
see RTL_IN_PAGE_ERROR_EXCEPTION_INFO_UNDERLYING_STATUS_INDEX
STATUS_INVALID_PARAMETER
--*/
{
NTSTATUS Status;
if (ARGUMENT_PRESENT(BytesCopied)) {
*BytesCopied = 0;
}
Status = RtlMappedViewRangeCheck(ViewBase, ViewSize, FromAddress, Size);
if (!NT_SUCCESS(Status)) {
//
// Note that ExceptionRecordOut is not filled in in this case.
//
goto Exit;
}
Status =
RtlpCopyMappedMemoryEx(
RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE,
ToAddress,
FromAddress,
Size,
BytesCopied,
ExceptionRecordOut
);
if (!NT_SUCCESS(Status)) {
goto Exit;
}
Status = STATUS_SUCCESS;
Exit:
return Status;
}
#endif
#if NOT_YET_USED
NTSTATUS
NTAPI
RtlMemoryMappedIoCapturePartialStruct(
PCVOID ViewBase,
SIZE_T ViewSize,
PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_DESCRIPTOR Descriptor,
PCVOID VoidStructInViewBase,
PVOID VoidSafeBuffer,
SIZE_T SafeBufferSize
)
{
NTSTATUS Status;
PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR Member;
PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR MemberEnd;
PCBYTE StructInViewBase;
PBYTE SafeBuffer;
ULONG_PTR SafeBufferEnd;
SIZE_T EntireStructFileSize;
StructInViewBase = (PCBYTE)VoidStructInViewBase;
SafeBuffer = (PBYTE)VoidSafeBuffer;
Status = STATUS_INTERNAL_ERROR;
Member = (PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR)~(ULONG_PTR)0;
MemberEnd = (PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR)~(ULONG_PTR)0;
if (!RTL_SOFT_VERIFY(
ViewBase != NULL
&& ViewSize != 0
&& Descriptor != NULL
&& StructInViewBase != NULL
&& SafeBuffer != NULL
&& SafeBufferSize != 0
&& SafeBufferSize == Descriptor->PartialStructMemorySize
)) {
Status = STATUS_INVALID_PARAMETER;
goto Exit;
}
if (!RTL_SOFT_VERIFY(NT_SUCCESS(Status =
RtlpAddWithOverflowCheckUlongPtr(
&SafeBufferEnd,
(ULONG_PTR)SafeBuffer,
SafeBufferSize
)))) {
goto Exit;
}
if (!RTL_SOFT_VERIFY(NT_SUCCESS(Status =
RtlMappedViewRangeCheck(
ViewBase,
ViewSize,
StructInViewBase,
(EntireStructFileSize = Descriptor->EntireStructFileSize)
)))) {
goto Exit;
}
Member = Descriptor->MemberDescriptors;
MemberEnd = Member + Descriptor->NumberOfMembers;
__try {
for ( ; Member != MemberEnd; ++Member ) {
RtlCopyMemory(
SafeBuffer + Member->MemberOffsetInMemory,
StructInViewBase + Member->MemberOffsetInFile,
Member->MemberSize
);
}
Status = STATUS_SUCCESS;
}
__except(
//
// Note that we describe the entire frombuffer here.
// We do not describe the tobuffer, and we don't describe just one field.
// It is an optimization to not describe individual fields.
// We cannot describe the tobuffer accurately because its size is different (smaller)
// than the frombuffer.
//
RtlpCopyMappedMemoryEx_ExceptionFilter(
RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE,
NULL, // "to" isn't checked, and the tosize and fromsize are different
VoidStructInViewBase,
EntireStructFileSize,
NULL, // BytesCopied
NULL, // ExceptionRecordOut
GetExceptionInformation(),
&Status
)) {
}
Exit:
return Status;
}
#endif
#if NOT_YET_USED
NTSTATUS
NTAPI
RtlValidateMemoryMappedIoCapturePartialStructDescriptor(
PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_DESCRIPTOR Struct,
OUT PULONG Disposition,
OUT PULONG_PTR Detail OPTIONAL,
OUT PULONG_PTR Detail2 OPTIONAL
)
{
NTSTATUS Status;
NTSTATUS Status2;
PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR Member;
PCMEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_MEMBER_DESCRIPTOR MemberEnd;
PCSTR LocalDetail;
ULONG_PTR LocalDetail2;
ULONG LocalDisposition;
BOOLEAN SetDetail2;
SIZE_T OffsetEnd;
SetDetail2 = FALSE;
LocalDetail = NULL;
LocalDetail2 = 0;
Status = STATUS_INTERNAL_ERROR;
Status2 = STATUS_INTERNAL_ERROR;
Member = NULL;
MemberEnd = NULL;
LocalDisposition = RTL_VALIDATE_MEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_DESCRIPTOR_DISPOSITION_BAD;
OffsetEnd = 0;
if (ARGUMENT_PRESENT(Detail)) {
*Detail = 0;
}
if (ARGUMENT_PRESENT(Detail2)) {
*Detail2 = 0;
}
if (Disposition != NULL) {
*Disposition = LocalDisposition;
}
Status = STATUS_INVALID_PARAMETER;
if (!RTL_SOFT_VERIFY(Struct != NULL)) {
goto Exit;
}
if (!RTL_SOFT_VERIFY(Disposition != NULL)) {
goto Exit;
}
Status = STATUS_SUCCESS;
if (!RTL_SOFT_VERIFY(Struct->PartialStructMemorySize <= Struct->EntireStructFileSize)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("memory > file");
goto Exit;
}
//
// Given that members cannot have zero size,
// the number of members must be <= size.
//
if (!RTL_SOFT_VERIFY(Struct->NumberOfMembers <= Struct->EntireStructFileSize)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("nummemb <= filesize");
goto Exit;
}
if (!RTL_SOFT_VERIFY(Struct->NumberOfMembers <= Struct->PartialStructMemorySize)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("nummemb <= memsize");
goto Exit;
}
if (!RTL_SOFT_VERIFY(Struct->NumberOfMembers != 0)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("nummemb != 0");
goto Exit;
}
if (!RTL_SOFT_VERIFY(Struct->EntireStructFileSize != 0)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("filesize != 0");
goto Exit;
}
if (!RTL_SOFT_VERIFY(Struct->PartialStructMemorySize != 0)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("memsize != 0");
goto Exit;
}
if (!RTL_SOFT_VERIFY(Struct->MemberDescriptors != NULL)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("members != NULL");
goto Exit;
}
Member = Struct->MemberDescriptors;
MemberEnd = Member + Struct->NumberOfMembers;
SetDetail2 = TRUE;
for ( ; Member != MemberEnd; ++Member )
{
if (!RTL_SOFT_VERIFY(Member->MemberSize != 0)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("membersize != NULL");
goto Exit;
}
if (!RTL_SOFT_VERIFY(Member->MemberOffsetInFile < Struct->EntireStructFileSize)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("fileoffset < filesize");
goto Exit;
}
if (!RTL_SOFT_VERIFY(NT_SUCCESS(Status2 = RtlpAddWithOverflowCheckSizet(&OffsetEnd, Member->MemberOffsetInFile, Member->MemberSize)))) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("file overflow");
goto Exit;
}
if (!RTL_SOFT_VERIFY(OffsetEnd <= Struct->EntireStructFileSize)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("file out of bounds");
goto Exit;
}
if (!RTL_SOFT_VERIFY(Member->MemberOffsetInMemory < Struct->PartialStructMemorySize)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("memoffset < memsize");
goto Exit;
}
if (!RTL_SOFT_VERIFY(NT_SUCCESS(Status2 = RtlpAddWithOverflowCheckSizet(&OffsetEnd, Member->MemberOffsetInMemory, Member->MemberSize)))) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("mem overflow");
goto Exit;
}
if (!RTL_SOFT_VERIFY(OffsetEnd <= Struct->PartialStructMemorySize)) {
LocalDetail = RTLP_PREPEND_LINE_SPACE_TO_STRING("mem out of bounds");
goto Exit;
}
}
LocalDisposition = RTL_VALIDATE_MEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_DESCRIPTOR_DISPOSITION_GOOD;
Exit:
if (LocalDisposition == RTL_VALIDATE_MEMORY_MAPPED_IO_CAPTURE_PARTIAL_STRUCT_DESCRIPTOR_DISPOSITION_BAD) {
if (ARGUMENT_PRESENT(Detail)) {
*Detail = (ULONG_PTR)LocalDetail;
}
if (ARGUMENT_PRESENT(Detail2) && SetDetail2) {
*Detail2 = (MemberEnd - Member);
}
}
if (Disposition != NULL) {
*Disposition = LocalDisposition;
}
return Status;
}
#endif
#if NOT_YET_USED
NTSTATUS
NTAPI
RtlMappedViewStrlen(
PCVOID VoidViewBase,
SIZE_T ViewSize,
PCVOID VoidString,
OUT PSIZE_T OutLength OPTIONAL
)
/*++
Routine Description:
Given a mapped view and size and starting address, verify that the 8bit string
starting at the address is nul terminated within the mapped view, optionally
returning the length of the string.
in_page_errors are caught
Arguments:
VoidViewBase -
ViewSize -
VoidString -
OutLength -
Return Value:
STATUS_SUCCESS: the string is nul terminated within the view
STATUS_ACCESS_VIOLATION: the string is not nul terminated within the view
STATUS_IN_PAGE_ERROR
--*/
{
NTSTATUS Status;
PCBYTE ByteViewBase;
PCBYTE ByteViewEnd;
PCBYTE ByteString;
PCBYTE ByteStringEnd;
Status = STATUS_INTERNAL_ERROR;
ByteViewBase = (PCBYTE)VoidViewBase;
ByteViewEnd = ViewSize + ByteViewBase;
ByteString = (PCBYTE)VoidString;
ByteStringEnd = ByteString;
if (ARGUMENT_PRESENT(OutLength)) {
*OutLength = 0;
}
if (!(ByteString >= ByteViewBase && ByteString < ByteViewEnd)) {
Status = STATUS_ACCESS_VIOLATION;
goto Exit;
}
__try {
//
// This could be done more efficiently with page granularity, using memchr.
//
for ( ; ByteStringEnd != ByteViewEnd && *ByteStringEnd != 0 ; ++ByteStringEnd) {
// nothing
}
if (ByteStringEnd == ByteViewEnd) {
Status = STATUS_ACCESS_VIOLATION;
} else {
Status = STATUS_SUCCESS;
}
} __except(
//
// We describe the whole buffer instead of an individual byte so that
// the loop variables can be enregistered.
//
// If we switch to page granularity, this optimization may be less important.
//
RtlpCopyMappedMemoryEx_ExceptionFilter(
RTLP_COPY_MAPPED_MEMORY_EX_FLAG_CATCH_INPAGE_ERRORS_IN_FROM_RANGE, // flags
NULL, // no to address
VoidViewBase, // from address
ViewSize, // size
NULL, // BytesCopied
NULL, // ExceptionRecord,
GetExceptionInformation(),
&Status
)) {
ASSERT(Status != STATUS_SUCCESS);
}
if (ARGUMENT_PRESENT(OutLength)) {
*OutLength = (SIZE_T)(ByteStringEnd - ByteString);
}
Exit:
return Status;
}
#endif
#if NOT_YET_USED
NTSTATUS
NTAPI
RtlMappedViewRangeCheck(
PCVOID ViewBase,
SIZE_T ViewSize,
PCVOID DataAddress,
SIZE_T DataSize
)
/*++
Routine Description:
Given a mapped view and size, range check a data address and size.
Arguments:
ViewBase -
ViewSize -
DataAddress -
DataSize -
Return Value:
STATUS_SUCCESS: all of the data is within the view
STATUS_ACCESS_VIOLATION: some of the data is outside the view
--*/
{
ULONG_PTR UlongPtrViewBegin;
ULONG_PTR UlongPtrViewEnd;
ULONG_PTR UlongPtrDataBegin;
ULONG_PTR UlongPtrDataEnd;
BOOLEAN InBounds;
//
// UlongPtrDataBegin is a valid address.
// UlongPtrDataEnd is one past a valid address.
// We must not allow UlongPtrDataBegin == UlongPtrViewEnd.
// We must allow UlongPtrDataEnd == UlongPtrViewEnd.
// Therefore, we must not allow UlongPtrDataBegin == UlongPtrDataEnd.
// This can be achieved by not allowing DataSize == 0.
//
if (DataSize == 0)
{
DataSize = 1;
}
UlongPtrViewBegin = (ULONG_PTR)ViewBase;
UlongPtrViewEnd = UlongPtrViewBegin + ViewSize;
UlongPtrDataBegin = (ULONG_PTR)DataAddress;
UlongPtrDataEnd = UlongPtrDataBegin + DataSize;
InBounds =
( UlongPtrDataBegin >= UlongPtrViewBegin
&& UlongPtrDataBegin < UlongPtrDataEnd
&& UlongPtrDataEnd <= UlongPtrViewEnd
&& DataSize <= ViewSize
);
return (InBounds ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION);
}
#endif
#if NOT_YET_USED
//
// This code is not yet as robust as the "capture partial struct" functions,
// which do overflow checking, including offering a "preflight" validation of
// constant parameter blocks.
//
typedef struct _RTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT {
SIZE_T FromOffset;
SIZE_T ToOffset;
SIZE_T Size;
} RTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT, *PRTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT;
typedef CONST RTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT *PCRTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT;
#define RTL_COPY_MEMORY_SCATTER_GATHER_FLAG_VALID (0x00000001)
typedef struct _RTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS {
ULONG Flags;
PCVOID FromBase;
SIZE_T FromSize;
PVOID ToBase;
SIZE_T ToSize;
SIZE_T NumberOfScatterGatherListElements;
PCRTL_COPY_MEMORY_SCATTER_GATHER_LIST_ELEMENT ScatterGatherListElements;
struct {
BOOLEAN Caught;
NTSTATUS UnderlyingStatus;
PEXCEPTION_RECORD ExceptionRecord OPTIONAL;
SIZE_T BytesCopied;
SIZE_T FailedElementIndex;
} InpageError;
} RTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS, *PRTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS;
typedef CONST RTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS *PCRTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS;
#endif
#if NOT_YET_USED
LONG
RtlpCopyMemoryScatterGatherExceptionHandlerAssumeValid(
PRTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS Parameters,
PEXCEPTION_POINTERS ExceptionPointers
)
{
PEXCEPTION_RECORD ExceptionRecord = 0;
ULONG NumberParameters = 0;
ULONG_PTR ExceptionAddress = 0;
ULONG_PTR CaughtBase = 0;
NTSTATUS ExceptionCode = 0;
LONG Disposition = 0;
Disposition = EXCEPTION_CONTINUE_SEARCH;
ExceptionRecord = ExceptionPointers->ExceptionRecord;
ExceptionCode = ExceptionRecord->ExceptionCode;
if (ExceptionCode != STATUS_IN_PAGE_ERROR) {
goto Exit;
}
NumberParameters = ExceptionRecord->NumberParameters;
if (RTL_IN_PAGE_ERROR_EXCEPTION_INFO_FAULTING_VA_INDEX < NumberParameters) {
//
// We don't have the information to do the range check so give up and do
// not catch the exception. This can happen apparently.
//
goto Exit;
}
ExceptionAddress = ExceptionRecord->ExceptionInformation[RTL_IN_PAGE_ERROR_EXCEPTION_INFO_FAULTING_VA_INDEX];
if (ExceptionAddress >= (CaughtBase = (ULONG_PTR)Parameters->FromBase)
&& ExceptionAddress < (CaughtBase + Parameters->FromSize)) {
// nothing
} else if (ExceptionAddress >= (CaughtBase = (ULONG_PTR)Parameters->ToBase)
&& ExceptionAddress < (CaughtBase + Parameters->ToSize)) {
// nothing
}
else {
// not in range, don't catch it
goto Exit;
}
Disposition = EXCEPTION_EXECUTE_HANDLER;
Parameters->InpageError.Caught = TRUE;
Parameters->InpageError.BytesCopied = (SIZE_T)(ExceptionAddress - CaughtBase);
if (ARGUMENT_PRESENT(Parameters->InpageError.ExceptionRecord)) {
*Parameters->InpageError.ExceptionRecord = *ExceptionRecord;
}
if (RTL_IN_PAGE_ERROR_EXCEPTION_INFO_UNDERLYING_STATUS_INDEX < NumberParameters) {
ExceptionCode = (NTSTATUS) ExceptionRecord->ExceptionInformation[RTL_IN_PAGE_ERROR_EXCEPTION_INFO_UNDERLYING_STATUS_INDEX];
} else {
// else just leave it as status_in_page_error
}
Parameters->InpageError.UnderlyingStatus = ExceptionCode;
// DbgPrint...
Exit:
return Disposition;
}
#endif
#if NOT_YET_USED
LONG
NTAPI
RtlCopyMemoryScatterGatherExceptionHandler(
PRTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS Parameters,
PEXCEPTION_POINTERS ExceptionPointers
)
{
//
// This bit lets people turn off "large try/excepts" when they only really want
// catch inpage errors in a small part of the try body. The pattern is:
//
// __try {
// Parameters.Flags &= ~RTL_COPY_MEMORY_SCATTER_GATHER_FLAG_VALID;
// ...
// ... lots of code ...
// ...
// Parameters.Flags |= RTL_COPY_MEMORY_SCATTER_GATHER_FLAG_VALID;
// RtlCopyMemory(&Parameters);
// Parameters.Flags &= ~RTL_COPY_MEMORY_SCATTER_GATHER_FLAG_VALID;
// ...
// ... lots of code ...
// ...
// __except(RtlCopyMemoryScatterGatherExceptionHandler())
//
if ((Parameters->Flags & RTL_COPY_MEMORY_SCATTER_GATHER_FLAG_VALID) == 0) {
return EXCEPTION_CONTINUE_SEARCH;
}
return RtlpCopyMemoryScatterGatherExceptionHandlerAssumeValid(Parameters, ExceptionPointers);
}
#endif
#if NOT_YET_USED
NTSTATUS
NTAPI
RtlCopyMemoryScatterGather(
PRTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS Parameters
)
{
RTL_COPY_MEMORY_SCATTER_GATHER_PARAMETERS LocalParameters;
SIZE_T i;
NTSTATUS Status = 0;
// capture in locals to avoid unncessary pointer derefs in the loop
LocalParameters.FromBase = Parameters->FromBase;
LocalParameters.ToBase = Parameters->ToBase;
LocalParameters.NumberOfScatterGatherListElements = Parameters->NumberOfScatterGatherListElements;
LocalParameters.ScatterGatherListElements = Parameters->ScatterGatherListElements;
__try {
for (i = 0 ; i != LocalParameters.NumberOfScatterGatherListElements ; ++i) {
RtlCopyMemory(
((PBYTE)LocalParameters.ToBase) + LocalParameters.ScatterGatherListElements[i].ToOffset,
((PCBYTE)LocalParameters.FromBase) + LocalParameters.ScatterGatherListElements[i].FromOffset,
LocalParameters.ScatterGatherListElements[i].Size
);
}
Status = STATUS_SUCCESS;
} __except(RtlpCopyMemoryScatterGatherExceptionHandlerAssumeValid(Parameters, GetExceptionInformation())) {
Status = Parameters->InpageError.UnderlyingStatus;
Parameters->InpageError.FailedElementIndex = i;
}
return Status;
}
#endif
#if defined(__cplusplus)
} /* extern "C" */
#endif