Bitdefender Hypervisor Memory Introspection
dtr_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 "dtr_protection.h"
6 #include "alerts.h"
7 #include "guests.h"
8 #include "hook_dtr.h"
9 #include "introcpu.h"
10 #include "winidt.h"
11 #include "lixidt.h"
12 
13 
14 static void *gIdtrHook;
15 static void *gGdtrHook;
16 
17 
18 static QWORD
20  _In_ INTRO_OBJECT_TYPE DtrType
21  )
29 {
30  switch (DtrType)
31  {
36 
37  default:
38  ERROR("[ERROR] Invalid dtr type: %d\n", DtrType);
39  }
40 
41  return 0;
42 }
43 
44 
45 static INTSTATUS
48  _In_ PEXCEPTION_KM_ORIGINATOR Originator,
49  _In_ INTRO_ACTION Action,
51  )
65 {
66  INTSTATUS status;
67  EVENT_DTR_VIOLATION *pDtrViol = &gAlert.Dtr;
68 
69  memzero(pDtrViol, sizeof(*pDtrViol));
70 
71  pDtrViol->Header.Action = Action;
72  pDtrViol->Header.Reason = Reason;
73 
74  pDtrViol->Header.Flags = IntAlertCoreGetFlags(IntDtrGetProtOption(Victim->Dtr.Type), Reason);
75  pDtrViol->Header.MitreID = idRootkit;
76 
77  IntAlertDtrFill(Victim, Originator, pDtrViol);
78 
80 
82  {
84  }
85  else if (introGuestWindows == gGuest.OSType)
86  {
88  }
89 
90  IntAlertFillCodeBlocks(Originator->Original.Rip, gGuest.Mm.SystemCr3, FALSE, &pDtrViol->CodeBlocks);
91 
92  IntAlertFillVersionInfo(&pDtrViol->Header);
93 
95 
96  status = IntNotifyIntroEvent(introEventDtrViolation, pDtrViol, sizeof(*pDtrViol));
97  if (!INT_SUCCESS(status))
98  {
99  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
100  }
101 
102  return status;
103 }
104 
105 
106 static INTSTATUS
108  _In_ DTR *OldDtr,
109  _In_ DTR *NewDtr,
110  _In_ DWORD Flags,
111  _Out_ INTRO_ACTION *Action
112  )
128 {
129  INTSTATUS status;
130  EXCEPTION_VICTIM_ZONE victim;
131  EXCEPTION_KM_ORIGINATOR originator;
132  BOOLEAN exitAfterInformation;
133  INTRO_ACTION_REASON reason;
134  INTRO_OBJECT_TYPE type;
135 
136  UNREFERENCED_PARAMETER(Flags);
137 
138  exitAfterInformation = FALSE;
139 
140  // By default we do not allow this
141  *Action = introGuestNotAllowed;
142  reason = introReasonUnknown;
143 
144  if (!!(Flags & IG_DESC_ACCESS_GDTR))
145  {
146  type = introObjectTypeGdtr;
147  }
148  else if (!!(Flags & IG_DESC_ACCESS_IDTR))
149  {
150  type = introObjectTypeIdtr;
151  }
152  else
153  {
155  }
156 
157  memzero(&victim, sizeof(victim));
158  memzero(&originator, sizeof(originator));
159 
161 
163  if (status == INT_STATUS_EXCEPTION_BLOCK)
164  {
165  reason = introReasonNoException;
166  exitAfterInformation = TRUE;
167  }
168  else if (!INT_SUCCESS(status))
169  {
170  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
171 
172  reason = introReasonInternalError;
173  exitAfterInformation = TRUE;
174  }
175 
176  status = IntExceptGetVictimDtr(NewDtr, OldDtr, type, &victim);
177  if (!INT_SUCCESS(status))
178  {
179  ERROR("[ERROR] Failed getting zone details: 0x%08x\n", status);
180 
181  reason = introReasonInternalError;
182  exitAfterInformation = TRUE;
183  }
184 
185  if (exitAfterInformation)
186  {
187  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
188  }
189  else
190  {
191  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventDtrViolation);
192  }
193 
195 
196  if (IntPolicyCoreTakeAction(IntDtrGetProtOption(type), Action, &reason))
197  {
198  IntDtrSendAlert(&victim, &originator, *Action, reason);
199  }
200 
202 
203  if (introGuestNotAllowed != *Action)
204  {
205  if (introObjectTypeIdtr == type)
206  {
207  // Remove on this CPU the old IDT protection because the IDT base will be outdated
209  {
211  }
212  else if (introGuestWindows == gGuest.OSType)
213  {
215  }
216 
217  gVcpu->IdtBase = NewDtr->Base;
218  gVcpu->IdtLimit = NewDtr->Limit;
219 
220  // Add on this CPU the new IDT protection with the updated IDT base
222  {
223  status = IntLixIdtProtectAll();
224  if (!INT_SUCCESS(status))
225  {
226  ERROR("[ERROR] IntLixIdtProtectAll failed. Status: %d\n", status);
227  }
228  }
229  else if (introGuestWindows == gGuest.OSType)
230  {
232  }
233  }
234  else if (introObjectTypeGdtr == type)
235  {
236  gVcpu->GdtBase = NewDtr->Base;
237  }
238  }
239 
240  return INT_STATUS_SUCCESS;
241 }
242 
243 
244 INTSTATUS
246  void
247  )
255 {
256  INTSTATUS status = INT_STATUS_SUCCESS;
257  PFUNC_DtrReadWriteHookCallback pCallback = NULL;
258 
259  if (!gGuest.SupportDTR)
260  {
261  WARNING("[WARNING] DTR events are not supported by the HV, will NOT protect IDTR!\n");
263  }
264 
265  if (NULL != gIdtrHook)
266  {
268  }
269 
270  pCallback = IntDtrHandleWrite;
271 
272  TRACE("[DTR] Adding protection on IDTR...\n");
273 
275  if (!INT_SUCCESS(status))
276  {
277  ERROR("[ERROR] Failed hooking the IDTR!\n");
278  return status;
279  }
280 
281  return status;
282 }
283 
284 
285 INTSTATUS
287  void
288  )
296 {
297  INTSTATUS status = INT_STATUS_SUCCESS;
298  PFUNC_DtrReadWriteHookCallback pCallback = NULL;
299 
300  if (!gGuest.SupportDTR)
301  {
302  WARNING("[WARNING] DTR events are not supported by the HV, will NOT protect GDTR!\n");
304  }
305 
306  if (NULL != gGdtrHook)
307  {
309  }
310 
311  pCallback = IntDtrHandleWrite;
312 
313  TRACE("[DTR] Adding protection on GDTR...\n");
314 
316  if (!INT_SUCCESS(status))
317  {
318  ERROR("[ERROR] Failed hooking the GDTR!\n");
319  return status;
320  }
321 
322  return status;
323 }
324 
325 
326 INTSTATUS
328  void
329  )
336 {
337  if (NULL == gIdtrHook)
338  {
340  }
341 
342  TRACE("[DTR] Removing protection on IDTR...\n");
343 
345 
346  gIdtrHook = NULL;
347 
348  return INT_STATUS_SUCCESS;
349 }
350 
351 
352 INTSTATUS
354  void
355  )
362 {
363  if (NULL == gGdtrHook)
364  {
366  }
367 
368  TRACE("[DTR] Removing protection on GDTR...\n");
369 
371 
372  gGdtrHook = NULL;
373 
374  return INT_STATUS_SUCCESS;
375 }
Measures kernel mode exceptions checks.
Definition: stats.h:51
QWORD GdtBase
Original GDT base.
Definition: guests.h:112
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
BOOLEAN SupportDTR
Set to True if support for DTR access exits was detected.
Definition: guests.h:358
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
IDTR access.
Definition: glueiface.h:313
DWORD Index
The VCPU number.
Definition: guests.h:172
#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
#define STATS_EXIT(id)
Definition: stats.h:160
WORD IdtLimit
The current IDT limit.
Definition: guests.h:111
Sent when a DTR violation triggers an alert. See EVENT_DTR_VIOLATION.
Definition: intro_types.h:98
static void * gGdtrHook
The GDTR hook.
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
Definition: intro_types.h:1198
EVENT_DTR_VIOLATION Dtr
Definition: alerts.h:20
#define EXCEPTION_KM_ORIGINATOR_OPT_DO_NOT_BLOCK
Flag that can be passed to IntExceptKernelGetOriginator if the action should not be blocked...
Definition: exceptions.h:1053
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
INTSTATUS IntHookDtrSetHook(DWORD Flags, PFUNC_DtrReadWriteHookCallback Callback, void **Hook)
Places a descriptor table register hook.
Definition: hook_dtr.c:11
int INTSTATUS
The status data type.
Definition: introstatus.h:24
GDTR access.
Definition: glueiface.h:314
Rootkit.
Definition: intro_types.h:1144
Describes a kernel-mode originator.
Definition: exceptions.h:943
INTSTATUS IntIdtrUnprotect(void)
Remove the IDTR protection.
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 QWORD IntDtrGetProtOption(INTRO_OBJECT_TYPE DtrType)
Given a DTR object type, return the protection option which controls it.
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
GENERIC_ALERT gAlert
Global alert buffer.
Definition: alerts.c:27
enum _INTRO_OBJECT_TYPE INTRO_OBJECT_TYPE
The type of the object protected by an EPT hook.
INTSTATUS IntWinIdtProtectOnCpu(DWORD CpuNumber)
Protects the IDT against writes on a CPU.
Definition: winidt.c:479
INTSTATUS IntLixIdtUnprotectAll(void)
Disable protection for IDT on all CPUs.
Definition: lixidt.c:261
static void * gIdtrHook
The IDTR hook.
#define INT_STATUS_EXCEPTION_BLOCK
Definition: introstatus.h:421
#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
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
unsigned long long QWORD
Definition: intro_types.h:53
#define INTRO_OPT_PROT_KM_IDTR
Enable interrupt descriptor-table registers protection.
Definition: intro_types.h:429
QWORD IdtBase
Original IDT base.
Definition: guests.h:110
#define TRUE
Definition: intro_types.h:30
INTRO_CODEBLOCKS CodeBlocks
Code blocks extracted for the alert.
Definition: intro_types.h:1642
#define TRACE(fmt,...)
Definition: glue.h:58
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
#define INT_STATUS_ALREADY_INITIALIZED_HINT
Definition: introstatus.h:323
#define WARNING(fmt,...)
Definition: glue.h:60
Event structure for GDTR/IDTR descriptor tables modifications.
Definition: intro_types.h:1625
Write access.
Definition: glueiface.h:319
A descriptor table register. Valid for IDTR and GDTR.
Definition: introcpu.h:71
Describes the modified zone.
Definition: exceptions.h:893
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1627
uint32_t DWORD
Definition: intro_types.h:49
INTSTATUS IntIdtrProtect(void)
Enable IDTR protection.
INTSTATUS IntWinIdtUnprotectOnCpu(DWORD CpuNumber)
Removes the IDT write protection for a CPU.
Definition: winidt.c:524
enum _INTRO_ACTION INTRO_ACTION
Event actions.
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
INTSTATUS(* PFUNC_DtrReadWriteHookCallback)(DTR *OldDtr, DTR *NewDtr, DWORD Flags, INTRO_ACTION *Action)
Called when a descriptor table register is accessed.
Definition: hook_dtr.h:21
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
INTSTATUS IntGdtrUnprotect(void)
Remove the GDTR protection.
INTRO_ACTION Action
The action that was taken as the result of this alert.
Definition: intro_types.h:1194
INTSTATUS IntLixIdtProtectAll(void)
Activates protection for IDT on all CPUs.
Definition: lixidt.c:234
void IntAlertDtrFill(const EXCEPTION_VICTIM_ZONE *Victim, const EXCEPTION_KM_ORIGINATOR *Originator, EVENT_DTR_VIOLATION *DtrViolation)
Saves information about a DTR write attempt in an event.
Definition: alerts.c:1176
static INTSTATUS IntDtrSendAlert(PEXCEPTION_VICTIM_ZONE Victim, PEXCEPTION_KM_ORIGINATOR Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Send an DTR alert.
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:1644
void IntAlertFillLixCurrentProcess(INTRO_PROCESS *EventProcess)
Saves the current Linux process inside an event.
Definition: alerts.c:1310
static INTSTATUS IntDtrHandleWrite(DTR *OldDtr, DTR *NewDtr, DWORD Flags, INTRO_ACTION *Action)
Handle an IDTR or GDTR modification.
INTSTATUS IntExceptGetVictimDtr(DTR *NewValue, DTR *OldValue, INTRO_OBJECT_TYPE Type, EXCEPTION_VICTIM_ZONE *Victim)
This function is used to get the information about the DTR victim.
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
INTSTATUS IntGdtrProtect(void)
Enable GDTR protection.
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 INTRO_OPT_PROT_KM_GDTR
Enable global descriptor-table registers protection.
Definition: intro_types.h:440
INTSTATUS IntHookDtrRemoveHook(HOOK_DTR *Hook)
Remove a descriptor register hook.
Definition: hook_dtr.c:106
#define FALSE
Definition: intro_types.h:34
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68