Bitdefender Hypervisor Memory Introspection
lixidt.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "lixidt.h"
6 #include "alerts.h"
7 #include "hook.h"
8 
9 
10 static INTSTATUS
12  _In_opt_ void *Context,
13  _In_ void *Hook,
14  _In_ QWORD Address,
15  _Out_ INTRO_ACTION *Action
16  )
30 {
32  EXCEPTION_VICTIM_ZONE victim = { 0 };
33  EXCEPTION_KM_ORIGINATOR originator = { 0 };
35  QWORD idtBase;
36  QWORD idtLimit;
37 
38  UNREFERENCED_PARAMETER(Context);
40  UNREFERENCED_PARAMETER(Address);
41 
42  if (Action == NULL)
43  {
45  }
46 
47  *Action = introGuestNotAllowed;
48  reason = introReasonUnknown;
49 
50  status = IntGuestGetIdtFromGla(gVcpu->Gla, &idtBase, &idtLimit);
51  if (!INT_SUCCESS(status))
52  {
53  ERROR("[ERROR] IntGuestGetIdtFromGla failed: 0x%08x, the write on 0x%016llx (gpa 0x%016llx) "
54  "from cpu %d seems to be outside any idt!\n", status, gVcpu->Gla, gVcpu->Gpa, gVcpu->Index);
55 
56  *Action = introGuestAllowed;
57 
59  }
60 
62 
63  status = IntExceptKernelGetOriginator(&originator, 0);
64  if (!INT_SUCCESS(status))
65  {
66  ERROR("[ERROR] Failed getting originator: 0x%08x\n", status);
67  reason = introReasonInternalError;
68  }
69 
70  status = IntExceptGetVictimEpt(&idtBase,
71  gVcpu->Gpa,
72  gVcpu->Gla,
74  ZONE_WRITE,
75  &victim);
76  if (!INT_SUCCESS(status))
77  {
78  ERROR("[ERROR] Failed getting zone details: 0x%08x\n", status);
79  reason = introReasonInternalError;
80  }
81 
82  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventEptViolation);
83 
85 
86  if (IntPolicyCoreTakeAction(INTRO_OPT_PROT_KM_IDT, Action, &reason))
87  {
88  EVENT_EPT_VIOLATION *pEptViol = &gAlert.Ept;
89  memzero(pEptViol, sizeof(*pEptViol));
90 
91  pEptViol->Header.Action = *Action;
93  pEptViol->Header.MitreID = idRootkit;
94 
96 
98 
100 
101  if (originator.Original.Driver != NULL)
102  {
103  IntAlertFillLixKmModule(originator.Original.Driver, &pEptViol->Originator.Module);
104  }
105  if (originator.Return.Driver != NULL)
106  {
108  }
109 
110  IntAlertEptFillFromVictimZone(&victim, pEptViol);
111 
112  IntAlertFillCodeBlocks(originator.Original.Rip, gVcpu->Regs.Cr3, FALSE, &pEptViol->CodeBlocks);
113  IntAlertFillExecContext(0, &pEptViol->ExecContext);
114 
115  IntAlertFillVersionInfo(&pEptViol->Header);
116 
117  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
118  if (!INT_SUCCESS(status))
119  {
120  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
121  }
122  }
123 
125 
126  return INT_STATUS_SUCCESS;
127 }
128 
129 
130 INTSTATUS
132  _In_ DWORD CpuNumber
133  )
145 {
146  INTSTATUS status = INT_STATUS_SUCCESS;
147  QWORD idtBase;
148  WORD idtLimit;
149 
150  idtBase = gGuest.VcpuArray[CpuNumber].IdtBase;
151  if (0 == idtBase)
152  {
153  status = IntIdtFindBase(CpuNumber, &idtBase, &idtLimit);
154  if (!INT_SUCCESS(status))
155  {
156  return status;
157  }
158 
159  gGuest.VcpuArray[CpuNumber].IdtBase = idtBase;
160  gGuest.VcpuArray[CpuNumber].IdtLimit = idtLimit;
161  }
162 
163  if (0 == idtBase)
164  {
165  WARNING("[WARNING] Cpu %d has no IDT yet!\n", CpuNumber);
167  }
168 
169  if (gGuest.VcpuArray[CpuNumber].IdtHookObject == NULL)
170  {
172  if (!INT_SUCCESS(status))
173  {
174  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
175  return status;
176  }
177  }
178  else
179  {
180  for (DWORD indexCpu = 0; indexCpu < gGuest.CpuCount; ++indexCpu)
181  {
182  if (CpuNumber == indexCpu)
183  {
184  continue;
185  }
186 
187  if (gGuest.VcpuArray[indexCpu].IdtBase == idtBase)
188  {
189  TRACE("[HOOK] IDT already hooked -> @ %llx for CPU %d.\n", idtBase, CpuNumber);
190  return INT_STATUS_SUCCESS;
191  }
192  }
193  }
194 
195  TRACE("[HOOK] Hooking IDT (0x20 entries) for CPU %d @ 0x%016llx\n", CpuNumber, idtBase);
196 
198  0,
199  idtBase,
200  IDT_DESC_SIZE64 * 0x20,
203  NULL,
204  0,
205  NULL);
206  if (!INT_SUCCESS(status))
207  {
208  ERROR("[ERROR] Failed hooking IDT at 0x%016llx for CPU %d: 0x%08x\n", idtBase, CpuNumber, status);
209  return status;
210  }
211 
212  TRACE("[HOOK] Hooking IDT Int80 for CPU %d @ 0x%016llx\n", CpuNumber, idtBase + IDT_DESC_SIZE64 * 0x80);
213 
215  0,
216  idtBase + IDT_DESC_SIZE64 * 0x80,
220  NULL,
221  0,
222  NULL);
223  if (!INT_SUCCESS(status))
224  {
225  ERROR("[ERROR] Failed hooking entry 80 of IDT at 0x%016llx for CPU %d: 0x%08x\n", idtBase, CpuNumber, status);
226  return status;
227  }
228 
229  return INT_STATUS_SUCCESS;
230 }
231 
232 
233 INTSTATUS
235  void
236  )
243 {
245 
246  for (DWORD i = 0; i < gGuest.CpuCount; i++)
247  {
248  INTSTATUS status = IntLixIdtProtectOnCpu(i);
249  if (!INT_SUCCESS(status))
250  {
251  failStatus = status;
252  continue;
253  }
254  }
255 
256  return failStatus;
257 }
258 
259 
260 INTSTATUS
262  void
263  )
269 {
270  for (DWORD i = 0; i < gGuest.CpuCount; i++)
271  {
273  {
275  if (!INT_SUCCESS(status))
276  {
277  ERROR("[ERROR] Failed removing idt hook object: 0x%08x\n", status);
278  }
279  }
280  }
281 
282  return INT_STATUS_SUCCESS;
283 }
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.
INTRO_CODEBLOCKS CodeBlocks
Code blocks extracted for the alert.
Definition: intro_types.h:1263
#define _Out_
Definition: intro_sal.h:22
INTSTATUS IntIdtFindBase(DWORD CpuNumber, QWORD *Base, WORD *Limit)
Returns the IDT base and limit for a guest CPU.
Definition: introcpu.c:102
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
INTSTATUS IntHookObjectDestroy(HOOK_OBJECT_DESCRIPTOR **Object, DWORD Flags)
Destroy an entire hook object. All regions belonging to this object will be removed.
Definition: hook_object.c:357
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
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
#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
uint16_t WORD
Definition: intro_types.h:48
#define STATS_EXIT(id)
Definition: stats.h:160
WORD IdtLimit
The current IDT limit.
Definition: guests.h:111
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
Definition: intro_types.h:1198
void * IdtHookObject
The EPT hook object used to protect the IDT.
Definition: guests.h:155
INTSTATUS IntLixIdtUnprotectAll(void)
Disable protection for IDT on all CPUs.
Definition: lixidt.c:261
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
#define ERROR(fmt,...)
Definition: glue.h:62
KERNEL_DRIVER * Driver
The driver that&#39;s modifying the memory.
Definition: exceptions.h:949
struct _EVENT_EPT_VIOLATION::@283 Originator
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
PVCPU_STATE VcpuArray
Array of the VCPUs assigned to this guest. The index in this array matches the VCPU number...
Definition: guests.h:372
#define INTRO_OPT_PROT_KM_IDT
Definition: intro_types.h:412
void IntAlertFillCpuContext(BOOLEAN CopyInstruction, INTRO_CPUCTX *CpuContext)
Fills the current CPU context for an alert.
Definition: alerts.c:492
struct _EXCEPTION_KM_ORIGINATOR::@63 Return
EVENT_EPT_VIOLATION Ept
Definition: alerts.h:16
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
Definition: alerts.c:327
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1217
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
void IntAlertFillLixKmModule(const KERNEL_DRIVER *Driver, INTRO_MODULE *EventModule)
Saves information about a kernel module inside an alert.
Definition: alerts.c:1235
void IntAlertEptFillFromVictimZone(const EXCEPTION_VICTIM_ZONE *Victim, EVENT_EPT_VIOLATION *EptViolation)
Fills the victim information inside an EPT alert.
Definition: alerts.c:868
#define INT_STATUS_NOT_INITIALIZED
Definition: introstatus.h:266
#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
INTSTATUS IntExceptGetVictimEpt(void *Context, QWORD Gpa, QWORD Gva, INTRO_OBJECT_TYPE Type, DWORD ZoneFlags, EXCEPTION_VICTIM_ZONE *Victim)
Fills an EXCEPTION_VICTIM_ZONE with relevant information from an EPT violation.
Definition: exceptions.c:742
unsigned long long QWORD
Definition: intro_types.h:53
QWORD IdtBase
Original IDT base.
Definition: guests.h:110
#define TRUE
Definition: intro_types.h:30
#define INT_STATUS_INVALID_PARAMETER_4
Definition: introstatus.h:71
QWORD Gpa
The accessed guest physical address. Valid only for EPT exits.
Definition: guests.h:101
#define TRACE(fmt,...)
Definition: glue.h:58
Kernel-mode exception.
Definition: exceptions.h:61
INTRO_EXEC_CONTEXT ExecContext
Information about the instruction that triggered the alert.
Definition: intro_types.h:1309
INTSTATUS IntLixIdtProtectAll(void)
Activates protection for IDT on all CPUs.
Definition: lixidt.c:234
#define WARNING(fmt,...)
Definition: glue.h:60
INTSTATUS IntGuestGetIdtFromGla(QWORD Address, QWORD *IdtBase, QWORD *IdtLimit)
Checks if an address is inside one of the guest&#39;s IDTs.
Definition: guests.h:526
Sent when an EPT violation triggers an alert. See EVENT_EPT_VIOLATION.
Definition: intro_types.h:84
#define IDT_DESC_SIZE64
The size of a 64-bit interrupt descriptor.
Definition: wddefs.h:32
DWORD CpuCount
The number of logical CPUs.
Definition: guests.h:279
Describes the modified zone.
Definition: exceptions.h:893
#define UNREFERENCED_PARAMETER(P)
Definition: introdefs.h:29
uint32_t DWORD
Definition: intro_types.h:49
static INTSTATUS IntLixIdtWriteHandler(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Called if a write occurs on the protected IDT descriptors.
Definition: lixidt.c:11
enum _INTRO_ACTION INTRO_ACTION
Event actions.
QWORD Rip
The RIP from where the call to the exported function came.
Definition: exceptions.h:950
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
INTSTATUS IntLixIdtProtectOnCpu(DWORD CpuNumber)
Activates protection for the provided CPU&#39;s IDT.
Definition: lixidt.c:131
struct _EXCEPTION_KM_ORIGINATOR::@64 Original
INTRO_ACTION Action
The action that was taken as the result of this alert.
Definition: intro_types.h:1194
INTSTATUS IntHookObjectHookRegion(void *Object, QWORD Cr3, QWORD Gla, SIZE_T Length, BYTE Type, void *Callback, void *Context, DWORD Flags, HOOK_REGION_DESCRIPTOR **Region)
Hook a contiguous region of virtual memory inside the provided virtual address space.
Definition: hook_object.c:132
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_MODULE Module
The module that did the malicious access.
Definition: intro_types.h:1221
Event structure for EPT violations.
Definition: intro_types.h:1215
void IntAlertFillLixCurrentProcess(INTRO_PROCESS *EventProcess)
Saves the current Linux process inside an event.
Definition: alerts.c:1310
Write-access hook.
Definition: glueiface.h:299
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
#define ZONE_WRITE
Used for write violation.
Definition: exceptions.h:734
QWORD Gla
The accessed guest virtual address. Valid only for EPT exits.
Definition: guests.h:102
INTSTATUS IntHookObjectCreate(DWORD ObjectType, QWORD Cr3, void **Object)
Create a new hook object.
Definition: hook_object.c:81
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
INTRO_MODULE ReturnModule
The module to which the current code returns to.
Definition: intro_types.h:1222
#define FALSE
Definition: intro_types.h:34