Bitdefender Hypervisor Memory Introspection
cr_protection.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "cr_protection.h"
6 #include "alerts.h"
7 #include "guests.h"
8 #include "hook_cr.h"
9 
13 static HOOK_CR *gCr4Hook = NULL;
14 
15 
16 static void
18  _In_ EXCEPTION_VICTIM_ZONE const *Victim,
19  _In_ EXCEPTION_KM_ORIGINATOR const *Originator,
20  _In_ INTRO_ACTION Action,
22  )
34 {
35  INTSTATUS status;
36  EVENT_CR_VIOLATION *pCrViol = &gAlert.Cr;
37 
38  memzero(pCrViol, sizeof(*pCrViol));
39 
40  pCrViol->Header.Action = Action;
41  pCrViol->Header.Reason = Reason;
42  if (Victim->Cr.Smap || Victim->Cr.Smep)
43  {
44  pCrViol->Header.MitreID = idExploitPrivEsc;
45  }
46  else
47  {
48  pCrViol->Header.MitreID = idRootkit;
49  }
50 
52 
53  IntAlertCrFill(Victim, Originator, pCrViol);
54 
56 
58  {
60 
63  }
64  else
65  {
67  }
68 
70  IntAlertFillCodeBlocks(Originator->Original.Rip, gGuest.Mm.SystemCr3, FALSE, &pCrViol->CodeBlocks);
71 
73 
74  status = IntNotifyIntroEvent(introEventCrViolation, pCrViol, sizeof(*pCrViol));
75  if (!INT_SUCCESS(status))
76  {
77  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
78  }
79 }
80 
81 
82 static INTSTATUS
84  _In_opt_ void *Context,
85  _In_ DWORD Cr,
86  _In_ QWORD OldValue,
87  _In_ QWORD NewValue,
88  _Out_ INTRO_ACTION *Action
89  )
105 {
106  INTSTATUS status;
107  EXCEPTION_VICTIM_ZONE victim;
108  EXCEPTION_KM_ORIGINATOR originator;
109  INTRO_ACTION_REASON reason;
110  BOOLEAN exitAfterInformation = FALSE;
111  BOOLEAN smap = (OldValue & CR4_SMAP) != 0 && (NewValue & CR4_SMAP) == 0;
112  BOOLEAN smep = (OldValue & CR4_SMEP) != 0 && (NewValue & CR4_SMEP) == 0;
113 
114  UNREFERENCED_PARAMETER(Context);
115 
116  *Action = introGuestNotAllowed;
117  reason = introReasonUnknown;
118 
119  // We allow writes that aren't on SMEP/SMAP or aren't deactivation of SMEP/SMAP
120  if (!smap && !smep)
121  {
122  *Action = introGuestAllowed;
123  return INT_STATUS_SUCCESS;
124  }
125 
127 
128  memzero(&victim, sizeof(victim));
129  memzero(&originator, sizeof(originator));
130 
131  status = IntExceptKernelGetOriginator(&originator, 0);
132  if (status == INT_STATUS_EXCEPTION_BLOCK)
133  {
134  reason = introReasonNoException;
135  exitAfterInformation = TRUE;
136  }
137  else if (!INT_SUCCESS(status))
138  {
139  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
140  reason = introReasonInternalError;
141  exitAfterInformation = TRUE;
142  }
143 
144  status = IntExceptGetVictimCr(NewValue, OldValue, Cr, &victim);
145  if (!INT_SUCCESS(status))
146  {
147  ERROR("[ERROR] Failed getting zone details: 0x%08x\n", status);
148  reason = introReasonInternalError;
149  exitAfterInformation = TRUE;
150  }
151 
152  if (exitAfterInformation)
153  {
154  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
155  }
156  else
157  {
158  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventCrViolation);
159  }
160 
162 
163  if (IntPolicyCoreTakeAction(INTRO_OPT_PROT_KM_CR4, Action, &reason))
164  {
165  IntCrSendAlert(&victim, &originator, *Action, reason);
166  }
167 
169 
170  return status;
171 }
172 
173 
174 static INTSTATUS
176  _In_opt_ void *Context,
177  _In_ DWORD Cr,
178  _In_ QWORD OldValue,
179  _In_ QWORD NewValue,
180  _Out_ INTRO_ACTION *Action
181  )
197 {
198  INTSTATUS status;
199  BOOLEAN exitAfterInformation, smep, smap;
200  KERNEL_DRIVER *pOrigDriver;
201  EXCEPTION_VICTIM_ZONE victim;
202  EXCEPTION_KM_ORIGINATOR originator;
203  INTRO_ACTION_REASON reason;
204 
205  UNREFERENCED_PARAMETER(Context);
206 
207  *Action = introGuestNotAllowed;
208  reason = introReasonUnknown;
209 
210  smap = (OldValue & CR4_SMAP) != 0 && (NewValue & CR4_SMAP) == 0;
211  smep = (OldValue & CR4_SMEP) != 0 && (NewValue & CR4_SMEP) == 0;
212 
213  // We allow writes that aren't on SMEP/SMAP or aren't deactivation of SMEP/SMAP
214  if (!smap && !smep)
215  {
216  *Action = introGuestAllowed;
217  return INT_STATUS_SUCCESS;
218  }
219 
220  pOrigDriver = IntDriverFindByAddress(gVcpu->Regs.Rip);
221  if (NULL == pOrigDriver)
222  {
223  WARNING("[WARNING] RIP 0x%016llx is not inside any module!\n", gVcpu->Regs.Rip);
224  }
225 
227 
228  memzero(&victim, sizeof(victim));
229  memzero(&originator, sizeof(originator));
230 
231  exitAfterInformation = FALSE;
232 
233  status = IntExceptKernelGetOriginator(&originator, 0);
234  if (status == INT_STATUS_EXCEPTION_BLOCK)
235  {
236  reason = introReasonNoException;
237  exitAfterInformation = TRUE;
238  }
239  else if (!INT_SUCCESS(status))
240  {
241  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
242  reason = introReasonInternalError;
243  exitAfterInformation = TRUE;
244  }
245 
246  status = IntExceptGetVictimCr(NewValue, OldValue, Cr, &victim);
247  if (!INT_SUCCESS(status))
248  {
249  ERROR("[ERROR] Failed getting zone details: 0x%08x\n", status);
250  reason = introReasonInternalError;
251  exitAfterInformation = TRUE;
252  }
253 
254  if (exitAfterInformation)
255  {
256  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
257  }
258  else
259  {
260  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventCrViolation);
261  }
262 
264 
265  if (IntPolicyCoreTakeAction(INTRO_OPT_PROT_KM_CR4, Action, &reason))
266  {
267  IntCrSendAlert(&victim, &originator, *Action, reason);
268  }
269 
271 
272  return INT_STATUS_SUCCESS;
273 }
274 
275 
276 static INTSTATUS
278  _In_opt_ void *Context,
279  _In_ DWORD Cr,
280  _In_ QWORD OldValue,
281  _In_ QWORD NewValue,
282  _Out_ INTRO_ACTION *Action
283  )
298 {
300  {
301  return IntCrWinHandleWrite(Context, Cr, OldValue, NewValue, Action);
302  }
303  else if (gGuest.OSType == introGuestLinux)
304  {
305  return IntCrLixHandleWrite(Context, Cr, OldValue, NewValue, Action);
306  }
307 
309 }
310 
311 
312 INTSTATUS
314  void
315  )
323 {
324  INTSTATUS status;
325 
326  if (NULL != gCr4Hook)
327  {
329  }
330 
331  TRACE("[CR4] Adding protection on CR4.SMEP and CR4.SMAP...\n");
332 
333  status = IntHookCrSetHook(4, 0, IntCr4HandleWrite, NULL, &gCr4Hook);
334  if (!INT_SUCCESS(status))
335  {
336  ERROR("[ERROR] IntHookCrSetHook failed: 0x%08x!\n", status);
337  return status;
338  }
339 
340  return INT_STATUS_SUCCESS;
341 }
342 
343 
344 INTSTATUS
346  void
347  )
353 {
354  if (NULL == gCr4Hook)
355  {
357  }
358 
359  TRACE("[CR4] Removing protection on CR4.SMEP and CR4.SMAP...\n");
360 
361  INTSTATUS status = IntHookCrRemoveHook(gCr4Hook);
362  if (!INT_SUCCESS(status))
363  {
364  ERROR("[ERROR] IntHookCrRemoveHook failed: 0x%08x\n", status);
365  return status;
366  }
367 
368  gCr4Hook = NULL;
369 
370  return INT_STATUS_SUCCESS;
371 }
Measures kernel mode exceptions checks.
Definition: stats.h:51
#define _In_opt_
Definition: intro_sal.h:16
enum _INTRO_ACTION_REASON INTRO_ACTION_REASON
The reason for which an INTRO_ACTION was taken.
_Bool BOOLEAN
Definition: intro_types.h:58
#define _Out_
Definition: intro_sal.h:22
QWORD IntAlertCoreGetFlags(QWORD ProtectionFlag, INTRO_ACTION_REASON Reason)
Returns the flags for an alert.
Definition: alerts.c:366
An internal error occurred (no memory, pages not present, etc.).
Definition: intro_types.h:195
BOOLEAN IntPolicyCoreForceBetaIfNeeded(QWORD Flag, INTRO_ACTION *Action)
Checks if a forced action should be taken even if the log-only mode is active.
Definition: introcore.c:2803
Event structure for CR violation.
Definition: intro_types.h:1346
BOOLEAN Valid
If FALSE, we failed to get the thread and the process token.
Definition: intro_types.h:883
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
#define _In_
Definition: intro_sal.h:21
MITRE_ID MitreID
The Mitre ID that corresponds to this attack.
Definition: intro_types.h:1199
QWORD SystemCr3
The Cr3 used to map the kernel.
Definition: guests.h:211
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
BOOLEAN IntPolicyCoreTakeAction(QWORD Flag, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
Returns the action that should be taken for a core introspection option.
Definition: introcore.c:2693
BOOLEAN ImpersonationToken
TRUE if this is an impersonation token.
Definition: intro_types.h:864
#define STATS_EXIT(id)
Definition: stats.h:160
INTSTATUS IntHookCrSetHook(DWORD Cr, DWORD Flags, PFUNC_CrWriteHookCallback Callback, void *Context, HOOK_CR **Hook)
Set a control register write hook.
Definition: hook_cr.c:11
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
Sent when a CR violation triggers an alert. See EVENT_CR_VIOLATION.
Definition: intro_types.h:88
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
Definition: intro_types.h:1198
static HOOK_CR * gCr4Hook
The Cr4 hook handle.
Definition: cr_protection.c:13
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
int INTSTATUS
The status data type.
Definition: introstatus.h:24
Rootkit.
Definition: intro_types.h:1144
Describes a kernel-mode originator.
Definition: exceptions.h:943
void IntAlertCrFill(const EXCEPTION_VICTIM_ZONE *Victim, const EXCEPTION_KM_ORIGINATOR *Originator, EVENT_CR_VIOLATION *CrViolation)
Saves information about a CR write attempt in an event.
Definition: alerts.c:1210
EVENT_CR_VIOLATION Cr
Definition: alerts.h:18
INTRO_GUEST_TYPE OSType
The type of the guest.
Definition: guests.h:278
void IntAlertFillCpuContext(BOOLEAN CopyInstruction, INTRO_CPUCTX *CpuContext)
Fills the current CPU context for an alert.
Definition: alerts.c:492
static void IntCrSendAlert(EXCEPTION_VICTIM_ZONE const *Victim, EXCEPTION_KM_ORIGINATOR const *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Sends a CR violation alert.
Definition: cr_protection.c:17
Describes a kernel driver.
Definition: drivers.h:30
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
Definition: alerts.c:327
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
Definition: intro_types.h:1195
INTSTATUS IntAlertFillCodeBlocks(QWORD Rip, QWORD Cr3, BOOLEAN Execute, INTRO_CODEBLOCKS *CodeBlocks)
Fills the code blocks pattern for an alert.
Definition: alerts.c:71
INTRO_TOKEN SecurityInfo
The thread token (if impersonating) or the process token (Windows only).
Definition: intro_types.h:912
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
#define INT_STATUS_EXCEPTION_BLOCK
Definition: introstatus.h:421
static INTSTATUS IntCrLixHandleWrite(void *Context, DWORD Cr, QWORD OldValue, QWORD NewValue, INTRO_ACTION *Action)
Handles a control register write attempt done by a Linux guest.
#define STATS_ENTER(id)
Definition: stats.h:153
INTRO_CPUCTX CpuContext
The context of the CPU that triggered the alert.
Definition: intro_types.h:1196
#define CR4_SMEP
Definition: processor.h:61
INTSTATUS IntNotifyIntroEvent(INTRO_EVENT_TYPE EventClass, void *Param, size_t EventSize)
Notifies the integrator about an introspection alert.
Definition: glue.c:1042
#define memzero(a, s)
Definition: introcrt.h:35
INTRO_WIN_TOKEN WindowsToken
A Windows token.
Definition: intro_types.h:892
unsigned long long QWORD
Definition: intro_types.h:53
INTSTATUS IntExceptGetVictimCr(QWORD NewValue, QWORD OldValue, DWORD Cr, EXCEPTION_VICTIM_ZONE *Victim)
This function is used to get the information about the CR victim.
#define TRUE
Definition: intro_types.h:30
#define TRACE(fmt,...)
Definition: glue.h:58
INTSTATUS IntHookCrRemoveHook(HOOK_CR *Hook)
Remove a control register hook.
Definition: hook_cr.c:135
void IntExceptKernelLogInformation(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_KM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Print the information about a kernel-mode violation and dumps the code-blocks.
Kernel-mode exception.
Definition: exceptions.h:61
static INTSTATUS IntCrWinHandleWrite(void *Context, DWORD Cr, QWORD OldValue, QWORD NewValue, INTRO_ACTION *Action)
Handles a control register write attempt done by a Windows guest.
Definition: cr_protection.c:83
#define INT_STATUS_ALREADY_INITIALIZED_HINT
Definition: introstatus.h:323
#define WARNING(fmt,...)
Definition: glue.h:60
#define CR4_SMAP
Definition: processor.h:62
INTRO_CODEBLOCKS CodeBlocks
Code blocks extracted for the alert.
Definition: intro_types.h:1368
Describes the modified zone.
Definition: exceptions.h:893
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
uint32_t DWORD
Definition: intro_types.h:49
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1348
enum _INTRO_ACTION INTRO_ACTION
Event actions.
INTSTATUS IntCr4Unprotect(void)
Disables the CR4 protection.
QWORD Cr3
The value of the guest CR3 register when the event was generated.
Definition: intro_types.h:970
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
void IntAlertFillWinProcessByCr3(QWORD ProcessCr3, INTRO_PROCESS *EventProcess)
Saves information about a Windows process inside an alert. The process is searched by its kernel CR3...
Definition: alerts.c:756
Exploitation for Privilege Escalation.
Definition: intro_types.h:1148
static INTSTATUS IntCr4HandleWrite(void *Context, DWORD Cr, QWORD OldValue, QWORD NewValue, INTRO_ACTION *Action)
Handles CR4 writes.
INTRO_ACTION Action
The action that was taken as the result of this alert.
Definition: intro_types.h:1194
KERNEL_DRIVER * IntDriverFindByAddress(QWORD Gva)
Returns the driver in which Gva resides.
Definition: drivers.c:164
#define INT_STATUS_NOT_SUPPORTED
Definition: introstatus.h:287
INTRO_PROCESS CurrentProcess
The current process.
Definition: intro_types.h:1197
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
The action was blocked because there was no exception for it.
Definition: intro_types.h:189
INTRO_EXEC_CONTEXT ExecContext
Information about the instruction that triggered the alert.
Definition: intro_types.h:1370
INTSTATUS IntCr4Protect(void)
Activates the Cr4 protection.
#define INTRO_OPT_PROT_KM_CR4
Enable CR4.SMEP and CR4.SMAP protection.
Definition: intro_types.h:426
void IntAlertFillLixCurrentProcess(INTRO_PROCESS *EventProcess)
Saves the current Linux process inside an event.
Definition: alerts.c:1310
INTSTATUS IntExceptKernelGetOriginator(EXCEPTION_KM_ORIGINATOR *Originator, DWORD Options)
This function is used to get the information about the kernel-mode originator.
INTSTATUS IntAlertFillExecContext(QWORD Cr3, INTRO_EXEC_CONTEXT *ExecContext)
Fills the current execution context.
Definition: alerts.c:31
void IntExcept(EXCEPTION_VICTIM_ZONE *Victim, void *Originator, EXCEPTION_TYPE Type, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason, INTRO_EVENT_TYPE EventClass)
This function is the entry point for the exception mechanism.
Definition: exceptions.c:3357
#define FALSE
Definition: intro_types.h:34