Bitdefender Hypervisor Memory Introspection
|
#include "lixmm.h"
#include "alerts.h"
#include "hook.h"
#include "lixfiles.h"
#include "lixnet.h"
#include "scan_engines.h"
#include "shellcode.h"
#include "lixksym.h"
#include "lixfastread.h"
Go to the source code of this file.
Macros | |
#define | LIX_VMA_VDSO_FLAGS (VM_READ | VM_EXEC | VM_DONTEXPAND | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) |
The flags set for vDSO mappings. More... | |
#define | LIX_VMA_PROT_MASK BIT(63) |
The bit in vma.vm_flags used to mark the VMA protection status. More... | |
#define | LIX_VMA_IS_VDSO(Vma) (((((Vma)->Flags & LIX_VMA_VDSO_FLAGS) == LIX_VMA_VDSO_FLAGS) && (0 == (Vma)->File) && (IntLixVmaGetPageCount(Vma) <= 2))) |
Checks if a Vma is a vDSO mapping. More... | |
#define | LIX_VMA_MAX_GUEST (10 * 4096) |
Max VMAs allowed for a process. More... | |
#define | for_each_vad(Process, _var_name) list_for_each((Process)->Vmas, LIX_VMA, _var_name) |
Iterator for the process VMAs. More... | |
Functions | |
static INTSTATUS | IntLixVmaFill (QWORD VmaGva, LIX_TASK_OBJECT *Process, LIX_VMA *Vma) |
Retrieves in-guest information about a VMA and stores them in a LIX_VMA structure. More... | |
static size_t | IntLixVmaGetPageCount (const LIX_VMA *Vma) |
Calculate the number of pages available inside a VMA. More... | |
INTSTATUS | IntLixMmGetInitMm (QWORD *InitMm) |
Find the address of the "init_mm" variable inside the kernel. More... | |
static INTSTATUS | IntLixMmFindVmaInLinkedList (QWORD MmGva, QWORD Address, QWORD *VmaGva, BOOLEAN Backward) |
Finds the GVA of the VMA which contains a user memory address by iterating the VMAs linked list of a mm_struct. More... | |
INTSTATUS | IntLixMmFindVmaInRbTree (QWORD MmGva, QWORD Address, QWORD *VmaGva) |
Finds the GVA of the VMA which contains a user memory address traversing the VMA rb tree of the mm_struct. More... | |
INTSTATUS | IntLixMmFetchVma (LIX_TASK_OBJECT *Task, QWORD Address, LIX_VMA *Vma) |
Retrieve information about a VMA structure containing a user mode address. More... | |
INTSTATUS | IntLixMmFindVmaRange (QWORD Gva, LIX_TASK_OBJECT *Task, QWORD *VmaStart, QWORD *VmaEnd) |
Finds the VMA limits that contain an address. More... | |
LIX_VMA * | IntLixMmFindVmaByRange (const LIX_TASK_OBJECT *Process, QWORD Address) |
Finds if a memory address inside a process is being protected and returns the corresponding LIX_VMA structure. More... | |
static LIX_VMA * | IntLixVmaFindByGva (const LIX_TASK_OBJECT *Process, QWORD Vma) |
Finds if a VMA is being protected and returns the corresponding LIX_VMA structure. More... | |
INTSTATUS | IntLixVmaCreate (QWORD VmaGva, LIX_TASK_OBJECT *Process, LIX_VMA **Vma) |
Creates a LIX_VMA object. More... | |
LIX_VMA * | IntLixMmFindVma (LIX_TASK_OBJECT *Task, QWORD Vma) |
Finds a protected VMA inside a process VMA list. More... | |
static INTSTATUS | IntVmaMarkProtection (LIX_VMA *Vma, BOOLEAN Protected) |
Marks the VMA as either protected or unprotected. More... | |
static INTSTATUS | IntLixVmaRemoveProtection (LIX_VMA *Vma, BOOLEAN Mark) |
Removes the protection for a VMA. More... | |
static void | IntLixVmaDestroy (LIX_VMA *Vma) |
Destroys a LIX_VMA object. More... | |
void | IntLixMmDestroyVmas (LIX_TASK_OBJECT *Task) |
Remove protection for the VMAs belonging to a process. More... | |
static INTSTATUS | IntLixVmaHandlePageExecution (void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action) |
Linux user mode page execution handler. More... | |
static INTSTATUS | IntLixVmaProtect (LIX_VMA *Vma) |
Activates protection for a VMA. More... | |
static INTSTATUS | IntLixMmPopulateVmasInternal (LIX_TASK_OBJECT *Process, BOOLEAN Backward) |
Iterate the VMA linked list of a process in the given direction and protect the executable ones. More... | |
INTSTATUS | IntLixMmPopulateVmas (LIX_TASK_OBJECT *Task) |
Populate the Introcore VMAs linked list by iterating the one inside the guest. More... | |
static void | IntLixMmListVmasInternal (QWORD Mm, LIX_TASK_OBJECT *Process, BOOLEAN Backward) |
Logs all VMAs from a mm_struct. More... | |
void | IntLixMmListVmas (QWORD Mm, LIX_TASK_OBJECT *Process) |
INTSTATUS | IntLixVmaInsert (void *Detour) |
Detour handler for "__vma_link_rb" function. More... | |
INTSTATUS | IntLixVmaChangeProtection (void *Detour) |
Detour handler for "change_protection" function. More... | |
static INTSTATUS | IntLixVmaIntervalChanged (LIX_VMA *AdjustedVma, QWORD InsertVma) |
Simply re-apply the protection for the given vma. More... | |
INTSTATUS | IntLixVmaExpandDownwards (void *Detour) |
Detour handler for "expand_downwards" function. More... | |
static INTSTATUS | IntLixVmaAdjustInternal (LIX_TASK_OBJECT *Task, QWORD Vma) |
Checks if the VMA limits have changed and updates the protected memory range. More... | |
INTSTATUS | IntLixVmaAdjust (void *Detour) |
Detour handler for in-guest functions adjusting VMA ranges. More... | |
INTSTATUS | IntLixVmaRemove (void *Detour) |
Detour handler for functions that unmap memory for processes. More... | |
#define for_each_vad | ( | Process, | |
_var_name | |||
) | list_for_each((Process)->Vmas, LIX_VMA, _var_name) |
Iterator for the process VMAs.
Definition at line 38 of file lixmm.c.
Referenced by IntLixMmDestroyVmas(), IntLixMmFindVma(), IntLixMmFindVmaByRange(), and IntLixVmaFindByGva().
#define LIX_VMA_IS_VDSO | ( | Vma | ) | (((((Vma)->Flags & LIX_VMA_VDSO_FLAGS) == LIX_VMA_VDSO_FLAGS) && (0 == (Vma)->File) && (IntLixVmaGetPageCount(Vma) <= 2))) |
Checks if a Vma is a vDSO mapping.
Definition at line 28 of file lixmm.c.
Referenced by IntLixMmPopulateVmasInternal(), and IntLixVmaInsert().
#define LIX_VMA_MAX_GUEST (10 * 4096) |
Max VMAs allowed for a process.
Definition at line 33 of file lixmm.c.
Referenced by IntLixMmFindVmaInLinkedList(), IntLixMmListVmasInternal(), and IntLixMmPopulateVmasInternal().
#define LIX_VMA_PROT_MASK BIT(63) |
The bit in vma.vm_flags used to mark the VMA protection status.
Definition at line 23 of file lixmm.c.
Referenced by IntLixVmaChangeProtection(), and IntVmaMarkProtection().
#define LIX_VMA_VDSO_FLAGS (VM_READ | VM_EXEC | VM_DONTEXPAND | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) |
void IntLixMmDestroyVmas | ( | LIX_TASK_OBJECT * | Task | ) |
Remove protection for the VMAs belonging to a process.
[in] | Task | The process whose VMAs will be unprotected. |
Definition at line 1016 of file lixmm.c.
Referenced by IntLixMmPopulateVmas(), and IntLixTaskDeactivateExploitProtection().
INTSTATUS IntLixMmFetchVma | ( | LIX_TASK_OBJECT * | Task, |
QWORD | Address, | ||
LIX_VMA * | Vma | ||
) |
Retrieve information about a VMA structure containing a user mode address.
[in] | Task | The process on whose mm space the address should be searched. |
[in] | Address | The searched address. |
[out] | Vma | Upon successful return will contain information about the requested VMA. |
Definition at line 581 of file lixmm.c.
Referenced by IntLixCredAnalyzeStack(), IntLixMmFindVmaRange(), and IntLixStackDumpUmStackTrace().
LIX_VMA* IntLixMmFindVma | ( | LIX_TASK_OBJECT * | Task, |
QWORD | Vma | ||
) |
Finds a protected VMA inside a process VMA list.
[in] | Task | The process in whose list the Vma should be found. |
[in] | Vma | The Gva of a VMA object. |
Definition at line 871 of file lixmm.c.
Referenced by IntLixVmaAdjustInternal(), IntLixVmaChangeProtection(), IntLixVmaExpandDownwards(), IntLixVmaInsert(), and IntLixVmaRemove().
LIX_VMA* IntLixMmFindVmaByRange | ( | const LIX_TASK_OBJECT * | Process, |
QWORD | Address | ||
) |
Finds if a memory address inside a process is being protected and returns the corresponding LIX_VMA structure.
[in] | Process | |
[in] | Address |
Definition at line 699 of file lixmm.c.
Referenced by IntExceptGetVictimEpt(), and IntLixVmaHandlePageExecution().
|
static |
Finds the GVA of the VMA which contains a user memory address by iterating the VMAs linked list of a mm_struct.
[in] | MmGva | The GVA of the mm_struct. |
[in] | Address | The address whose VMA has to be found. |
[out] | VmaGva | Upon successful return, this parameter will contain the address of the VMA containing the Address parameter |
[in] | Backward | This parameter controls if the list should be iterated onward or backwards. |
Definition at line 359 of file lixmm.c.
Referenced by IntLixMmFetchVma().
Finds the GVA of the VMA which contains a user memory address traversing the VMA rb tree of the mm_struct.
This function will attempt to find the Address inside the red black tree within 64 iterations. This limit should be high enough since it allows a maximum of 2^64 -1 objects.
The red black tree implementation allows the lock-free lookup. It guarantees that a found item is correct. However, it does not guarantee that if an item is not found it doesn't exist. Check https://elixir.bootlin.com/linux/v5.5/source/lib/rbtree.c for an in-depth explanation.
It is highly recommended to perform a IntLixMmFindVmaInLinkedList call when this function fails in order to make sure that the Address indeed does not exist.
[in] | MmGva | The GVA of the mm_struct. |
[in] | Address | The address whose VMA has to be found. |
[out] | VmaGva | Upon successful return, this parameter will contain the address of the VMA containing the Address parameter. |
Definition at line 464 of file lixmm.c.
Referenced by IntLixMmFetchVma().
INTSTATUS IntLixMmFindVmaRange | ( | QWORD | Gva, |
LIX_TASK_OBJECT * | Task, | ||
QWORD * | VmaStart, | ||
QWORD * | VmaEnd | ||
) |
Finds the VMA limits that contain an address.
[in] | Gva | The address that will be searched. |
[in] | Task | The process the process on whose address space the search will be performed. |
[out] | VmaStart | Upon successful return will contain the lower limit of the VMA. |
[out] | VmaEnd | Upon successful return will contain the upper limit of the VMA. |
Definition at line 640 of file lixmm.c.
Referenced by IntLixTaskGetUserStack(), and IntLixTaskIsUserStackPivoted().
Find the address of the "init_mm" variable inside the kernel.
Searches the linux kernel for the 'init_mm' variable. This variable can be exported in kallsyms but some distros (Debian) disable variable exporting in kallsyms, and we must do it our way then.
Linux kernel v5.5 defines the init_mm as follows:
If the "init_mm" address couldn't be resolved via kallsyms then this function will perform a search inside the ".data" section and will apply the following heuristic in order to determine it's address:
[out] | InitMm | Upon successful return will contain the address of the init_mm symbol. |
Definition at line 76 of file lixmm.c.
Referenced by IntLixGuestNew().
void IntLixMmListVmas | ( | QWORD | Mm, |
LIX_TASK_OBJECT * | Process | ||
) |
Logs all VMAs from a mm_struct.
[in] | Mm | The mm_struct GVA. |
[in] | Process | Pointer to a LIX_TASK_OBJECT structure. |
Definition at line 1671 of file lixmm.c.
Referenced by IntLixTaskDump().
|
static |
Logs all VMAs from a mm_struct.
Iterates the VMA linked list of the given mm_struct and lists their attributes, such as VmaStart, VmaEnd, VmaFlags and page count.
[in] | Mm | The guest virtual address of the mm_struct whose VMAs will be listed. |
[in] | Process | The process owning the mm_struct. |
[in] | Backward | If set to TRUE, the VMA linked list will be iterated backwards. |
Definition at line 1555 of file lixmm.c.
Referenced by IntLixMmListVmas().
INTSTATUS IntLixMmPopulateVmas | ( | LIX_TASK_OBJECT * | Task | ) |
Populate the Introcore VMAs linked list by iterating the one inside the guest.
This function will iterate the in-guest VMA list and attempt to protect the ones which are marked as executable.
[in] | Task | The process whose VMA list should be populated. |
Definition at line 1510 of file lixmm.c.
Referenced by IntLixTaskActivateExploitProtection().
|
static |
Iterate the VMA linked list of a process in the given direction and protect the executable ones.
This function will iterate in the given direction the VMAs linked list of a process and the ones that are marked as executable but are not file mappings will be cached internally and protected. The vDSO VMA is ignored since it is protected globally.
[in] | Process | The process whose VMA list this function will iterate. |
[in] | Backward | If the list should be iterated backwards. |
Definition at line 1400 of file lixmm.c.
Referenced by IntLixMmPopulateVmas().
INTSTATUS IntLixVmaAdjust | ( | void * | Detour | ) |
Detour handler for in-guest functions adjusting VMA ranges.
This function checks the result of the "vma_adjust" call and adjust the protection for the affected VMAs.
[in] | Detour | Unused. |
|
static |
Checks if the VMA limits have changed and updates the protected memory range.
[in] | Task | Process the Vma belongs to. |
[in] | Vma | The GVA of the vma structure to be processed. |
Definition at line 1970 of file lixmm.c.
Referenced by IntLixVmaAdjust().
INTSTATUS IntLixVmaChangeProtection | ( | void * | Detour | ) |
Detour handler for "change_protection" function.
This function is called whenever a VMA belonging to a protected memory space is making a transition from executable to non-executable and vice-versa. If the VMA if being marked as executable than this function will establish the protection, otherwise the protection will be removed and it will be marked as unprotected.
[in] | Detour | Unused. |
INTSTATUS IntLixVmaCreate | ( | QWORD | VmaGva, |
LIX_TASK_OBJECT * | Process, | ||
LIX_VMA ** | Vma | ||
) |
Creates a LIX_VMA object.
[in] | VmaGva | The GVA of the vma based on which the LIX_VMA will be created. |
[in] | Process | The process owning the VMA. |
[out] | Vma | Upon successful return will contain the pointer to the newly created LIX_VMA object. |
Definition at line 821 of file lixmm.c.
Referenced by IntLixMmPopulateVmasInternal(), IntLixVmaChangeProtection(), IntLixVmaInsert(), and IntLixVmaIntervalChanged().
|
static |
Destroys a LIX_VMA object.
Removes the EPT hooks established for the given VMA and mark it as unprotected. This function will also destroy the LIX_VMA object removing it from the internal list and freeing the allocated memory.
[in] | Vma | The VMA which will be destroyed. |
Definition at line 995 of file lixmm.c.
Referenced by IntLixMmDestroyVmas(), IntLixMmPopulateVmasInternal(), IntLixVmaAdjustInternal(), IntLixVmaChangeProtection(), IntLixVmaExpandDownwards(), IntLixVmaInsert(), IntLixVmaIntervalChanged(), and IntLixVmaRemove().
INTSTATUS IntLixVmaExpandDownwards | ( | void * | Detour | ) |
Detour handler for "expand_downwards" function.
This function updates the protection for VMAs which are able to expand downwards (usually this is the case for stack VMAs). It checks if the lower limit has changed and updates the protected memory range.
[in] | Detour | Unused. |
|
static |
Retrieves in-guest information about a VMA and stores them in a LIX_VMA structure.
[in] | VmaGva | The GVA of the vma based on which the LIX_VMA will be created. |
[in] | Process | The process owning the VMA. |
[out] | Vma | Upon successful return the structure will be filled with details regarding the VMA. |
Definition at line 753 of file lixmm.c.
Referenced by IntLixMmFetchVma(), IntLixMmListVmasInternal(), IntLixMmPopulateVmasInternal(), and IntLixVmaCreate().
|
static |
|
inlinestatic |
Calculate the number of pages available inside a VMA.
[in] | Vma | The VMA structure whose page count will be returned. |
Definition at line 50 of file lixmm.c.
Referenced by IntLixMmListVmasInternal(), and IntLixVmaProtect().
|
static |
Linux user mode page execution handler.
This function will review the analyze the violation and will decide if the execution is malicious or not based on the following heuristic:
The previous checks may have three outcomes:
If the attempt was malicious and it was not excepted, and the PROC_OPT_KILL_ON_EXPLOIT option is available, then a UD exception will be injected in order to crash the victim. Even if the injected UD will trigger a segmentation fault which can be caught by an exception handler, the IntLixCrashHandle function will make sure that the signal delivered is SIGKILL instead of SIGSEGV.
[in] | Context | The context provided to IntHookGpaSetHook. |
[in] | Hook | The GPA_HOOK object. |
[in] | Address | The GPA access that trigger the violation. |
[out] | Action | Will contain the action that should be taken regarding the violation. |
Definition at line 1035 of file lixmm.c.
Referenced by IntLixVmaProtect().
INTSTATUS IntLixVmaInsert | ( | void * | Detour | ) |
Detour handler for "__vma_link_rb" function.
This function is called when an executable VMA is being created. If the newly created VMA is already protected (by a previous vma_adjust call) then it will be ignored.
[in] | Detour | Unused. |
Simply re-apply the protection for the given vma.
Will shrink or expand the given VMA. Will also create & insert a new vad located at InsertVma if needed. This is because the InsertVma, most probably, contain a sub-part of the AdjustedVma, and this way we can simply copy the hooks to the new vad, instead of deleting & re-hooking them on the next exit (it's very slow that way).
[in] | AdjustedVma | The Vma whose interval changed. |
[in] | InsertVma | The GVA of a newly created vma. |
Definition at line 1843 of file lixmm.c.
Referenced by IntLixVmaAdjustInternal(), and IntLixVmaExpandDownwards().
Activates protection for a VMA.
This function will establish the GVA hooks for the given vma and will mark it as protected.
[in] | Vma | The vma to protect |
Definition at line 1322 of file lixmm.c.
Referenced by IntLixMmPopulateVmasInternal(), IntLixVmaChangeProtection(), IntLixVmaInsert(), and IntLixVmaIntervalChanged().
INTSTATUS IntLixVmaRemove | ( | void * | Detour | ) |
Detour handler for functions that unmap memory for processes.
This functions removes the protection from a vma as it's being unmapped from the process memory space. Usually, the kernel function that will trigger this event is "(__)vma_rb_erase". Because the support for RHEL 6 required lots of hacks and workarounds, other functions may trigger this. However, every detour must provide this function the Gva of the removed VMA in R8 register and the Gva mm struct owning the VMA in R9 register.
[in] | Detour | Unused. |
Removes the protection for a VMA.
[in] | Vma | The VMA whose protection will be removed. |
[in] | Mark | TRUE if the caller wants to also mark the VMA as unprotected. |
Definition at line 955 of file lixmm.c.
Referenced by IntLixVmaDestroy(), IntLixVmaHandlePageExecution(), IntLixVmaIntervalChanged(), and IntLixVmaProtect().
Marks the VMA as either protected or unprotected.
Based on the Protected parameter value, the vma's flags inside the guest will be patched to reflect whether it is protected or not. This mechanism is used in order to increase the performance by ignoring any changes on VMAs that are not protected by Introcore.
[in] | Vma | The VMA that should be marked. |
[in] | Protected | TRUE if the VMA should be marked as protected, FALSE otherwise. |
Definition at line 898 of file lixmm.c.
Referenced by IntLixVmaProtect(), and IntLixVmaRemoveProtection().