139 lines
3.2 KiB
C
139 lines
3.2 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
probewrt.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the routine to support probe for write on
|
||
the Intel 386. The Intel 386 has the unique property that in
|
||
kernel mode the writable bit of the PTE is ignored. This allows
|
||
the kernel to write user mode pages which may be read only. Note,
|
||
that copy-on-write pages are protected as read-only as well, hence
|
||
the kernel could write to a user-mode copy on write page and the
|
||
copy on write would not occur.
|
||
|
||
|
||
Author:
|
||
|
||
Lou Perazzoli (loup) 6-Apr-1990
|
||
|
||
Environment:
|
||
|
||
Kernel mode only. Non-paged.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "mi.h"
|
||
|
||
|
||
VOID
|
||
MmProbeForWrite (
|
||
IN PVOID Address,
|
||
IN ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function probes an address for write accessibility on
|
||
the Intel 386.
|
||
|
||
Arguments:
|
||
|
||
Address - Supplies a pointer to the structure to probe.
|
||
|
||
Length - Supplies the length of the structure.
|
||
|
||
Return Value:
|
||
|
||
None. If the Address cannot be written an exception is raised.
|
||
|
||
--*/
|
||
|
||
{
|
||
PMMPTE PointerPte;
|
||
PMMPTE LastPte;
|
||
MMPTE PteContents;
|
||
CCHAR Temp;
|
||
|
||
//
|
||
// Loop on the copy on write case until the page is only
|
||
// writable.
|
||
//
|
||
|
||
if (Address >= (PVOID)MM_HIGHEST_USER_ADDRESS) {
|
||
ExRaiseStatus(STATUS_ACCESS_VIOLATION);
|
||
}
|
||
|
||
PointerPte = MiGetPteAddress (Address);
|
||
LastPte = MiGetPteAddress ((PVOID)((ULONG)Address + Length - 1));
|
||
|
||
while (PointerPte <= LastPte) {
|
||
|
||
for (;;) {
|
||
|
||
//
|
||
// Touch the address as a byte to check for readability and
|
||
// get the PTE built.
|
||
//
|
||
|
||
do {
|
||
Temp = *(volatile CCHAR *)Address;
|
||
PteContents = *(volatile MMPTE *)PointerPte;
|
||
} while (PteContents.u.Hard.Valid == 0);
|
||
|
||
if (PteContents.u.Hard.Write == 1) {
|
||
|
||
//
|
||
// The PTE is writable and not copy on write.
|
||
//
|
||
|
||
break;
|
||
}
|
||
|
||
if (PteContents.u.Hard.CopyOnWrite == 1) {
|
||
|
||
//
|
||
// The PTE is copy on write. Call the pager and let
|
||
// it deal with this. Once the page fault is complete,
|
||
// this loop will again be repeated and the PTE will
|
||
// again be checked for write access and copy-on-write
|
||
// access. The PTE could still be copy-on-write even
|
||
// after the pager is called if the page table page
|
||
// was removed from the working set at this time (unlikely,
|
||
// but still possible).
|
||
//
|
||
|
||
if (!NT_SUCCESS (MmAccessFault (TRUE,
|
||
Address,
|
||
UserMode))) {
|
||
|
||
//
|
||
// Raise an access violation status.
|
||
//
|
||
|
||
ExRaiseStatus(STATUS_ACCESS_VIOLATION);
|
||
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// Raise an access violation status.
|
||
//
|
||
|
||
ExRaiseStatus(STATUS_ACCESS_VIOLATION);
|
||
|
||
}
|
||
}
|
||
PointerPte += 1;
|
||
Address = (PVOID)((ULONG)Address + PAGE_SIZE);
|
||
}
|
||
}
|