Bitdefender Hypervisor Memory Introspection
winpfn.c File Reference
#include "winpfn.h"
#include "hook.h"

Go to the source code of this file.

Macros

#define for_each_pfn_lock(_var_name)   list_for_each (gWinPfns, WIN_PFN_LOCK, _var_name)
 Iterates the linked list in gWinPfns. More...
 

Functions

INTSTATUS IntWinPfnIsMmPfnDatabase (QWORD MmPfnDatabase)
 Checks if a a guest virtual address points to MmPfnDatabase. More...
 
static INTSTATUS IntWinPfnModifyRefCount (QWORD PhysicalAddress, BOOLEAN Increment)
 Modifies the in-guest reference count of a physical page. More...
 
static PWIN_PFN_LOCK IntWinPfnFindByGpa (QWORD GpaPage)
 Finds a PFN lock by a guest physical address. More...
 
static PWIN_PFN_LOCK IntWinPfnFindByGva (QWORD GvaPage)
 Finds a PFN lock by a guest virtual address. More...
 
static INTSTATUS IntWinPfnMoveLock (WIN_PFN_LOCK *PfnLock, QWORD NewGpa)
 Moves a lock set for a guest virtual address when the page to which it translates to changes. More...
 
static INTSTATUS IntWinPfnUnlockAddress (QWORD Address, BOOLEAN IsPhysical)
 Unlocks a guest page. More...
 
static INTSTATUS IntWinPfnHandleTranslationChange (WIN_PFN_LOCK *Context, QWORD VirtualAddress, QWORD OldEntry, QWORD NewEntry, QWORD OldPageSize, QWORD NewPageSize)
 Handles translation changes for locked guest virtual pages. More...
 
static INTSTATUS IntWinPfnLockAddress (QWORD Address, BOOLEAN IsPhysical, PWIN_PFN_LOCK *PfnLock)
 Locks a guest page. More...
 
INTSTATUS IntWinPfnLockGva (QWORD Gva, WIN_PFN_LOCK **PfnLock)
 Locks a guest virtual address. More...
 
INTSTATUS IntWinPfnLockGpa (QWORD Gpa, WIN_PFN_LOCK **PfnLock)
 Locks a guest physical address. More...
 
INTSTATUS IntWinPfnRemoveLock (WIN_PFN_LOCK *PfnLock, BOOLEAN Force)
 Removes a PFN lock. More...
 
void IntWinPfnDump (void)
 Prints all the PFN locks. More...
 
void IntWinPfnUnInit (void)
 Uninits the PFN locks. More...
 

Variables

static LIST_HEAD gWinPfns = LIST_HEAD_INIT(gWinPfns)
 The list of locked PFNs. More...
 

Macro Definition Documentation

◆ for_each_pfn_lock

#define for_each_pfn_lock (   _var_name)    list_for_each (gWinPfns, WIN_PFN_LOCK, _var_name)

Iterates the linked list in gWinPfns.

Can be used to safely iterate the PFN list. The current PFN pointed to by _var_name can safely be removed from the list, but note that removing other detours while iterating the list using this macro is not a valid operation and can corrupt the list.

Parameters
[in]_var_nameThe name of the variable in which the WIN_PFN_LOCK pointer will be placed. This variable will be declared by the macro an available only in the context created by the macro.

Definition at line 20 of file winpfn.c.

Referenced by IntWinPfnDump(), IntWinPfnFindByGpa(), IntWinPfnFindByGva(), and IntWinPfnUnInit().

Function Documentation

◆ IntWinPfnDump()

void IntWinPfnDump ( void  )

Prints all the PFN locks.

Definition at line 901 of file winpfn.c.

◆ IntWinPfnFindByGpa()

static PWIN_PFN_LOCK IntWinPfnFindByGpa ( QWORD  GpaPage)
static

Finds a PFN lock by a guest physical address.

Parameters
[in]GpaPageThe page to search by.
Returns
A pointer to the lock for the given page; NULL if no lock exists.

Definition at line 338 of file winpfn.c.

Referenced by IntWinPfnLockAddress(), and IntWinPfnUnlockAddress().

◆ IntWinPfnFindByGva()

static PWIN_PFN_LOCK IntWinPfnFindByGva ( QWORD  GvaPage)
static

Finds a PFN lock by a guest virtual address.

Parameters
[in]GvaPageThe page to search by.
Returns
A pointer to the lock for the given page; NULL if no lock exists.

Definition at line 364 of file winpfn.c.

Referenced by IntWinPfnLockAddress(), and IntWinPfnUnlockAddress().

◆ IntWinPfnHandleTranslationChange()

static INTSTATUS IntWinPfnHandleTranslationChange ( WIN_PFN_LOCK Context,
QWORD  VirtualAddress,
QWORD  OldEntry,
QWORD  NewEntry,
QWORD  OldPageSize,
QWORD  NewPageSize 
)
static

Handles translation changes for locked guest virtual pages.

This is the EPT swap hook set by IntWinPfnLockAddress. Since locks on virtual pages are in fact locks on the physical pages to which they translate to, when the translation changes, we also have to move the lock to the new page. If the new page is a large page, or if the page is swapped out, the in-guest reference counter is decremented. For large pages the swap hook will also be removed, as large pages are not swappable. If the page size remains 4KB, the lock is moved using IntWinPfnMoveLock.

Parameters
[in]ContextThe context set by IntWinPfnLockAddress. This will be the WIN_PFN_LOCK structure for which the hook was placed.
[in]VirtualAddressThe guest virtual address for which the translation changed.
[in]OldEntryThe old page table entry for VirtualAddress.
[in]NewEntryThe new page table entry for VirtualAddress.
[in]OldPageSizeThe old page size. Ignored.
[in]NewPageSizeThe new page size.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 531 of file winpfn.c.

Referenced by IntWinPfnLockAddress().

◆ IntWinPfnIsMmPfnDatabase()

INTSTATUS IntWinPfnIsMmPfnDatabase ( QWORD  MmPfnDatabase)

Checks if a a guest virtual address points to MmPfnDatabase.

Parameters
[in]MmPfnDatabaseGuest virtual address to check.
Return values
INT_STATUS_SUCCESSif the provided address is indeed the MmPfnDataBase.
INT_STATUS_INVALID_OBJECT_TYPEif it is not.

Definition at line 24 of file winpfn.c.

Referenced by IntWinGuestFindKernelObjectsInternal().

◆ IntWinPfnLockAddress()

static INTSTATUS IntWinPfnLockAddress ( QWORD  Address,
BOOLEAN  IsPhysical,
PWIN_PFN_LOCK PfnLock 
)
static

Locks a guest page.

Every IntWinPfnLockAddress call for an address must match a call to this function. If the Introcore reference counter reaches 0, it means that we also have to remove the lock from the guest, but only if it is a physical, not large, page. Also, any resources held by the lock are freed: the swap hook (if it exists) and the lock itself. It will also be removed from the gWinPfns list.

Parameters
[in]AddressAddress to unlock.
[in]IsPhysicalTrue if Address is a guest physical address; False if it is a guest virtual address.
[out]PfnLockOn success, will contain a pointer to the lock. May be NULL.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_2if Address is a guest virtual address and it does not point inside the kernel.
INT_STATUS_NOT_FOUNDif no lock is found for Address.

Definition at line 636 of file winpfn.c.

Referenced by IntWinPfnLockGpa(), and IntWinPfnLockGva().

◆ IntWinPfnLockGpa()

INTSTATUS IntWinPfnLockGpa ( QWORD  Gpa,
WIN_PFN_LOCK **  PfnLock 
)

Locks a guest physical address.

Parameters
[in]GpaGuest physical address to lock.
[out]PfnLockOn success, will contain a pointer to the lock. May be NULL.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 820 of file winpfn.c.

Referenced by IntWinProcLockCr3().

◆ IntWinPfnLockGva()

INTSTATUS IntWinPfnLockGva ( QWORD  Gva,
WIN_PFN_LOCK **  PfnLock 
)

Locks a guest virtual address.

This will actually lock the guest physical address to which Gva translates to, and place a swap hook on Gva page tables. If the page is not currently present, it will be locked when it will be made present.

Parameters
[in]GvaGuest virtual address to lock.
[out]PfnLockOn success, will contain a pointer to the lock. May be NULL.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 799 of file winpfn.c.

◆ IntWinPfnModifyRefCount()

static INTSTATUS IntWinPfnModifyRefCount ( QWORD  PhysicalAddress,
BOOLEAN  Increment 
)
static

Modifies the in-guest reference count of a physical page.

The counter is incremented or decremented with WIN_PFN_INC_VALUE.

When incrementing the counter, if the page is not in the WinPfnModifiedPage, WinPfnActivePage, WinPfnModifiedNowritePage, or WinPfnStandbyPage states the operation is refused.

We do not increment the counter if it the new value would be larger than WIN_PFN_REF_MAX.

When decrementing the counter, we do nothing if the value is already less than WIN_PFN_INC_VALUE.

Parameters
[in]PhysicalAddressPhysical address for which to modify the reference counter.
[in]IncrementTrue to increment the counter, False to decrement it.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_NOT_NEEDED_HINTif the change is not needed.
INT_STATUS_NOT_SUPPORTEDif the page is not in a state that supports the reference counter change.
INT_STATUS_NOT_INITIALIZEDif the PFN entry for this page is not initialized.

Definition at line 197 of file winpfn.c.

Referenced by IntWinPfnHandleTranslationChange(), IntWinPfnLockAddress(), IntWinPfnMoveLock(), IntWinPfnRemoveLock(), and IntWinPfnUnlockAddress().

◆ IntWinPfnMoveLock()

static INTSTATUS IntWinPfnMoveLock ( WIN_PFN_LOCK PfnLock,
QWORD  NewGpa 
)
static

Moves a lock set for a guest virtual address when the page to which it translates to changes.

Since locks on virtual pages are in fact locks on the physical pages to which they translate to, when the translation changes we need to move the lock to the new page. This means that we must unlock the old page and lock the new one.

If the old physical address of the lock is 0 it means that the page is swapped in and we only have to set the lock on the new page.

If the new physical address is 0 it means that the page is swapped out and we only have to remove the lock from the old page.

Parameters
[in,out]PfnLockThe lock that must be moved.
[in]NewGpaThe new guest physical address that will receive the lock.
Returns
INT_STATUS_SUCCESS if successful, or an appropriate INTSTATUS error value.

Definition at line 390 of file winpfn.c.

Referenced by IntWinPfnHandleTranslationChange().

◆ IntWinPfnRemoveLock()

INTSTATUS IntWinPfnRemoveLock ( WIN_PFN_LOCK PfnLock,
BOOLEAN  Force 
)

Removes a PFN lock.

This will decrement the Introcore reference counter and only remove the lock when it reaches 0, unless a forced removal is requested.

Parameters
[in,out]PfnLockLock to remove. The pointer will no longer be valid after this function returns.
[in]ForceTrue to remove the lock even if the reference counter is not 0.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_NOT_NEEDED_HINTif the reference counter has not reached 0 and Force is False.
INT_STATUS_INVALID_PARAMETER_1if PfnLock is NULL.

Definition at line 838 of file winpfn.c.

Referenced by IntWinPfnUnInit(), IntWinProcRemoveProcess(), and IntWinProcUnlockCr3().

◆ IntWinPfnUnInit()

void IntWinPfnUnInit ( void  )

Uninits the PFN locks.

If any locks are still active when this function is called, they will be forcibly removed using IntWinPfnRemoveLock.

Definition at line 922 of file winpfn.c.

Referenced by IntGuestUninit().

◆ IntWinPfnUnlockAddress()

static INTSTATUS IntWinPfnUnlockAddress ( QWORD  Address,
BOOLEAN  IsPhysical 
)
static

Unlocks a guest page.

Every IntWinPfnLockAddress call for an address must match a call to this function. If the Introcore reference counter reaches 0, it means that we also have to remove the lock from the guest, but only if it is a physical, not large, page. Also, any resources held by the lock are freed: the swap hook (if it exists) and the lock itself. It will also be removed from the gWinPfns list.

Parameters
[in]AddressAddress to unlock.
[in]IsPhysicalTrue if Address is a guest physical address; False if it is a guest virtual address.
Return values
INT_STATUS_SUCCESSin case of success.
INT_STATUS_INVALID_PARAMETER_2if Address is a guest virtual address and it does not point inside the kernel.
INT_STATUS_NOT_FOUNDif no lock is found for Address.

Definition at line 446 of file winpfn.c.

Variable Documentation

◆ gWinPfns

LIST_HEAD gWinPfns = LIST_HEAD_INIT(gWinPfns)
static

The list of locked PFNs.

Definition at line 10 of file winpfn.c.