Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

protect.c File Reference

#include "mi.h"

Go to the source code of this file.

Functions

HARDWARE_PTE MiFlushTbAndCapture (IN PMMPTE PtePointer, IN HARDWARE_PTE TempPte, IN PMMPFN Pfn1)
ULONG MiSetProtectionOnTransitionPte (IN PMMPTE PointerPte, IN ULONG ProtectionMask)
MMPTE MiCaptureSystemPte (IN PMMPTE PointerProtoPte, IN PEPROCESS Process)
NTSTATUS NtProtectVirtualMemory (IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN OUT PSIZE_T RegionSize, IN ULONG NewProtect, OUT PULONG OldProtect)
NTSTATUS MiProtectVirtualMemory (IN PEPROCESS Process, IN PVOID *BaseAddress, IN PSIZE_T RegionSize, IN ULONG NewProtect, IN PULONG LastProtect)
ULONG MiSetProtectionOnSection (IN PEPROCESS Process, IN PMMVAD FoundVad, IN PVOID StartingAddress, IN PVOID EndingAddress, IN ULONG NewProtect, OUT PULONG CapturedOldProtect, IN ULONG DontCharge)
ULONG MiGetPageProtection (IN PMMPTE PointerPte, IN PEPROCESS Process)
ULONG MiChangeNoAccessForkPte (IN PMMPTE PointerPte, IN ULONG ProtectionMask)
NTSTATUS MiCheckSecuredVad (IN PMMVAD Vad, IN PVOID Base, IN SIZE_T Size, IN ULONG ProtectionMask)

Variables

CCHAR MmReadWrite [32]


Function Documentation

MMPTE MiCaptureSystemPte IN PMMPTE  PointerProtoPte,
IN PEPROCESS  Process
 

Definition at line 2204 of file protect.c.

References LOCK_PFN, MiMakeSystemAddressValidPfnWs(), and UNLOCK_PFN.

02211 : 02212 02213 Nonpagable helper routine to capture the contents of a pagable PTE. 02214 02215 Arguments: 02216 02217 PointerProtoPte - Supplies a pointer to the prototype PTE. 02218 02219 Process - Supplies the relevant process. 02220 02221 Return Value: 02222 02223 PTE contents. 02224 02225 Environment: 02226 02227 Kernel mode. Caller holds address space and working set mutexes if 02228 Process is set. Working set mutex was acquired unsafe. 02229 02230 --*/ 02231 02232 { 02233 MMPTE TempPte; 02234 KIRQL OldIrql; 02235 02236 LOCK_PFN (OldIrql); 02237 MiMakeSystemAddressValidPfnWs (PointerProtoPte, Process); 02238 TempPte = *PointerProtoPte; 02239 UNLOCK_PFN (OldIrql); 02240 return TempPte; 02241 }

ULONG MiChangeNoAccessForkPte IN PMMPTE  PointerPte,
IN ULONG  ProtectionMask
 

Definition at line 2032 of file protect.c.

References FALSE, MM_NOACCESS, PAGED_CODE, and TRUE.

Referenced by MiProtectVirtualMemory(), and MiSetProtectionOnSection().

02039 : 02040 02041 02042 Arguments: 02043 02044 PointerPte - Supplies a pointer to the current PTE. 02045 02046 ProtectionMask - Supplies the protection mask to set. 02047 02048 Return Value: 02049 02050 FALSE if the loop should be repeated for this PTE, TRUE 02051 if protection has been set. 02052 02053 02054 Environment: 02055 02056 Kernel mode, address creation mutex held, APCs disabled. 02057 02058 --*/ 02059 02060 { 02061 PAGED_CODE(); 02062 02063 if (ProtectionMask == MM_NOACCESS) { 02064 02065 // 02066 // No need to change the page protection. 02067 // 02068 02069 return TRUE; 02070 } 02071 02072 PointerPte->u.Proto.ReadOnly = 1; 02073 02074 return FALSE; 02075 }

NTSTATUS MiCheckSecuredVad IN PMMVAD  Vad,
IN PVOID  Base,
IN SIZE_T  Size,
IN ULONG  ProtectionMask
 

Definition at line 2244 of file protect.c.

References End, _MMSECURE_ENTRY::EndVpn, _MMSECURE_ENTRY::List, List, MM_GUARD_PAGE, MM_SECURE_DELETE_CHECK, MmReadWrite, NTSTATUS(), Size, _MMSECURE_ENTRY::StartVpn, Status, and _MMSECURE_ENTRY::u2.

Referenced by MiProtectVirtualMemory(), MmUnmapViewOfSection(), NtAllocateVirtualMemory(), and NtFreeVirtualMemory().

02253 : 02254 02255 This routine checks to see if the specified VAD is secured in such 02256 a way as to conflict with the address range and protection mask 02257 specified. 02258 02259 Arguments: 02260 02261 Vad - Supplies a pointer to the VAD containing the address range. 02262 02263 Base - Supplies the base of the range the protection starts at. 02264 02265 Size - Supplies the size of the range. 02266 02267 ProtectionMask - Supplies the protection mask being set. 02268 02269 Return Value: 02270 02271 Status value. 02272 02273 Environment: 02274 02275 Kernel mode. 02276 02277 --*/ 02278 02279 { 02280 PVOID End; 02281 PLIST_ENTRY Next; 02282 PMMSECURE_ENTRY Entry; 02283 NTSTATUS Status = STATUS_SUCCESS; 02284 02285 End = (PVOID)((PCHAR)Base + Size); 02286 02287 if (ProtectionMask < MM_SECURE_DELETE_CHECK) { 02288 if ((Vad->u.VadFlags.NoChange == 1) && 02289 (Vad->u2.VadFlags2.SecNoChange == 1) && 02290 (Vad->u.VadFlags.Protection != ProtectionMask)) { 02291 02292 // 02293 // An attempt is made at changing the protection 02294 // of a SEC_NO_CHANGE section - return an error. 02295 // 02296 02297 Status = STATUS_INVALID_PAGE_PROTECTION; 02298 goto done; 02299 } 02300 } else { 02301 02302 // 02303 // Deletion - set to no-access for check. SEC_NOCHANGE allows 02304 // deletion, but does not allow page protection changes. 02305 // 02306 02307 ProtectionMask = 0; 02308 } 02309 02310 if (Vad->u2.VadFlags2.OneSecured) { 02311 02312 if (((ULONG_PTR)Base <= Vad->u3.Secured.EndVpn) && 02313 ((ULONG_PTR)End >= Vad->u3.Secured.StartVpn)) { 02314 02315 // 02316 // This region conflicts, check the protections. 02317 // 02318 02319 if (ProtectionMask & MM_GUARD_PAGE) { 02320 Status = STATUS_INVALID_PAGE_PROTECTION; 02321 goto done; 02322 } 02323 02324 if (Vad->u2.VadFlags2.ReadOnly) { 02325 if (MmReadWrite[ProtectionMask] < 10) { 02326 Status = STATUS_INVALID_PAGE_PROTECTION; 02327 goto done; 02328 } 02329 } else { 02330 if (MmReadWrite[ProtectionMask] < 11) { 02331 Status = STATUS_INVALID_PAGE_PROTECTION; 02332 goto done; 02333 } 02334 } 02335 } 02336 02337 } else if (Vad->u2.VadFlags2.MultipleSecured) { 02338 02339 Next = Vad->u3.List.Flink; 02340 do { 02341 Entry = CONTAINING_RECORD( Next, 02342 MMSECURE_ENTRY, 02343 List); 02344 02345 if (((ULONG_PTR)Base <= Entry->EndVpn) && 02346 ((ULONG_PTR)End >= Entry->StartVpn)) { 02347 02348 // 02349 // This region conflicts, check the protections. 02350 // 02351 02352 if (ProtectionMask & MM_GUARD_PAGE) { 02353 Status = STATUS_INVALID_PAGE_PROTECTION; 02354 goto done; 02355 } 02356 02357 if (Entry->u2.VadFlags2.ReadOnly) { 02358 if (MmReadWrite[ProtectionMask] < 10) { 02359 Status = STATUS_INVALID_PAGE_PROTECTION; 02360 goto done; 02361 } 02362 } else { 02363 if (MmReadWrite[ProtectionMask] < 11) { 02364 Status = STATUS_INVALID_PAGE_PROTECTION; 02365 goto done; 02366 } 02367 } 02368 } 02369 Next = Entry->List.Flink; 02370 } while (Entry->List.Flink != &Vad->u3.List); 02371 } 02372 02373 done: 02374 return Status; 02375 }

HARDWARE_PTE MiFlushTbAndCapture IN PMMPTE  PtePointer,
IN HARDWARE_PTE  TempPte,
IN PMMPFN  Pfn1
 

Definition at line 2079 of file protect.c.

References ASSERT, FALSE, KeFlushSingleTb(), LOCK_PFN, MI_CAPTURE_DIRTY_BIT_TO_PFN, MI_IS_PTE_DIRTY, MiActiveWriteWatch, MiCaptureWriteWatchDirtyBit(), MiGetVirtualAddressMappedByPte, PsGetCurrentProcess, _MMSUPPORT::u, _MMPTE::u, UNLOCK_PFN, and _EPROCESS::Vm.

Referenced by MiProtectVirtualMemory(), and MiSetProtectionOnSection().

02087 { 02088 MMPTE PreviousPte; 02089 KIRQL OldIrql; 02090 PEPROCESS Process; 02091 PVOID VirtualAddress; 02092 02093 // 02094 // Flush the TB as we have changed the protection 02095 // of a valid PTE. 02096 // 02097 02098 LOCK_PFN (OldIrql); 02099 02100 PreviousPte.u.Flush = KeFlushSingleTb ( 02101 MiGetVirtualAddressMappedByPte (PointerPte), 02102 FALSE, 02103 FALSE, 02104 (PHARDWARE_PTE)PointerPte, 02105 TempPte); 02106 02107 ASSERT (PreviousPte.u.Hard.Valid == 1); 02108 02109 // 02110 // A page protection is being changed, on certain 02111 // hardware the dirty bit should be ORed into the 02112 // modify bit in the PFN element. 02113 // 02114 02115 MI_CAPTURE_DIRTY_BIT_TO_PFN (&PreviousPte, Pfn1); 02116 02117 // 02118 // If the PTE indicates the page has been modified (this is different 02119 // from the PFN indicating this), then ripple it back to the write watch 02120 // bitmap now since we are still in the correct process context. 02121 // 02122 02123 if (MiActiveWriteWatch != 0) { 02124 if ((Pfn1->u3.e1.PrototypePte == 0) && 02125 (MI_IS_PTE_DIRTY(PreviousPte))) { 02126 02127 Process = PsGetCurrentProcess(); 02128 02129 if (Process->Vm.u.Flags.WriteWatch == 1) { 02130 02131 // 02132 // This process has (or had) write watch VADs. Search now 02133 // for a write watch region encapsulating the PTE being 02134 // invalidated. 02135 // 02136 02137 VirtualAddress = MiGetVirtualAddressMappedByPte (PointerPte); 02138 MiCaptureWriteWatchDirtyBit (Process, VirtualAddress); 02139 } 02140 } 02141 } 02142 #if DBG 02143 else { 02144 Process = PsGetCurrentProcess(); 02145 ASSERT (Process->Vm.u.Flags.WriteWatch == 0); 02146 } 02147 #endif 02148 02149 UNLOCK_PFN (OldIrql); 02150 return PreviousPte.u.Flush; 02151 }

ULONG MiGetPageProtection IN PMMPTE  PointerPte,
IN PEPROCESS  Process
 

Definition at line 1874 of file protect.c.

References Index, KSTACK_POOL_START, MI_CONVERT_FROM_PTE_PROTECTION, MI_IS_PTE_PROTOTYPE, MI_PFN_ELEMENT, MI_PTE_LOOKUP_NEEDED, MiCaptureSystemPte(), MiGetVirtualAddressMappedByPte, MiLocateWsle(), MiNumberOfExtraSystemPdes, MiPteToProto, MM_VA_MAPPED_BY_PDE, MmWorkingSetList, MmWsle, _MMPFN::OriginalPte, PAGED_CODE, _MMPTE::u, _MMPFN::u1, and _MMPFN::u3.

Referenced by MiProtectVirtualMemory(), MiQueryAddressState(), MiSetProtectionOnSection(), and NtAllocateVirtualMemory().

01881 : 01882 01883 This routine returns the page protection of a non-zero PTE. 01884 It may release and reacquire the working set mutex. 01885 01886 Arguments: 01887 01888 PointerPte - Supplies a pointer to a non-zero PTE. 01889 01890 Return Value: 01891 01892 Returns the protection code. 01893 01894 Environment: 01895 01896 Kernel mode, working set and address creation mutex held. 01897 Note, that the address creation mutex does not need to be held 01898 if the working set mutex does not need to be released in the 01899 case of a prototype PTE. 01900 01901 --*/ 01902 01903 { 01904 01905 MMPTE PteContents; 01906 MMPTE ProtoPteContents; 01907 PMMPFN Pfn1; 01908 PMMPTE ProtoPteAddress; 01909 PVOID Va; 01910 ULONG Index; 01911 01912 PAGED_CODE(); 01913 01914 PteContents = *PointerPte; 01915 01916 if ((PteContents.u.Soft.Valid == 0) && (PteContents.u.Soft.Prototype == 1)) { 01917 01918 // 01919 // This pte is in prototype format, the protection is 01920 // stored in the prototype PTE. 01921 // 01922 01923 if (MI_IS_PTE_PROTOTYPE(PointerPte) || 01924 #ifdef _X86_ 01925 (MiNumberOfExtraSystemPdes && (PointerPte >= (PMMPTE)KSTACK_POOL_START && PointerPte < (PMMPTE)(KSTACK_POOL_START + MiNumberOfExtraSystemPdes * MM_VA_MAPPED_BY_PDE))) || 01926 #endif 01927 (PteContents.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)) { 01928 01929 // 01930 // The protection is within this PTE. 01931 // 01932 01933 return MI_CONVERT_FROM_PTE_PROTECTION ( 01934 PteContents.u.Soft.Protection); 01935 } 01936 01937 ProtoPteAddress = MiPteToProto (PointerPte); 01938 01939 // 01940 // Capture protopte PTE contents. 01941 // 01942 01943 ProtoPteContents = MiCaptureSystemPte (ProtoPteAddress, Process); 01944 01945 // 01946 // The working set mutex may have been released and the 01947 // page may no longer be in prototype format, get the 01948 // new contents of the PTE and obtain the protection mask. 01949 // 01950 01951 PteContents = MiCaptureSystemPte (PointerPte, Process); 01952 } 01953 01954 if ((PteContents.u.Soft.Valid == 0) && (PteContents.u.Soft.Prototype == 1)) { 01955 01956 // 01957 // Pte is still prototype, return the protection captured 01958 // from the prototype PTE. 01959 // 01960 01961 if (ProtoPteContents.u.Hard.Valid == 1) { 01962 01963 // 01964 // The prototype PTE is valid, get the protection from 01965 // the PFN database. 01966 // 01967 01968 Pfn1 = MI_PFN_ELEMENT (ProtoPteContents.u.Hard.PageFrameNumber); 01969 return MI_CONVERT_FROM_PTE_PROTECTION( 01970 Pfn1->OriginalPte.u.Soft.Protection); 01971 01972 } else { 01973 01974 // 01975 // The prototype PTE is not valid, return the protection from the 01976 // PTE. 01977 // 01978 01979 return MI_CONVERT_FROM_PTE_PROTECTION ( 01980 ProtoPteContents.u.Soft.Protection); 01981 } 01982 } 01983 01984 if (PteContents.u.Hard.Valid == 1) { 01985 01986 // 01987 // The page is valid, the protection field is either in the 01988 // PFN database original PTE element or the WSLE. If 01989 // the page is private, get it from the PFN original PTE 01990 // element, else use the WSLE. 01991 // 01992 01993 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 01994 01995 if ((Pfn1->u3.e1.PrototypePte == 0) || 01996 #ifdef _X86_ 01997 (MiNumberOfExtraSystemPdes && (PointerPte >= (PMMPTE)KSTACK_POOL_START && PointerPte < (PMMPTE)(KSTACK_POOL_START + MiNumberOfExtraSystemPdes * MM_VA_MAPPED_BY_PDE))) || 01998 #endif 01999 (MI_IS_PTE_PROTOTYPE(PointerPte))) { 02000 02001 // 02002 // This is a private PTE or the PTE address is that of a 02003 // prototype PTE, hence the protection is in 02004 // the original PTE. 02005 // 02006 02007 return MI_CONVERT_FROM_PTE_PROTECTION( 02008 Pfn1->OriginalPte.u.Soft.Protection); 02009 } 02010 02011 // 02012 // The PTE was a hardware PTE, get the protection 02013 // from the WSLE. 02014 02015 Va = (PULONG)MiGetVirtualAddressMappedByPte (PointerPte); 02016 Index = MiLocateWsle ((PVOID)Va, MmWorkingSetList, 02017 Pfn1->u1.WsIndex); 02018 02019 return MI_CONVERT_FROM_PTE_PROTECTION (MmWsle[Index].u1.e1.Protection); 02020 } 02021 02022 // 02023 // PTE is either demand zero or transition, in either 02024 // case protection is in PTE. 02025 // 02026 02027 return MI_CONVERT_FROM_PTE_PROTECTION (PteContents.u.Soft.Protection); 02028 02029 }

NTSTATUS MiProtectVirtualMemory IN PEPROCESS  Process,
IN PVOID *  BaseAddress,
IN PSIZE_T  RegionSize,
IN ULONG  NewProtect,
IN PULONG  LastProtect
 

Definition at line 344 of file protect.c.

References ALT_CHANGE, ASSERT, _MMVAD::ControlArea, _MMVAD::EndingVpn, ExAcquireFastMutexUnsafe(), EXCEPTION_EXECUTE_HANDLER, ExReleaseFastMutexUnsafe(), FALSE, L, LOCK_WS_AND_ADDRESS_SPACE, LOCK_WS_UNSAFE, MI_CONVERT_FROM_PTE_PROTECTION, MI_GET_USED_PTES_HANDLE, MI_GET_WORKING_SET_FROM_PTE, MI_INCREMENT_USED_PTES_BY_HANDLE, MI_MAKE_VALID_PTE, MI_PFN_ELEMENT, MI_SET_PTE_IN_WORKING_SET, MI_VA_TO_VPN, MiChangeNoAccessForkPte(), MiCheckForConflictingVad, MiCheckSecuredVad(), MiCopyOnWrite(), MiDoesPdeExistAndMakeValid(), MiDoesPpeExistAndMakeValid, MiFlushTbAndCapture(), MiGetPageProtection(), MiGetPdeAddress, MiGetPpeAddress, MiGetProtoPteAddress, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiIsEntireRangeCommitted(), MiIsPteOnPdeBoundary, MiMakePdeExistAndMakeValid(), MiMakePpeExistAndMakeValid, MiMakeProtectForNativePage(), MiMakeProtectionMask(), MiProtectFor4kPage(), MiQueryProtectionFor4kPage(), MiRemovePageFromWorkingSet(), MiSetProtectionOnSection(), MiSetProtectionOnTransitionPte(), MM_PROTECTION_COPY_MASK, MmSectionCommitMutex, NT_SUCCESS, NTSTATUS(), NULL, _MMPFN::OriginalPte, PAGE_4K, PAGE_4K_ALIGN, PAGE_ALIGN, PAGE_SIZE, _MMVAD::StartingVpn, Status, TRUE, _MMPTE::u, _CONTROL_AREA::u, _MMVAD::u, _MMVAD::u2, _MMPFN::u3, UNLOCK_ADDRESS_SPACE, UNLOCK_WS_AND_ADDRESS_SPACE, UNLOCK_WS_UNSAFE, and VOID().

Referenced by NtAllocateVirtualMemory(), and NtProtectVirtualMemory().

00354 : 00355 00356 This routine changes the protection on a region of committed pages 00357 within the virtual address space of the subject process. Setting 00358 the protection on a range of pages causes the old protection to be 00359 replaced by the specified protection value. 00360 00361 Arguments: 00362 00363 Process - Supplies a pointer to the current process. 00364 00365 BaseAddress - Supplies the starting address to protect. 00366 00367 RegionsSize - Supplies the size of the region to protect. 00368 00369 NewProtect - Supplies the new protection to set. 00370 00371 LastProtect - Supplies the address of a kernel owned pointer to 00372 store (without probing) the old protection into. 00373 00374 00375 Return Value: 00376 00377 the status of the protect operation. 00378 00379 Environment: 00380 00381 Kernel mode 00382 00383 --*/ 00384 00385 { 00386 PMMVAD FoundVad; 00387 PVOID StartingAddress; 00388 PVOID EndingAddress; 00389 PVOID CapturedBase; 00390 SIZE_T CapturedRegionSize; 00391 NTSTATUS Status; 00392 ULONG Attached; 00393 PMMPTE PointerPte; 00394 PMMPTE LastPte; 00395 PMMPTE PointerPde; 00396 PMMPTE PointerPpe; 00397 PMMPTE PointerProtoPte; 00398 PMMPTE LastProtoPte; 00399 PMMPFN Pfn1; 00400 ULONG CapturedOldProtect; 00401 ULONG ProtectionMask; 00402 MMPTE TempPte; 00403 MMPTE PteContents; 00404 MMPTE PreviousPte; 00405 ULONG Locked; 00406 PVOID Va; 00407 ULONG DoAgain; 00408 ULONG Waited; 00409 PVOID UsedPageTableHandle; 00410 PVOID UsedPageDirectoryHandle; 00411 ULONG WorkingSetIndex; 00412 #if defined(_MIALT4K_) 00413 PVOID OriginalBase; 00414 SIZE_T OriginalRegionSize; 00415 ULONG OriginalProtectionMask; 00416 PVOID StartingAddressFor4k; 00417 PVOID EndingAddressFor4k; 00418 SIZE_T CapturedRegionSizeFor4k; 00419 ULONG CapturedOldProtectFor4k; 00420 BOOLEAN EmulationFor4kPage = FALSE; 00421 #endif 00422 00423 Attached = FALSE; 00424 Locked = FALSE; 00425 00426 // 00427 // Get the address creation mutex to block multiple threads from 00428 // creating or deleting address space at the same time. 00429 // Get the working set mutex so PTEs can be modified. 00430 // Block APCs so an APC which takes a page 00431 // fault does not corrupt various structures. 00432 // 00433 00434 CapturedBase = *BaseAddress; 00435 CapturedRegionSize = *RegionSize; 00436 00437 #if defined(_MIALT4K_) 00438 OriginalBase = CapturedBase; 00439 OriginalRegionSize = CapturedRegionSize; 00440 00441 if (Process->Wow64Process != NULL) { 00442 00443 StartingAddressFor4k = (PVOID)PAGE_4K_ALIGN(OriginalBase); 00444 00445 EndingAddressFor4k = (PVOID)(((ULONG_PTR)OriginalBase + 00446 OriginalRegionSize - 1) | (PAGE_4K - 1)); 00447 00448 CapturedRegionSizeFor4k = (ULONG_PTR)EndingAddressFor4k - 00449 (ULONG_PTR)StartingAddressFor4k + 1L; 00450 00451 OriginalProtectionMask = MiMakeProtectionMask(NewProtect); 00452 00453 EmulationFor4kPage = TRUE; 00454 00455 } 00456 #endif 00457 00458 try { 00459 ProtectionMask = MiMakeProtectionMask (NewProtect); 00460 } except (EXCEPTION_EXECUTE_HANDLER) { 00461 return GetExceptionCode(); 00462 } 00463 00464 LOCK_WS_AND_ADDRESS_SPACE (Process); 00465 00466 // 00467 // Make sure the address space was not deleted, if so, return an error. 00468 // 00469 00470 if (Process->AddressSpaceDeleted != 0) { 00471 Status = STATUS_PROCESS_IS_TERMINATING; 00472 goto ErrorFound; 00473 } 00474 00475 EndingAddress = (PVOID)(((ULONG_PTR)CapturedBase + 00476 CapturedRegionSize - 1L) | (PAGE_SIZE - 1L)); 00477 StartingAddress = (PVOID)PAGE_ALIGN(CapturedBase); 00478 FoundVad = MiCheckForConflictingVad (StartingAddress, EndingAddress); 00479 00480 if (FoundVad == (PMMVAD)NULL) { 00481 00482 // 00483 // No virtual address is reserved at the specified base address, 00484 // return an error. 00485 // 00486 00487 Status = STATUS_CONFLICTING_ADDRESSES; 00488 goto ErrorFound; 00489 } 00490 00491 // 00492 // Ensure that the starting and ending addresses are all within 00493 // the same virtual address descriptor. 00494 // 00495 00496 if ((MI_VA_TO_VPN (StartingAddress) < FoundVad->StartingVpn) || 00497 (MI_VA_TO_VPN (EndingAddress) > FoundVad->EndingVpn)) { 00498 00499 // 00500 // Not within the section virtual address descriptor, 00501 // return an error. 00502 // 00503 00504 Status = STATUS_CONFLICTING_ADDRESSES; 00505 goto ErrorFound; 00506 } 00507 00508 if (FoundVad->u.VadFlags.UserPhysicalPages == 1) { 00509 00510 // 00511 // These must always be readwrite. 00512 // 00513 00514 Status = STATUS_CONFLICTING_ADDRESSES; 00515 goto ErrorFound; 00516 } 00517 00518 if (FoundVad->u.VadFlags.PhysicalMapping == 1) { 00519 00520 // 00521 // Setting the protection of a physically mapped section is 00522 // not allowed as there is no corresponding PFN database element. 00523 // 00524 00525 Status = STATUS_CONFLICTING_ADDRESSES; 00526 goto ErrorFound; 00527 } 00528 00529 if (FoundVad->u.VadFlags.NoChange == 1) { 00530 00531 // 00532 // An attempt is made at changing the protection 00533 // of a secured VAD, check to see if the address range 00534 // to change allows the change. 00535 // 00536 00537 Status = MiCheckSecuredVad (FoundVad, 00538 CapturedBase, 00539 CapturedRegionSize, 00540 ProtectionMask); 00541 00542 if (!NT_SUCCESS (Status)) { 00543 goto ErrorFound; 00544 } 00545 } 00546 #if defined(_MIALT4K_) 00547 else if (EmulationFor4kPage == TRUE) { 00548 // 00549 // if not secured, relax the protection 00550 // 00551 00552 NewProtect = MiMakeProtectForNativePage(StartingAddressFor4k, 00553 NewProtect, 00554 Process); 00555 00556 ProtectionMask = MiMakeProtectionMask (NewProtect); 00557 } 00558 #endif 00559 00560 if (FoundVad->u.VadFlags.PrivateMemory == 0) { 00561 00562 00563 // 00564 // For mapped sections, the NO_CACHE attribute is not allowed. 00565 // 00566 00567 if (NewProtect & PAGE_NOCACHE) { 00568 00569 // 00570 // Not allowed. 00571 // 00572 00573 Status = STATUS_INVALID_PARAMETER_4; 00574 goto ErrorFound; 00575 } 00576 00577 // 00578 // If this is a file mapping, then all pages must be 00579 // committed as there can be no sparse file maps. Images 00580 // can have non-committed pages if the alignment is greater 00581 // than the page size. 00582 // 00583 00584 if ((FoundVad->ControlArea->u.Flags.File == 0) || 00585 (FoundVad->ControlArea->u.Flags.Image == 1)) { 00586 00587 PointerProtoPte = MiGetProtoPteAddress (FoundVad, 00588 MI_VA_TO_VPN (StartingAddress)); 00589 LastProtoPte = MiGetProtoPteAddress (FoundVad, 00590 MI_VA_TO_VPN (EndingAddress)); 00591 00592 // 00593 // Release the working set mutex and acquire the section 00594 // commit mutex. Check all the prototype PTEs described by 00595 // the virtual address range to ensure they are committed. 00596 // 00597 00598 UNLOCK_WS_UNSAFE (Process); 00599 ExAcquireFastMutexUnsafe (&MmSectionCommitMutex); 00600 00601 while (PointerProtoPte <= LastProtoPte) { 00602 00603 // 00604 // Check to see if the prototype PTE is committed, if 00605 // not return an error. 00606 // 00607 00608 if (PointerProtoPte->u.Long == 0) { 00609 00610 // 00611 // Error, this prototype PTE is not committed. 00612 // 00613 00614 ExReleaseFastMutexUnsafe (&MmSectionCommitMutex); 00615 Status = STATUS_NOT_COMMITTED; 00616 UNLOCK_ADDRESS_SPACE (Process); 00617 goto ErrorFoundNoWs; 00618 } 00619 PointerProtoPte += 1; 00620 } 00621 00622 // 00623 // The range is committed, release the section commitment 00624 // mutex, acquire the working set mutex and update the local PTEs. 00625 // 00626 00627 ExReleaseFastMutexUnsafe (&MmSectionCommitMutex); 00628 00629 // 00630 // Set the protection on the section pages. This could 00631 // get a quota exceeded exception. 00632 // 00633 00634 LOCK_WS_UNSAFE (Process); 00635 } 00636 00637 #if defined(_MIALT4K_) 00638 00639 // 00640 // We need to change the alternate table before PTEs are created for the protection 00641 // change. 00642 // 00643 00644 if (EmulationFor4kPage == TRUE) { 00645 00646 // 00647 // Before accessing Alternate Table, unlock the working set mutex 00648 // 00649 00650 UNLOCK_WS_UNSAFE (Process); 00651 00652 // 00653 // Get the old protection 00654 // 00655 00656 CapturedOldProtectFor4k = 00657 MiQueryProtectionFor4kPage(StartingAddressFor4k, Process); 00658 00659 if (CapturedOldProtectFor4k != 0) { 00660 00661 CapturedOldProtectFor4k = 00662 MI_CONVERT_FROM_PTE_PROTECTION(CapturedOldProtectFor4k); 00663 00664 } 00665 00666 // 00667 // Set the alternate permission table 00668 // 00669 00670 if ((FoundVad->u.VadFlags.ImageMap == 1) || 00671 (FoundVad->u2.VadFlags2.CopyOnWrite == 1)) { 00672 00673 OriginalProtectionMask |= MM_PROTECTION_COPY_MASK; 00674 00675 } 00676 00677 MiProtectFor4kPage (StartingAddressFor4k, 00678 CapturedRegionSizeFor4k, 00679 OriginalProtectionMask, 00680 ALT_CHANGE, 00681 Process); 00682 00683 LOCK_WS_UNSAFE (Process); 00684 } 00685 #endif 00686 00687 try { 00688 Locked = MiSetProtectionOnSection ( Process, 00689 FoundVad, 00690 StartingAddress, 00691 EndingAddress, 00692 NewProtect, 00693 &CapturedOldProtect, 00694 FALSE ); 00695 00696 } except (EXCEPTION_EXECUTE_HANDLER) { 00697 00698 Status = GetExceptionCode(); 00699 goto ErrorFound; 00700 } 00701 } else { 00702 00703 // 00704 // Not a section, private. 00705 // For private pages, the WRITECOPY attribute is not allowed. 00706 // 00707 00708 if ((NewProtect & PAGE_WRITECOPY) || 00709 (NewProtect & PAGE_EXECUTE_WRITECOPY)) { 00710 00711 // 00712 // Not allowed. 00713 // 00714 00715 Status = STATUS_INVALID_PARAMETER_4; 00716 goto ErrorFound; 00717 } 00718 00719 // 00720 // Ensure all of the pages are already committed as described 00721 // in the virtual address descriptor. 00722 // 00723 00724 if ( !MiIsEntireRangeCommitted(StartingAddress, 00725 EndingAddress, 00726 FoundVad, 00727 Process)) { 00728 00729 // 00730 // Previously reserved pages have been decommitted, or an error 00731 // occurred, release mutex and return status. 00732 // 00733 00734 Status = STATUS_NOT_COMMITTED; 00735 goto ErrorFound; 00736 } 00737 00738 #if defined(_MIALT4K_) 00739 00740 // 00741 // We need to change the alternate table before PTEs are created for the protection 00742 // change. 00743 // 00744 00745 if (EmulationFor4kPage == TRUE) { 00746 00747 // 00748 // Before accessing Alternate Table, unlock the working set mutex 00749 // 00750 00751 UNLOCK_WS_UNSAFE (Process); 00752 00753 // 00754 // Get the old protection 00755 // 00756 00757 CapturedOldProtectFor4k = 00758 MiQueryProtectionFor4kPage(StartingAddressFor4k, Process); 00759 00760 if (CapturedOldProtectFor4k != 0) { 00761 00762 CapturedOldProtectFor4k = 00763 MI_CONVERT_FROM_PTE_PROTECTION(CapturedOldProtectFor4k); 00764 00765 } 00766 00767 // 00768 // Set the alternate permission table 00769 // 00770 00771 MiProtectFor4kPage (StartingAddressFor4k, 00772 CapturedRegionSizeFor4k, 00773 OriginalProtectionMask, 00774 ALT_CHANGE, 00775 Process); 00776 00777 LOCK_WS_UNSAFE (Process); 00778 } 00779 #endif 00780 00781 // 00782 // The address range is committed, change the protection. 00783 // 00784 00785 PointerPpe = MiGetPpeAddress (StartingAddress); 00786 PointerPde = MiGetPdeAddress (StartingAddress); 00787 PointerPte = MiGetPteAddress (StartingAddress); 00788 LastPte = MiGetPteAddress (EndingAddress); 00789 00790 #if defined (_WIN64) 00791 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 00792 if (PointerPde->u.Long == 0) { 00793 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 00794 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 00795 } 00796 #endif 00797 00798 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE); 00799 00800 // 00801 // Capture the protection for the first page. 00802 // 00803 00804 if (PointerPte->u.Long != 0) { 00805 00806 CapturedOldProtect = MiGetPageProtection (PointerPte, Process); 00807 00808 // 00809 // Make sure the page directory & table pages are still resident. 00810 // 00811 00812 #if defined (_WIN64) 00813 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 00814 if (PointerPde->u.Long == 0) { 00815 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 00816 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 00817 } 00818 #endif 00819 00820 (VOID) MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE); 00821 00822 } else { 00823 00824 // 00825 // Get the protection from the VAD. 00826 // 00827 00828 CapturedOldProtect = 00829 MI_CONVERT_FROM_PTE_PROTECTION(FoundVad->u.VadFlags.Protection); 00830 } 00831 00832 // 00833 // For all the PTEs in the specified address range, set the 00834 // protection depending on the state of the PTE. 00835 // 00836 00837 while (PointerPte <= LastPte) { 00838 00839 if (MiIsPteOnPdeBoundary (PointerPte)) { 00840 00841 PointerPde = MiGetPteAddress (PointerPte); 00842 PointerPpe = MiGetPdeAddress (PointerPte); 00843 00844 #if defined (_WIN64) 00845 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 00846 if (PointerPde->u.Long == 0) { 00847 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 00848 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 00849 } 00850 #endif 00851 00852 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE); 00853 } 00854 00855 PteContents = *PointerPte; 00856 00857 if (PteContents.u.Long == 0) { 00858 00859 // 00860 // Increment the count of non-zero page table entries 00861 // for this page table and the number of private pages 00862 // for the process. The protection will be set as 00863 // if the PTE was demand zero. 00864 // 00865 00866 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (MiGetVirtualAddressMappedByPte (PointerPte)); 00867 00868 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle); 00869 } 00870 00871 if (PteContents.u.Hard.Valid == 1) { 00872 00873 // 00874 // Set the protection into both the PTE and the original PTE 00875 // in the PFN database. 00876 // 00877 00878 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 00879 00880 if (Pfn1->u3.e1.PrototypePte == 1) { 00881 00882 // 00883 // This PTE refers to a fork prototype PTE, make it 00884 // private. 00885 // 00886 00887 MiCopyOnWrite (MiGetVirtualAddressMappedByPte (PointerPte), 00888 PointerPte); 00889 00890 // 00891 // This may have released the working set mutex and 00892 // the page directory and table pages may no longer be 00893 // in memory. 00894 // 00895 00896 do { 00897 00898 (VOID)MiDoesPpeExistAndMakeValid (MiGetPteAddress (PointerPde), 00899 Process, 00900 FALSE, 00901 &Waited); 00902 00903 Waited = 0; 00904 00905 (VOID)MiDoesPdeExistAndMakeValid (PointerPde, 00906 Process, 00907 FALSE, 00908 &Waited); 00909 00910 } while (Waited != 0); 00911 00912 // 00913 // Do the loop again for the same PTE. 00914 // 00915 00916 continue; 00917 } else { 00918 00919 // 00920 // The PTE is a private page which is valid, if the 00921 // specified protection is no-access or guard page 00922 // remove the PTE from the working set. 00923 // 00924 00925 if ((NewProtect & PAGE_NOACCESS) || 00926 (NewProtect & PAGE_GUARD)) { 00927 00928 // 00929 // Remove the page from the working set. 00930 // 00931 00932 Locked = MiRemovePageFromWorkingSet (PointerPte, 00933 Pfn1, 00934 &Process->Vm); 00935 00936 00937 continue; 00938 } else { 00939 00940 #if PFN_CONSISTENCY 00941 MiSetOriginalPteProtection (Pfn1, ProtectionMask); 00942 #else 00943 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask; 00944 #endif 00945 MI_MAKE_VALID_PTE (TempPte, 00946 PointerPte->u.Hard.PageFrameNumber, 00947 ProtectionMask, 00948 PointerPte); 00949 00950 WorkingSetIndex = MI_GET_WORKING_SET_FROM_PTE (&PteContents); 00951 MI_SET_PTE_IN_WORKING_SET (&TempPte, WorkingSetIndex); 00952 00953 // 00954 // Flush the TB as we have changed the protection 00955 // of a valid PTE. 00956 // 00957 00958 PreviousPte.u.Flush = MiFlushTbAndCapture (PointerPte, 00959 TempPte.u.Flush, 00960 Pfn1); 00961 } 00962 } 00963 } else { 00964 00965 if (PteContents.u.Soft.Prototype == 1) { 00966 00967 // 00968 // This PTE refers to a fork prototype PTE, make the 00969 // page private. This is accomplished by releasing 00970 // the working set mutex, reading the page thereby 00971 // causing a fault, and re-executing the loop, hopefully, 00972 // this time, we'll find the page present and will 00973 // turn it into a private page. 00974 // 00975 // Note, that a TRY is used to catch guard 00976 // page exceptions and no-access exceptions. 00977 // 00978 00979 Va = MiGetVirtualAddressMappedByPte (PointerPte); 00980 00981 DoAgain = TRUE; 00982 00983 while (PteContents.u.Hard.Valid == 0) { 00984 00985 UNLOCK_WS_UNSAFE (Process); 00986 00987 try { 00988 00989 *(volatile ULONG *)Va; 00990 } except (EXCEPTION_EXECUTE_HANDLER) { 00991 00992 if (GetExceptionCode() == 00993 STATUS_ACCESS_VIOLATION) { 00994 00995 // 00996 // The prototype PTE must be noaccess. 00997 // 00998 00999 DoAgain = MiChangeNoAccessForkPte (PointerPte, 01000 ProtectionMask); 01001 } else if (GetExceptionCode() == 01002 STATUS_IN_PAGE_ERROR) { 01003 // 01004 // Ignore this page and go onto the next one. 01005 // 01006 01007 PointerPte += 1; 01008 DoAgain = TRUE; 01009 01010 if (PointerPte > LastPte) { 01011 LOCK_WS_UNSAFE (Process); 01012 break; 01013 } 01014 } 01015 } 01016 01017 LOCK_WS_UNSAFE (Process); 01018 01019 do { 01020 01021 (VOID)MiDoesPpeExistAndMakeValid (MiGetPteAddress (PointerPde), 01022 Process, 01023 FALSE, 01024 &Waited); 01025 01026 Waited = 0; 01027 01028 (VOID)MiDoesPdeExistAndMakeValid (PointerPde, 01029 Process, 01030 FALSE, 01031 &Waited); 01032 01033 } while (Waited != 0); 01034 01035 PteContents = *(volatile MMPTE *)PointerPte; 01036 } 01037 01038 if (DoAgain) { 01039 continue; 01040 } 01041 01042 } else { 01043 01044 if (PteContents.u.Soft.Transition == 1) { 01045 01046 if (MiSetProtectionOnTransitionPte ( 01047 PointerPte, 01048 ProtectionMask)) { 01049 continue; 01050 } 01051 } else { 01052 01053 // 01054 // Must be page file space or demand zero. 01055 // 01056 01057 PointerPte->u.Soft.Protection = ProtectionMask; 01058 ASSERT (PointerPte->u.Long != 0); 01059 } 01060 } 01061 } 01062 PointerPte += 1; 01063 } //end while 01064 } 01065 01066 // 01067 // Common completion code. 01068 // 01069 01070 #if defined(_MIALT4K_) 01071 01072 if (EmulationFor4kPage == TRUE) { 01073 01074 StartingAddress = StartingAddressFor4k; 01075 01076 EndingAddress = EndingAddressFor4k; 01077 01078 if (CapturedOldProtectFor4k != 0) { 01079 01080 // 01081 // change CapturedOldProtect when CapturedOldProtectFor4k 01082 // contains the true protection for the 4k page 01083 // 01084 01085 CapturedOldProtect = CapturedOldProtectFor4k; 01086 01087 } 01088 } 01089 #endif 01090 01091 *RegionSize = (PCHAR)EndingAddress - (PCHAR)StartingAddress + 1L; 01092 *BaseAddress = StartingAddress; 01093 *LastProtect = CapturedOldProtect; 01094 01095 if (Locked) { 01096 Status = STATUS_WAS_UNLOCKED; 01097 } else { 01098 Status = STATUS_SUCCESS; 01099 } 01100 01101 ErrorFound: 01102 UNLOCK_WS_AND_ADDRESS_SPACE (Process); 01103 01104 ErrorFoundNoWs: 01105 return Status; 01106 }

ULONG MiSetProtectionOnSection IN PEPROCESS  Process,
IN PMMVAD  FoundVad,
IN PVOID  StartingAddress,
IN PVOID  EndingAddress,
IN ULONG  NewProtect,
OUT PULONG  CapturedOldProtect,
IN ULONG  DontCharge
 

Definition at line 1110 of file protect.c.

References ASSERT, EXCEPTION_EXECUTE_HANDLER, ExRaiseStatus(), FALSE, Index, LOCK_WS_UNSAFE, MI_CONVERT_FROM_PTE_PROTECTION, MI_GET_USED_PTES_HANDLE, MI_GET_WORKING_SET_FROM_PTE, MI_INCREMENT_USED_PTES_BY_HANDLE, MI_IS_PTE_PROTECTION_COPY_WRITE, MI_MAKE_VALID_PTE, MI_PFN_ELEMENT, MI_PTE_LOOKUP_NEEDED, MI_SET_PTE_IN_WORKING_SET, MI_VA_TO_VPN, MI_WRITE_INVALID_PTE, MiCaptureSystemPte(), MiChangeNoAccessForkPte(), MiChargeCommitment(), MiChargePageFileQuota(), MiCopyOnWrite(), MiDoesPdeExistAndMakeValid(), MiDoesPpeExistAndMakeValid, MiFlushTbAndCapture(), MiGetPageProtection(), MiGetPdeAddress, MiGetPpeAddress, MiGetProtoPteAddress, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiIsPteOnPdeBoundary, MiLocateWsle(), MiMakePdeExistAndMakeValid(), MiMakePpeExistAndMakeValid, MiMakeProtectionMask(), MiPteToProto, MiRemovePageFromWorkingSet(), MiReturnCommitment(), MiReturnPageFileQuota(), MiSetProtectionOnTransitionPte(), MM_COPY_ON_WRITE_MASK, MM_DBG_COMMIT_RETURN_PROTECTION, MM_DBG_COMMIT_SET_PROTECTION, MM_PROTECTION_COPY_MASK, MM_TRACK_COMMIT, MmWorkingSetList, MmWsle, NTSTATUS(), NULL, _MMPFN::OriginalPte, PAGED_CODE, PrototypePte, PS_JOB_STATUS_REPORT_COMMIT_CHANGES, PsChangeJobMemoryUsage(), PsReportProcessMemoryLimitViolation(), _MMPFN::PteAddress, TRUE, _MMPTE::u, _MMWSLE::u1, _MMPFN::u1, _MMPFN::u3, UNLOCK_WS_UNSAFE, and VOID().

Referenced by MiProtectVirtualMemory(), and NtAllocateVirtualMemory().

01122 : 01123 01124 This routine changes the protection on a region of committed pages 01125 within the virtual address space of the subject process. Setting 01126 the protection on a range of pages causes the old protection to be 01127 replaced by the specified protection value. 01128 01129 Arguments: 01130 01131 Process - Supplies a pointer to the current process. 01132 01133 FoundVad - Supplies a pointer to the VAD containing the range to protect. 01134 01135 StartingAddress - Supplies the starting address to protect. 01136 01137 EndingAddress - Supplies the ending address to protect. 01138 01139 NewProtect - Supplies the new protection to set. 01140 01141 CapturedOldProtect - Supplies the address of a kernel owned pointer to 01142 store (without probing) the old protection into. 01143 01144 DontCharge - Supplies TRUE if no quota or commitment should be charged. 01145 01146 Return Value: 01147 01148 Returns TRUE if a locked page was removed from the working set (protection 01149 was guard page or no-access, FALSE otherwise. 01150 01151 Exceptions raised for page file quota or commitment violations. 01152 01153 Environment: 01154 01155 Kernel mode, working set mutex held, address creation mutex held 01156 APCs disabled. 01157 01158 --*/ 01159 01160 { 01161 PMMPTE PointerPte; 01162 PMMPTE LastPte; 01163 PMMPTE PointerPde; 01164 PMMPTE PointerPpe; 01165 PMMPTE PointerProtoPte; 01166 PMMPFN Pfn1; 01167 MMPTE TempPte; 01168 MMPTE PreviousPte; 01169 ULONG Locked; 01170 ULONG ProtectionMask; 01171 ULONG ProtectionMaskNotCopy; 01172 ULONG NewProtectionMask; 01173 MMPTE PteContents; 01174 ULONG Index; 01175 PULONG Va; 01176 ULONG WriteCopy; 01177 ULONG DoAgain; 01178 ULONG Waited; 01179 SIZE_T QuotaCharge; 01180 PVOID UsedPageTableHandle; 01181 PVOID UsedPageDirectoryHandle; 01182 ULONG WorkingSetIndex; 01183 01184 PAGED_CODE(); 01185 01186 Locked = FALSE; 01187 WriteCopy = FALSE; 01188 QuotaCharge = 0; 01189 01190 // 01191 // Make the protection field. 01192 // 01193 01194 ASSERT (FoundVad->u.VadFlags.PrivateMemory == 0); 01195 01196 if ((FoundVad->u.VadFlags.ImageMap == 1) || 01197 (FoundVad->u2.VadFlags2.CopyOnWrite == 1)) { 01198 01199 if (NewProtect & PAGE_READWRITE) { 01200 NewProtect &= ~PAGE_READWRITE; 01201 NewProtect |= PAGE_WRITECOPY; 01202 } 01203 01204 if (NewProtect & PAGE_EXECUTE_READWRITE) { 01205 NewProtect &= ~PAGE_EXECUTE_READWRITE; 01206 NewProtect |= PAGE_EXECUTE_WRITECOPY; 01207 } 01208 } 01209 01210 ProtectionMask = MiMakeProtectionMask (NewProtect); 01211 01212 // 01213 // Determine if copy on write is being set. 01214 // 01215 01216 ProtectionMaskNotCopy = ProtectionMask; 01217 if ((ProtectionMask & MM_COPY_ON_WRITE_MASK) == MM_COPY_ON_WRITE_MASK) { 01218 WriteCopy = TRUE; 01219 ProtectionMaskNotCopy &= ~MM_PROTECTION_COPY_MASK; 01220 } 01221 01222 #if defined(_MIALT4K_) 01223 01224 if ((Process->Wow64Process != NULL) && 01225 (FoundVad->u.VadFlags.ImageMap == 0) && 01226 (FoundVad->u2.VadFlags2.CopyOnWrite == 0) && 01227 (WriteCopy)) { 01228 01229 NTSTATUS status; 01230 01231 status = MiSetCopyPagesFor4kPage(Process, 01232 &FoundVad, 01233 &StartingAddress, 01234 &EndingAddress, 01235 ProtectionMask); 01236 01237 if (status != STATUS_SUCCESS) { 01238 ExRaiseStatus (status); 01239 } 01240 01241 } 01242 01243 #endif 01244 01245 PointerPpe = MiGetPpeAddress (StartingAddress); 01246 PointerPde = MiGetPdeAddress (StartingAddress); 01247 PointerPte = MiGetPteAddress (StartingAddress); 01248 LastPte = MiGetPteAddress (EndingAddress); 01249 01250 #if defined (_WIN64) 01251 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 01252 if (PointerPde->u.Long == 0) { 01253 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 01254 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 01255 } 01256 #endif 01257 01258 MiMakePdeExistAndMakeValid(PointerPde, Process, FALSE); 01259 01260 // 01261 // Capture the protection for the first page. 01262 // 01263 01264 if (PointerPte->u.Long != 0) { 01265 01266 *CapturedOldProtect = MiGetPageProtection (PointerPte, Process); 01267 01268 // 01269 // Make sure the Page table page is still resident. 01270 // 01271 01272 PointerPpe = MiGetPteAddress (PointerPde); 01273 01274 do { 01275 01276 (VOID)MiDoesPpeExistAndMakeValid (PointerPpe, Process, FALSE, &Waited); 01277 Waited = 0; 01278 01279 (VOID)MiDoesPdeExistAndMakeValid (PointerPde, Process, FALSE, &Waited); 01280 } while (Waited != 0); 01281 01282 } else { 01283 01284 // 01285 // Get the protection from the VAD, unless image file. 01286 // 01287 01288 if (FoundVad->u.VadFlags.ImageMap == 0) { 01289 01290 // 01291 // This is not an image file, the protection is in the VAD. 01292 // 01293 01294 *CapturedOldProtect = 01295 MI_CONVERT_FROM_PTE_PROTECTION(FoundVad->u.VadFlags.Protection); 01296 } else { 01297 01298 // 01299 // This is an image file, the protection is in the 01300 // prototype PTE. 01301 // 01302 01303 PointerProtoPte = MiGetProtoPteAddress (FoundVad, 01304 MI_VA_TO_VPN ( 01305 MiGetVirtualAddressMappedByPte (PointerPte))); 01306 01307 TempPte = MiCaptureSystemPte (PointerProtoPte, Process); 01308 01309 *CapturedOldProtect = MiGetPageProtection (&TempPte, 01310 Process); 01311 01312 // 01313 // Make sure the Page directory and table pages are still resident. 01314 // 01315 01316 PointerPpe = MiGetPteAddress (PointerPde); 01317 01318 do { 01319 01320 (VOID)MiDoesPpeExistAndMakeValid(PointerPpe, Process, FALSE, &Waited); 01321 Waited = 0; 01322 01323 (VOID)MiDoesPdeExistAndMakeValid(PointerPde, Process, FALSE, &Waited); 01324 } while (Waited != 0); 01325 } 01326 } 01327 01328 // 01329 // If the page protection is being change to be copy-on-write, the 01330 // commitment and page file quota for the potentially dirty private pages 01331 // must be calculated and charged. This must be done before any 01332 // protections are changed as the changes cannot be undone. 01333 // 01334 01335 if (WriteCopy) { 01336 01337 // 01338 // Calculate the charges. If the page is shared and not write copy 01339 // it is counted as a charged page. 01340 // 01341 01342 while (PointerPte <= LastPte) { 01343 01344 if (MiIsPteOnPdeBoundary (PointerPte)) { 01345 01346 PointerPde = MiGetPteAddress (PointerPte); 01347 PointerPpe = MiGetPteAddress (PointerPde); 01348 01349 do { 01350 01351 while (!MiDoesPpeExistAndMakeValid(PointerPpe, Process, FALSE, &Waited)) { 01352 01353 // 01354 // No PPE exists for this address. Therefore 01355 // all the PTEs are shared and not copy on write. 01356 // go to the next PPE. 01357 // 01358 01359 PointerPpe += 1; 01360 PointerPde = MiGetVirtualAddressMappedByPte (PointerPpe); 01361 PointerProtoPte = PointerPte; 01362 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 01363 01364 if (PointerPte > LastPte) { 01365 QuotaCharge += 1 + LastPte - PointerProtoPte; 01366 goto Done; 01367 } 01368 QuotaCharge += PointerPte - PointerProtoPte; 01369 } 01370 01371 Waited = 0; 01372 01373 while (!MiDoesPdeExistAndMakeValid(PointerPde, Process, FALSE, &Waited)) { 01374 01375 // 01376 // No PDE exists for this address. Therefore 01377 // all the PTEs are shared and not copy on write. 01378 // go to the next PDE. 01379 // 01380 01381 PointerPde += 1; 01382 PointerProtoPte = PointerPte; 01383 PointerPpe = MiGetPteAddress (PointerPde); 01384 PointerPte = MiGetVirtualAddressMappedByPte (PointerPde); 01385 01386 if (PointerPte > LastPte) { 01387 QuotaCharge += 1 + LastPte - PointerProtoPte; 01388 goto Done; 01389 } 01390 QuotaCharge += PointerPte - PointerProtoPte; 01391 #if defined (_WIN64) 01392 if (MiIsPteOnPdeBoundary (PointerPde)) { 01393 Waited = 1; 01394 break; 01395 } 01396 #endif 01397 } 01398 } while (Waited != 0); 01399 } 01400 01401 PteContents = *PointerPte; 01402 01403 if (PteContents.u.Long == 0) { 01404 01405 // 01406 // The PTE has not been evaluated, assume copy on write. 01407 // 01408 01409 QuotaCharge += 1; 01410 01411 } else if ((PteContents.u.Hard.Valid == 1) && 01412 (PteContents.u.Hard.CopyOnWrite == 0)) { 01413 01414 // 01415 // See if this is a prototype PTE, if so charge it. 01416 // 01417 01418 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 01419 01420 if (Pfn1->u3.e1.PrototypePte == 1) { 01421 QuotaCharge += 1; 01422 } 01423 } else { 01424 01425 if (PteContents.u.Soft.Prototype == 1) { 01426 01427 // 01428 // This is a prototype PTE. Charge if it is not 01429 // in copy on write format. 01430 // 01431 01432 if (PteContents.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED) { 01433 01434 // 01435 // Page protection is within the PTE. 01436 // 01437 01438 if (!MI_IS_PTE_PROTECTION_COPY_WRITE(PteContents.u.Soft.Protection)) { 01439 QuotaCharge += 1; 01440 } 01441 } else { 01442 01443 // 01444 // The PTE references the prototype directly, therefore 01445 // it can't be copy on write. Charge. 01446 // 01447 01448 QuotaCharge += 1; 01449 } 01450 } 01451 } 01452 PointerPte += 1; 01453 } 01454 01455 Done: 01456 NOTHING; 01457 01458 // 01459 // Charge for the quota. 01460 // 01461 01462 if (!DontCharge) { 01463 MiChargePageFileQuota (QuotaCharge, Process); 01464 01465 if (Process->CommitChargeLimit) { 01466 if (Process->CommitCharge + QuotaCharge > Process->CommitChargeLimit) { 01467 MiReturnPageFileQuota (QuotaCharge, Process); 01468 if (Process->Job) { 01469 PsReportProcessMemoryLimitViolation (); 01470 } 01471 ExRaiseStatus (STATUS_COMMITMENT_LIMIT); 01472 } 01473 } 01474 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 01475 if (PsChangeJobMemoryUsage(QuotaCharge) == FALSE) { 01476 MiReturnPageFileQuota (QuotaCharge, Process); 01477 ExRaiseStatus (STATUS_COMMITMENT_LIMIT); 01478 } 01479 } 01480 01481 if (MiChargeCommitment (QuotaCharge, Process) == FALSE) { 01482 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 01483 01484 // 01485 // Temporarily up the process commit charge as the 01486 // job code will be referencing it as though everything 01487 // has succeeded. 01488 // 01489 01490 Process->CommitCharge += QuotaCharge; 01491 PsChangeJobMemoryUsage(-(SSIZE_T)QuotaCharge); 01492 Process->CommitCharge -= QuotaCharge; 01493 } 01494 MiReturnPageFileQuota (QuotaCharge, Process); 01495 ExRaiseStatus STATUS_COMMITMENT_LIMIT; 01496 } 01497 01498 // 01499 // Add the quota into the charge to the VAD. 01500 // 01501 01502 MM_TRACK_COMMIT (MM_DBG_COMMIT_SET_PROTECTION, QuotaCharge); 01503 FoundVad->u.VadFlags.CommitCharge += QuotaCharge; 01504 Process->CommitCharge += QuotaCharge; 01505 if (Process->CommitCharge > Process->CommitChargePeak) { 01506 Process->CommitChargePeak = Process->CommitCharge; 01507 } 01508 } 01509 } 01510 01511 // 01512 // For all the PTEs in the specified address range, set the 01513 // protection depending on the state of the PTE. 01514 // 01515 01516 // 01517 // If the PTE was copy on write (but not written) and the 01518 // new protection is NOT copy-on-write, return page file quota 01519 // and commitment. 01520 // 01521 01522 PointerPpe = MiGetPpeAddress (StartingAddress); 01523 PointerPde = MiGetPdeAddress (StartingAddress); 01524 PointerPte = MiGetPteAddress (StartingAddress); 01525 01526 do { 01527 01528 MiDoesPpeExistAndMakeValid (PointerPpe, Process, FALSE, &Waited); 01529 01530 Waited = 0; 01531 01532 MiDoesPdeExistAndMakeValid (PointerPde, Process, FALSE, &Waited); 01533 01534 } while (Waited != 0); 01535 01536 QuotaCharge = 0; 01537 01538 while (PointerPte <= LastPte) { 01539 01540 if (MiIsPteOnPdeBoundary (PointerPte)) { 01541 PointerPde = MiGetPteAddress (PointerPte); 01542 PointerPpe = MiGetPdeAddress (PointerPte); 01543 01544 #if defined (_WIN64) 01545 MiMakePpeExistAndMakeValid (PointerPpe, Process, FALSE); 01546 if (PointerPde->u.Long == 0) { 01547 UsedPageDirectoryHandle = MI_GET_USED_PTES_HANDLE (PointerPte); 01548 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageDirectoryHandle); 01549 } 01550 #endif 01551 01552 MiMakePdeExistAndMakeValid (PointerPde, Process, FALSE); 01553 } 01554 01555 PteContents = *PointerPte; 01556 01557 if (PteContents.u.Long == 0) { 01558 01559 // 01560 // The PTE is zero, set it into prototype PTE format 01561 // with the protection in the prototype PTE. 01562 // 01563 01564 TempPte = PrototypePte; 01565 TempPte.u.Soft.Protection = ProtectionMask; 01566 MI_WRITE_INVALID_PTE (PointerPte, TempPte); 01567 01568 // 01569 // Increment the count of non-zero page table entries 01570 // for this page table and the number of private pages 01571 // for the process. 01572 // 01573 01574 UsedPageTableHandle = MI_GET_USED_PTES_HANDLE (MiGetVirtualAddressMappedByPte (PointerPte)); 01575 01576 MI_INCREMENT_USED_PTES_BY_HANDLE (UsedPageTableHandle); 01577 01578 } else if (PteContents.u.Hard.Valid == 1) { 01579 01580 // 01581 // Set the protection into both the PTE and the original PTE 01582 // in the PFN database for private pages only. 01583 // 01584 01585 NewProtectionMask = ProtectionMask; 01586 01587 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 01588 01589 if ((NewProtect & PAGE_NOACCESS) || 01590 (NewProtect & PAGE_GUARD)) { 01591 01592 Locked = MiRemovePageFromWorkingSet (PointerPte, 01593 Pfn1, 01594 &Process->Vm ); 01595 continue; 01596 01597 } else { 01598 01599 if (Pfn1->u3.e1.PrototypePte == 1) { 01600 01601 // 01602 // The true protection may be in the WSLE, locate 01603 // the WSLE. 01604 // 01605 01606 Va = (PULONG)MiGetVirtualAddressMappedByPte (PointerPte); 01607 Index = MiLocateWsle ((PVOID)Va, MmWorkingSetList, 01608 Pfn1->u1.WsIndex); 01609 01610 // 01611 // Check to see if this is a prototype PTE. This 01612 // is done by comparing the PTE address in the 01613 // PFN database to the PTE address indicated by the 01614 // VAD. If they are not equal, this is a prototype 01615 // PTE. 01616 // 01617 01618 if (Pfn1->PteAddress != 01619 MiGetProtoPteAddress (FoundVad, 01620 MI_VA_TO_VPN ((PVOID)Va))) { 01621 01622 // 01623 // This PTE refers to a fork prototype PTE, make it 01624 // private. 01625 // 01626 01627 MiCopyOnWrite ((PVOID)Va, PointerPte); 01628 01629 if (WriteCopy) { 01630 QuotaCharge += 1; 01631 } 01632 01633 // 01634 // This may have released the working set mutex and 01635 // the page table page may no longer be in memory. 01636 // 01637 01638 PointerPpe = MiGetPteAddress (PointerPde); 01639 01640 do { 01641 01642 (VOID)MiDoesPpeExistAndMakeValid (PointerPpe, 01643 Process, 01644 FALSE, 01645 &Waited); 01646 01647 Waited = 0; 01648 01649 (VOID)MiDoesPdeExistAndMakeValid (PointerPde, 01650 Process, 01651 FALSE, 01652 &Waited); 01653 01654 } while (Waited != 0); 01655 01656 // 01657 // Do the loop again. 01658 // 01659 01660 continue; 01661 01662 } else { 01663 01664 // 01665 // Update the protection field in the WSLE and 01666 // the PTE. 01667 // 01668 // 01669 // If the PTE is copy on write uncharge the 01670 // previously charged quota. 01671 // 01672 01673 if ((!WriteCopy) && (PteContents.u.Hard.CopyOnWrite == 1)) { 01674 QuotaCharge += 1; 01675 } 01676 01677 MmWsle[Index].u1.e1.Protection = ProtectionMask; 01678 MmWsle[Index].u1.e1.SameProtectAsProto = 0; 01679 } 01680 01681 } else { 01682 01683 // 01684 // Page is private (copy on written), protection mask 01685 // is stored in the original pte field. 01686 // 01687 01688 #if PFN_CONSISTENCY 01689 MiSetOriginalPteProtection (Pfn1, ProtectionMaskNotCopy); 01690 #else 01691 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMaskNotCopy; 01692 #endif 01693 NewProtectionMask = ProtectionMaskNotCopy; 01694 } 01695 01696 MI_MAKE_VALID_PTE (TempPte, 01697 PteContents.u.Hard.PageFrameNumber, 01698 NewProtectionMask, 01699 PointerPte); 01700 01701 WorkingSetIndex = MI_GET_WORKING_SET_FROM_PTE (&PteContents); 01702 01703 MI_SET_PTE_IN_WORKING_SET (&TempPte, WorkingSetIndex); 01704 } 01705 01706 // 01707 // Flush the TB as we have changed the protection 01708 // of a valid PTE. 01709 // 01710 01711 PreviousPte.u.Flush = MiFlushTbAndCapture (PointerPte, 01712 TempPte.u.Flush, 01713 Pfn1); 01714 } else { 01715 01716 if (PteContents.u.Soft.Prototype == 1) { 01717 01718 // 01719 // The PTE is in prototype PTE format. 01720 // 01721 01722 // 01723 // Is it a fork prototype PTE? 01724 // 01725 01726 Va = (PULONG)MiGetVirtualAddressMappedByPte (PointerPte); 01727 01728 if ((PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED) && 01729 (MiPteToProto (PointerPte) != 01730 MiGetProtoPteAddress (FoundVad, 01731 MI_VA_TO_VPN ((PVOID)Va)))) { 01732 01733 // 01734 // This PTE refers to a fork prototype PTE, make the 01735 // page private. This is accomplished by releasing 01736 // the working set mutex, reading the page thereby 01737 // causing a fault, and re-executing the loop, hopefully, 01738 // this time, we'll find the page present and will 01739 // turn it into a private page. 01740 // 01741 // Note, that page with prototype = 1 cannot be 01742 // no-access. 01743 // 01744 01745 DoAgain = TRUE; 01746 01747 while (PteContents.u.Hard.Valid == 0) { 01748 01749 UNLOCK_WS_UNSAFE (Process); 01750 01751 try { 01752 01753 *(volatile ULONG *)Va; 01754 } except (EXCEPTION_EXECUTE_HANDLER) { 01755 01756 if (GetExceptionCode() != 01757 STATUS_GUARD_PAGE_VIOLATION) { 01758 01759 // 01760 // The prototype PTE must be noaccess. 01761 // 01762 01763 DoAgain = MiChangeNoAccessForkPte (PointerPte, 01764 ProtectionMask); 01765 } 01766 } 01767 01768 PointerPpe = MiGetPteAddress (PointerPde); 01769 01770 LOCK_WS_UNSAFE (Process); 01771 01772 do { 01773 01774 (VOID)MiDoesPpeExistAndMakeValid (PointerPpe, 01775 Process, 01776 FALSE, 01777 &Waited); 01778 01779 Waited = 0; 01780 01781 (VOID)MiDoesPdeExistAndMakeValid (PointerPde, 01782 Process, 01783 FALSE, 01784 &Waited); 01785 01786 } while (Waited != 0); 01787 01788 PteContents = *(volatile MMPTE *)PointerPte; 01789 } 01790 01791 if (DoAgain) { 01792 continue; 01793 } 01794 01795 } else { 01796 01797 // 01798 // If the new protection is not write-copy, the PTE 01799 // protection is not in the prototype PTE (can't be 01800 // write copy for sections), and the protection in 01801 // the PTE is write-copy, release the page file 01802 // quota and commitment for this page. 01803 // 01804 01805 if ((!WriteCopy) && 01806 (PteContents.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)) { 01807 if (MI_IS_PTE_PROTECTION_COPY_WRITE(PteContents.u.Soft.Protection)) { 01808 QuotaCharge += 1; 01809 } 01810 01811 } 01812 01813 // 01814 // The PTE is a prototype PTE. Make the high part 01815 // of the PTE indicate that the protection field 01816 // is in the PTE itself. 01817 // 01818 01819 MI_WRITE_INVALID_PTE (PointerPte, PrototypePte); 01820 PointerPte->u.Soft.Protection = ProtectionMask; 01821 } 01822 01823 } else { 01824 01825 if (PteContents.u.Soft.Transition == 1) { 01826 01827 // 01828 // This is a transition PTE. (Page is private) 01829 // 01830 01831 if (MiSetProtectionOnTransitionPte ( 01832 PointerPte, 01833 ProtectionMaskNotCopy)) { 01834 continue; 01835 } 01836 01837 } else { 01838 01839 // 01840 // Must be page file space or demand zero. 01841 // 01842 01843 PointerPte->u.Soft.Protection = ProtectionMaskNotCopy; 01844 } 01845 } 01846 } 01847 01848 PointerPte += 1; 01849 } 01850 01851 // 01852 // Return the quota charge and the commitment, if any. 01853 // 01854 01855 if ((QuotaCharge > 0) && (!DontCharge)) { 01856 01857 MiReturnCommitment (QuotaCharge); 01858 MM_TRACK_COMMIT (MM_DBG_COMMIT_RETURN_PROTECTION, QuotaCharge); 01859 MiReturnPageFileQuota (QuotaCharge, Process); 01860 01861 ASSERT (QuotaCharge <= FoundVad->u.VadFlags.CommitCharge); 01862 01863 FoundVad->u.VadFlags.CommitCharge -= QuotaCharge; 01864 if (Process->JobStatus & PS_JOB_STATUS_REPORT_COMMIT_CHANGES) { 01865 PsChangeJobMemoryUsage(-(SSIZE_T)QuotaCharge); 01866 } 01867 Process->CommitCharge -= QuotaCharge; 01868 } 01869 01870 return Locked; 01871 }

ULONG MiSetProtectionOnTransitionPte IN PMMPTE  PointerPte,
IN ULONG  ProtectionMask
 

Definition at line 2154 of file protect.c.

References FALSE, LOCK_PFN, MI_PFN_ELEMENT, _MMPFN::OriginalPte, TRUE, _MMPTE::u, and UNLOCK_PFN.

02161 { 02162 KIRQL OldIrql; 02163 MMPTE PteContents; 02164 PMMPFN Pfn1; 02165 02166 // 02167 // This is a transition PTE. (Page is private) 02168 // 02169 02170 // 02171 // Need pfn mutex to ensure page doesn't become 02172 // non-transition. 02173 // 02174 02175 LOCK_PFN (OldIrql); 02176 02177 // 02178 // Make sure the page is still a transition page. 02179 // 02180 02181 PteContents = *(volatile MMPTE *)PointerPte; 02182 02183 if ((PteContents.u.Soft.Prototype == 0) && 02184 (PointerPte->u.Soft.Transition == 1)) { 02185 02186 Pfn1 = MI_PFN_ELEMENT ( 02187 PteContents.u.Trans.PageFrameNumber); 02188 02189 Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask; 02190 PointerPte->u.Soft.Protection = ProtectionMask; 02191 UNLOCK_PFN (OldIrql); 02192 return FALSE; 02193 } 02194 02195 // 02196 // Do this loop again for the same PTE. 02197 // 02198 02199 UNLOCK_PFN (OldIrql); 02200 return TRUE; 02201 }

NTSTATUS NtProtectVirtualMemory IN HANDLE  ProcessHandle,
IN OUT PVOID *  BaseAddress,
IN OUT PSIZE_T  RegionSize,
IN ULONG  NewProtect,
OUT PULONG  OldProtect
 

Definition at line 69 of file protect.c.

References DbgPrint, EXCEPTION_EXECUTE_HANDLER, FALSE, KeAttachProcess(), KeDetachProcess(), KernelMode, KPROCESSOR_MODE, MiMakeProtectionMask(), MiProtectVirtualMemory(), MM_DBG_SHOW_NT_CALLS, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PAGED_CODE, ProbeForWritePointer, ProbeForWriteUlong, ProbeForWriteUlong_ptr, PsGetCurrentProcess, PsProcessType, Status, and TRUE.

Referenced by LdrpDphSnapImports(), LdrpSetProtection(), LdrpSnapIAT(), LdrpWalkImportDescriptor(), and main().

00079 : 00080 00081 This routine changes the protection on a region of committed pages 00082 within the virtual address space of the subject process. Setting 00083 the protection on a range of pages causes the old protection to be 00084 replaced by the specified protection value. 00085 00086 Arguments: 00087 00088 ProcessHandle - An open handle to a process object. 00089 00090 BaseAddress - The base address of the region of pages 00091 whose protection is to be changed. This value is 00092 rounded down to the next host page address 00093 boundary. 00094 00095 RegionSize - A pointer to a variable that will receive 00096 the actual size in bytes of the protected region 00097 of pages. The initial value of this argument is 00098 rounded up to the next host page size boundary. 00099 00100 NewProtect - The new protection desired for the 00101 specified region of pages. 00102 00103 Protect Values 00104 00105 PAGE_NOACCESS - No access to the specified region 00106 of pages is allowed. An attempt to read, 00107 write, or execute the specified region 00108 results in an access violation (i.e. a GP 00109 fault). 00110 00111 PAGE_EXECUTE - Execute access to the specified 00112 region of pages is allowed. An attempt to 00113 read or write the specified region results in 00114 an access violation. 00115 00116 PAGE_READONLY - Read only and execute access to the 00117 specified region of pages is allowed. An 00118 attempt to write the specified region results 00119 in an access violation. 00120 00121 PAGE_READWRITE - Read, write, and execute access to 00122 the specified region of pages is allowed. If 00123 write access to the underlying section is 00124 allowed, then a single copy of the pages are 00125 shared. Otherwise the pages are shared read 00126 only/copy on write. 00127 00128 PAGE_GUARD - Read, write, and execute access to the 00129 specified region of pages is allowed, 00130 however, access to the region causes a "guard 00131 region entered" condition to be raised in the 00132 subject process. If write access to the 00133 underlying section is allowed, then a single 00134 copy of the pages are shared. Otherwise the 00135 pages are shared read only/copy on write. 00136 00137 PAGE_NOCACHE - The page should be treated as uncached. 00138 This is only valid for non-shared pages. 00139 00140 00141 OldProtect - A pointer to a variable that will receive 00142 the old protection of the first page within the 00143 specified region of pages. 00144 00145 Return Value: 00146 00147 Returns the status 00148 00149 TBS 00150 00151 00152 Environment: 00153 00154 Kernel mode. 00155 00156 --*/ 00157 00158 00159 { 00160 // 00161 // note - special treatment for the following cases... 00162 // 00163 // if a page is locked in the working set (memory?) and the 00164 // protection is changed to no access, the page should be 00165 // removed from the working set... valid pages can't be no access. 00166 // 00167 // if page is going to be read only or no access? and is demand 00168 // zero, make sure it is changed to a page of zeroes. 00169 // 00170 // update the vm spec to explain locked pages are unlocked when 00171 // freed or protection is changed to no-access (this may be a nasty 00172 // problem if we don't want to do this!! 00173 // 00174 00175 PEPROCESS Process; 00176 KPROCESSOR_MODE PreviousMode; 00177 NTSTATUS Status; 00178 ULONG Attached = FALSE; 00179 PVOID CapturedBase; 00180 SIZE_T CapturedRegionSize; 00181 ULONG ProtectionMask; 00182 00183 ULONG LastProtect; 00184 00185 PAGED_CODE(); 00186 00187 // 00188 // Check the protection field. This could raise an exception. 00189 // 00190 00191 try { 00192 ProtectionMask = MiMakeProtectionMask (NewProtect); 00193 } except (EXCEPTION_EXECUTE_HANDLER) { 00194 return GetExceptionCode(); 00195 } 00196 00197 PreviousMode = KeGetPreviousMode(); 00198 00199 if (PreviousMode != KernelMode) { 00200 00201 // 00202 // Capture the region size and base address under an exception handler. 00203 // 00204 00205 try { 00206 00207 ProbeForWritePointer (BaseAddress); 00208 ProbeForWriteUlong_ptr (RegionSize); 00209 ProbeForWriteUlong (OldProtect); 00210 00211 // 00212 // Capture the region size and base address. 00213 // 00214 00215 CapturedBase = *BaseAddress; 00216 CapturedRegionSize = *RegionSize; 00217 00218 } except (EXCEPTION_EXECUTE_HANDLER) { 00219 00220 // 00221 // If an exception occurs during the probe or capture 00222 // of the initial values, then handle the exception and 00223 // return the exception code as the status value. 00224 // 00225 00226 return GetExceptionCode(); 00227 } 00228 00229 } else { 00230 00231 // 00232 // Capture the region size and base address. 00233 // 00234 00235 CapturedRegionSize = *RegionSize; 00236 CapturedBase = *BaseAddress; 00237 } 00238 00239 #if DBG 00240 if (MmDebug & MM_DBG_SHOW_NT_CALLS) { 00241 if ( !MmWatchProcess ) { 00242 DbgPrint("protectvm process handle %lx base address %lx size %lx protect %lx\n", 00243 ProcessHandle, CapturedBase, CapturedRegionSize, NewProtect); 00244 } 00245 } 00246 #endif 00247 00248 // 00249 // Make sure the specified starting and ending addresses are 00250 // within the user part of the virtual address space. 00251 // 00252 00253 if (CapturedBase > MM_HIGHEST_USER_ADDRESS) { 00254 00255 // 00256 // Invalid base address. 00257 // 00258 00259 return STATUS_INVALID_PARAMETER_2; 00260 } 00261 00262 if ((ULONG_PTR)MM_HIGHEST_USER_ADDRESS - (ULONG_PTR)CapturedBase < 00263 CapturedRegionSize) { 00264 00265 // 00266 // Invalid region size; 00267 // 00268 00269 return STATUS_INVALID_PARAMETER_3; 00270 } 00271 00272 if (CapturedRegionSize == 0) { 00273 return STATUS_INVALID_PARAMETER_3; 00274 } 00275 00276 Status = ObReferenceObjectByHandle ( ProcessHandle, 00277 PROCESS_VM_OPERATION, 00278 PsProcessType, 00279 PreviousMode, 00280 (PVOID *)&Process, 00281 NULL ); 00282 00283 if (!NT_SUCCESS(Status)) { 00284 return Status; 00285 } 00286 00287 // 00288 // If the specified process is not the current process, attach 00289 // to the specified process. 00290 // 00291 00292 if (PsGetCurrentProcess() != Process) { 00293 KeAttachProcess (&Process->Pcb); 00294 Attached = TRUE; 00295 } 00296 00297 Status = MiProtectVirtualMemory (Process, 00298 &CapturedBase, 00299 &CapturedRegionSize, 00300 NewProtect, 00301 &LastProtect); 00302 00303 00304 if (Attached) { 00305 KeDetachProcess(); 00306 } 00307 00308 ObDereferenceObject (Process); 00309 00310 // 00311 // Establish an exception handler and write the size and base 00312 // address. 00313 // 00314 00315 try { 00316 00317 // 00318 // Reprobe the addresses as certain architectures (intel 386 for one) 00319 // do not trap kernel writes. This is the one service which allows 00320 // the protection of the page to change between the initial probe 00321 // and the final argument update. 00322 // 00323 00324 if (PreviousMode != KernelMode) { 00325 00326 ProbeForWritePointer (BaseAddress); 00327 ProbeForWriteUlong_ptr (RegionSize); 00328 ProbeForWriteUlong (OldProtect); 00329 } 00330 00331 *RegionSize = CapturedRegionSize; 00332 *BaseAddress = CapturedBase; 00333 *OldProtect = LastProtect; 00334 00335 } except (EXCEPTION_EXECUTE_HANDLER) { 00336 NOTHING; 00337 } 00338 00339 return Status; 00340 }


Variable Documentation

CCHAR MmReadWrite[32]
 

Definition at line 57 of file protect.c.

Referenced by MiAccessCheck(), and MiCheckSecuredVad().


Generated on Sat May 15 19:45:21 2004 for test by doxygen 1.3.7